2f2646fb78
Pencil button next to "Next check: X" in the header opens a modal with a warning about sequence gaps/duplicates. Saves via new PUT /api/account/:id/check-no endpoint (sets current_check_no = next - 1).
486 lines
20 KiB
HTML
486 lines
20 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>ezcheck</title>
|
||
<link rel="stylesheet" href="/css/style.css">
|
||
</head>
|
||
<body>
|
||
<header>
|
||
<div class="header-left">
|
||
<span class="header-brand" id="company-name">ezcheck</span>
|
||
<select id="account-switcher" class="account-switcher" title="Switch account"></select>
|
||
<button id="btn-account-settings" class="btn-header-icon" title="Account settings">⚙</button>
|
||
</div>
|
||
<span class="header-info">Next check: <strong id="current-check-no">—</strong><button id="btn-set-check-no" class="btn-header-inline" title="Set next check number">✎</button></span>
|
||
</header>
|
||
|
||
<!-- View nav tabs -->
|
||
<nav class="view-nav">
|
||
<button class="view-tab active" data-view="checks">Checks</button>
|
||
<button class="view-tab" data-view="deposits">Deposits</button>
|
||
</nav>
|
||
|
||
<!-- Checks view -->
|
||
<div id="view-checks" class="view-pane">
|
||
<div class="toolbar">
|
||
<div class="toolbar-left">
|
||
<input type="search" id="filter-payee" placeholder="Search payee…" style="width:160px">
|
||
<input type="date" id="filter-date-from" title="From date">
|
||
<span style="color:var(--text-muted)">–</span>
|
||
<input type="date" id="filter-date-to" title="To date">
|
||
<select id="filter-status">
|
||
<option value="" selected>All</option>
|
||
<option value="0">Unprinted</option>
|
||
<option value="1">Printed</option>
|
||
</select>
|
||
</div>
|
||
<div class="toolbar-right">
|
||
<button id="btn-generate-pdf" class="btn-primary" disabled>
|
||
Generate PDF <span id="selected-count" class="badge">0</span>
|
||
</button>
|
||
<button id="btn-new-check" class="btn-secondary">+ New Check</button>
|
||
<button id="btn-import" class="btn-secondary">Import .mdb</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="checks-summary" class="checks-summary"></div>
|
||
|
||
<div class="table-wrap">
|
||
<table id="checks-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="col-select"><input type="checkbox" id="select-all-checks" title="Select all"></th>
|
||
<th class="col-no sortable" data-col="check_no"># <span class="sort-indicator"></span></th>
|
||
<th class="col-date sortable" data-col="check_date">Date <span class="sort-indicator"></span></th>
|
||
<th class="col-payee sortable" data-col="payee">Payee <span class="sort-indicator"></span></th>
|
||
<th class="col-amount sortable" data-col="amount">Amount <span class="sort-indicator"></span></th>
|
||
<th class="col-memo">Memo</th>
|
||
<th class="col-status">Status</th>
|
||
<th class="col-actions"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="checks-tbody">
|
||
<tr class="loading-row"><td colspan="8">Loading…</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div><!-- /view-checks -->
|
||
|
||
<!-- Deposits view -->
|
||
<div id="view-deposits" class="view-pane" hidden>
|
||
<div class="toolbar">
|
||
<div class="toolbar-left">
|
||
<input type="date" id="dep-filter-from" title="From date">
|
||
<span style="color:var(--text-muted)">–</span>
|
||
<input type="date" id="dep-filter-to" title="To date">
|
||
<select id="dep-filter-status">
|
||
<option value="" selected>All</option>
|
||
<option value="0">Unprinted</option>
|
||
<option value="1">Printed</option>
|
||
</select>
|
||
</div>
|
||
<div class="toolbar-right">
|
||
<button id="btn-new-deposit" class="btn-secondary">+ New Deposit</button>
|
||
</div>
|
||
</div>
|
||
<div class="table-wrap">
|
||
<table id="deposits-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="col-date">Date</th>
|
||
<th class="col-amount" style="text-align:right">Checks Total</th>
|
||
<th class="col-amount" style="text-align:right">Cash</th>
|
||
<th class="col-amount" style="text-align:right">Cash Back</th>
|
||
<th class="col-amount" style="text-align:right">Deposit Total</th>
|
||
<th style="width:50px;text-align:center">Items</th>
|
||
<th class="col-status">Status</th>
|
||
<th class="col-actions"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="deposits-tbody">
|
||
<tr class="loading-row"><td colspan="8">Loading…</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div><!-- /view-deposits -->
|
||
|
||
<!-- Slide-in panel -->
|
||
<div id="panel-overlay"></div>
|
||
<aside id="check-panel">
|
||
<div class="panel-header">
|
||
<h2 id="panel-title">New Check</h2>
|
||
<button id="btn-close-panel" class="btn-icon" title="Close">×</button>
|
||
</div>
|
||
<form id="check-form" novalidate>
|
||
<div class="form-group required">
|
||
<label for="f-payee">Payee</label>
|
||
<input type="text" id="f-payee" name="payee" required autocomplete="off">
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group required">
|
||
<label for="f-amount">Amount ($)</label>
|
||
<input type="number" id="f-amount" name="amount" required min="0.01" step="0.01" placeholder="0.00">
|
||
</div>
|
||
<div class="form-group required">
|
||
<label for="f-date">Date</label>
|
||
<input type="date" id="f-date" name="check_date" required>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="f-memo">Memo</label>
|
||
<input type="text" id="f-memo" name="memo">
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label for="f-note1">Note 1</label>
|
||
<input type="text" id="f-note1" name="note1">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="f-note2">Note 2</label>
|
||
<input type="text" id="f-note2" name="note2">
|
||
</div>
|
||
</div>
|
||
<details class="address-section">
|
||
<summary>Payee Address</summary>
|
||
<div class="address-fields">
|
||
<div class="form-group">
|
||
<label for="f-addr1">Line 1</label>
|
||
<input type="text" id="f-addr1" name="payee_address1">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="f-addr2">Line 2</label>
|
||
<input type="text" id="f-addr2" name="payee_address2">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="f-addr3">Line 3</label>
|
||
<input type="text" id="f-addr3" name="payee_address3">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="f-addr4">Line 4</label>
|
||
<input type="text" id="f-addr4" name="payee_address4">
|
||
</div>
|
||
</div>
|
||
</details>
|
||
<div class="form-actions">
|
||
<button type="submit" class="btn-primary" id="btn-save">Save Check</button>
|
||
<button type="button" class="btn-ghost" id="btn-cancel">Cancel</button>
|
||
</div>
|
||
</form>
|
||
</aside>
|
||
|
||
<!-- Setup wizard -->
|
||
<div id="wizard-overlay" class="modal-overlay"></div>
|
||
<div id="wizard-modal" class="modal wizard-modal" role="dialog" aria-labelledby="wizard-title">
|
||
<div class="modal-header">
|
||
<h2 id="wizard-title">Account Setup</h2>
|
||
</div>
|
||
<div class="wizard-steps-indicator">
|
||
<div class="wizard-step-dot active" data-step="1"><span>1</span><label>Checkwriter</label></div>
|
||
<div class="wizard-step-line"></div>
|
||
<div class="wizard-step-dot" data-step="2"><span>2</span><label>Bank</label></div>
|
||
<div class="wizard-step-line"></div>
|
||
<div class="wizard-step-dot" data-step="3"><span>3</span><label>Account</label></div>
|
||
</div>
|
||
|
||
<div class="modal-body wizard-body">
|
||
<!-- Step 1: Checkwriter -->
|
||
<div class="wizard-step" id="wizard-step-1">
|
||
<div class="form-group required">
|
||
<label for="w-company1">Organization Name</label>
|
||
<input type="text" id="w-company1" autocomplete="organization">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="w-addr1">Address</label>
|
||
<input type="text" id="w-addr1" autocomplete="street-address">
|
||
</div>
|
||
<div class="form-row form-row-3">
|
||
<div class="form-group">
|
||
<label for="w-city">City</label>
|
||
<input type="text" id="w-city" autocomplete="address-level2">
|
||
</div>
|
||
<div class="form-group form-group-sm">
|
||
<label for="w-state">State</label>
|
||
<input type="text" id="w-state" maxlength="2" autocomplete="address-level1" placeholder="MT">
|
||
</div>
|
||
<div class="form-group form-group-sm">
|
||
<label for="w-zip">ZIP</label>
|
||
<input type="text" id="w-zip" maxlength="10" autocomplete="postal-code">
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="w-contact">Phone / Website / Email</label>
|
||
<input type="text" id="w-contact" placeholder="e.g. 406-555-0100">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 2: Bank -->
|
||
<div class="wizard-step" id="wizard-step-2" hidden>
|
||
<div class="form-group required">
|
||
<label for="w-bank-name">Bank Name</label>
|
||
<input type="text" id="w-bank-name">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="w-bank-addr">Bank Address</label>
|
||
<input type="text" id="w-bank-addr">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="w-transit">Transit Code</label>
|
||
<input type="text" id="w-transit" placeholder="e.g. 092900383">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="w-bank-contact">Phone / Website</label>
|
||
<input type="text" id="w-bank-contact">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 3: Account -->
|
||
<div class="wizard-step" id="wizard-step-3" hidden>
|
||
<div class="form-group required">
|
||
<label for="w-routing">Routing Number</label>
|
||
<input type="text" id="w-routing" inputmode="numeric" maxlength="9">
|
||
</div>
|
||
<div class="form-group required">
|
||
<label for="w-account">Account Number</label>
|
||
<input type="text" id="w-account" inputmode="numeric">
|
||
</div>
|
||
<div class="form-group required">
|
||
<label for="w-start-check">Starting Check Number</label>
|
||
<input type="number" id="w-start-check" min="1" step="1" value="1001">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="w-logo">Logo (optional)</label>
|
||
<input type="file" id="w-logo" accept="image/*">
|
||
<span class="field-hint">Printed top-left of each check. PNG or GIF recommended.</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="wizard-error" class="wizard-error" hidden></div>
|
||
</div>
|
||
|
||
<div class="modal-footer wizard-footer">
|
||
<button id="btn-wizard-prev" class="btn-secondary" hidden>← Back</button>
|
||
<button id="btn-wizard-next" class="btn-primary">Next →</button>
|
||
<button id="btn-wizard-finish" class="btn-primary" hidden>Save & Start</button>
|
||
<button id="btn-wizard-skip" class="btn-ghost">Use Import instead</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Import modal -->
|
||
<div id="import-modal-overlay" class="modal-overlay"></div>
|
||
<div id="import-modal" class="modal" role="dialog" aria-labelledby="import-modal-title">
|
||
<div class="modal-header">
|
||
<h2 id="import-modal-title">Import from .mdb</h2>
|
||
<button id="btn-close-import" class="btn-icon" title="Close">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<p class="modal-desc">Select an ezCheckPrinting <code>.mdb</code> file to import account settings, check layout, and check history. This will replace existing data.</p>
|
||
<div class="form-group">
|
||
<label for="import-file">File</label>
|
||
<input type="file" id="import-file" accept=".mdb">
|
||
</div>
|
||
<div id="import-log" class="import-log" hidden></div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button id="btn-run-import" class="btn-primary">Import</button>
|
||
<button id="btn-cancel-import" class="btn-ghost">Cancel</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Account settings modal -->
|
||
<div id="acct-settings-overlay" class="modal-overlay"></div>
|
||
<div id="acct-settings-modal" class="modal" role="dialog" aria-labelledby="acct-settings-title">
|
||
<div class="modal-header">
|
||
<h2 id="acct-settings-title">Account Settings</h2>
|
||
<button id="btn-close-acct-settings" class="btn-icon" title="Close">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="acct-settings-form" novalidate>
|
||
|
||
<p class="settings-section-label">Organization</p>
|
||
<div class="form-group required">
|
||
<label for="as-company1">Name</label>
|
||
<input type="text" id="as-company1" name="company1">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="as-company2">Address</label>
|
||
<input type="text" id="as-company2" name="company2">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="as-company3">City / State / ZIP</label>
|
||
<input type="text" id="as-company3" name="company3">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="as-company4">Phone / Web / Email</label>
|
||
<input type="text" id="as-company4" name="company4">
|
||
</div>
|
||
|
||
<p class="settings-section-label">Bank</p>
|
||
<div class="form-group">
|
||
<label for="as-bank-name">Bank Name</label>
|
||
<input type="text" id="as-bank-name" name="bank_name">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="as-bank-info1">Bank Address</label>
|
||
<input type="text" id="as-bank-info1" name="bank_info1">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="as-bank-info2">Bank Phone / Web</label>
|
||
<input type="text" id="as-bank-info2" name="bank_info2">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="as-transit">Transit Code</label>
|
||
<input type="text" id="as-transit" name="transit_code">
|
||
</div>
|
||
|
||
<p class="settings-section-label">Account</p>
|
||
<div class="form-row">
|
||
<div class="form-group required">
|
||
<label for="as-routing">Routing Number</label>
|
||
<input type="text" id="as-routing" name="routing_number" inputmode="numeric" maxlength="9">
|
||
</div>
|
||
<div class="form-group required">
|
||
<label for="as-account">Account Number</label>
|
||
<input type="text" id="as-account" name="account_number" inputmode="numeric">
|
||
</div>
|
||
</div>
|
||
|
||
<p class="settings-section-label">Logo</p>
|
||
<div class="form-group">
|
||
<label for="as-logo">Upload new logo</label>
|
||
<input type="file" id="as-logo" accept="image/*">
|
||
<span class="field-hint">Replaces existing logo. PNG or GIF recommended.</span>
|
||
</div>
|
||
<div id="as-logo-preview" class="logo-preview" hidden></div>
|
||
|
||
<p class="settings-section-label">Printer Offset <span class="field-hint">(inches — adjust if checks print misaligned)</span></p>
|
||
<div class="form-row form-row-4">
|
||
<div class="form-group">
|
||
<label for="as-off-left">Left</label>
|
||
<input type="number" id="as-off-left" name="offset_left" step="0.01" placeholder="0">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="as-off-right">Right</label>
|
||
<input type="number" id="as-off-right" name="offset_right" step="0.01" placeholder="0">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="as-off-up">Up</label>
|
||
<input type="number" id="as-off-up" name="offset_up" step="0.01" placeholder="0">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="as-off-down">Down</label>
|
||
<input type="number" id="as-off-down" name="offset_down" step="0.01" placeholder="0">
|
||
</div>
|
||
</div>
|
||
|
||
<div id="acct-settings-error" class="wizard-error" hidden></div>
|
||
</form>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button id="btn-save-acct-settings" class="btn-primary">Save Changes</button>
|
||
<button id="btn-cancel-acct-settings" class="btn-ghost">Cancel</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Set next check number modal -->
|
||
<div id="set-check-no-overlay" class="modal-overlay"></div>
|
||
<div id="set-check-no-modal" class="modal" role="dialog" aria-labelledby="set-check-no-title">
|
||
<div class="modal-header">
|
||
<h2 id="set-check-no-title">Set Next Check Number</h2>
|
||
<button id="btn-close-set-check-no" class="btn-icon" title="Close">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="warning-box">
|
||
<strong>Warning:</strong> Changing the next check number can create duplicate check numbers or gaps in your sequence. Only do this if checks were printed outside this system or your book was restarted.
|
||
</div>
|
||
<div class="form-group" style="margin-top:12px">
|
||
<label for="set-check-no-input">Next check number</label>
|
||
<input type="number" id="set-check-no-input" min="1" step="1" style="width:120px">
|
||
</div>
|
||
<div id="set-check-no-error" class="wizard-error" hidden></div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button id="btn-confirm-set-check-no" class="btn-primary">Set Number</button>
|
||
<button id="btn-cancel-set-check-no" class="btn-ghost">Cancel</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Deposit slide-in panel -->
|
||
<div id="dep-panel-overlay"></div>
|
||
<aside id="deposit-panel">
|
||
<div class="panel-header">
|
||
<h2 id="dep-panel-title">New Deposit</h2>
|
||
<button id="btn-close-dep-panel" class="btn-icon" title="Close">×</button>
|
||
</div>
|
||
<div id="deposit-panel-body">
|
||
<!-- Top section: date + cash fields -->
|
||
<div class="dep-summary">
|
||
<div class="form-row">
|
||
<div class="form-group required">
|
||
<label for="dep-date">Deposit Date</label>
|
||
<input type="date" id="dep-date">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="dep-currency">Currency ($)</label>
|
||
<input type="number" id="dep-currency" min="0" step="0.01" placeholder="0.00">
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label for="dep-coin">Coin ($)</label>
|
||
<input type="number" id="dep-coin" min="0" step="0.01" placeholder="0.00">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="dep-cashback">Cash Back ($)</label>
|
||
<input type="number" id="dep-cashback" min="0" step="0.01" placeholder="0.00">
|
||
</div>
|
||
</div>
|
||
<div class="dep-totals">
|
||
<div class="dep-total-row"><span>Cash Total</span><span id="dep-cash-total">$0.00</span></div>
|
||
<div class="dep-total-row"><span>Checks Total</span><span id="dep-checks-total">$0.00</span></div>
|
||
<div class="dep-total-row"><span>Subtotal</span><span id="dep-subtotal">$0.00</span></div>
|
||
<div class="dep-total-row"><span>Cash Back</span><span id="dep-cashback-display">$0.00</span></div>
|
||
<div class="dep-total-row dep-total-grand"><span>Deposit Total</span><span id="dep-grand-total">$0.00</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Check items grid -->
|
||
<div class="dep-checks-section">
|
||
<div class="dep-checks-header">
|
||
<span>Checks</span>
|
||
<button type="button" id="btn-add-dep-item" class="btn-sm btn-secondary">+ Add Row</button>
|
||
</div>
|
||
<table class="dep-items-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Check #</th>
|
||
<th>Payee</th>
|
||
<th>Memo</th>
|
||
<th style="text-align:right">Amount</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="dep-items-tbody"></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div id="dep-panel-error" class="wizard-error" hidden></div>
|
||
|
||
<div class="form-actions dep-form-actions">
|
||
<div class="dep-pdf-btns">
|
||
<button type="button" id="btn-dep-slip" class="btn-secondary" disabled>Deposit Slip</button>
|
||
<button type="button" id="btn-dep-report" class="btn-secondary" disabled>Report</button>
|
||
</div>
|
||
<div>
|
||
<button type="button" id="btn-save-deposit" class="btn-primary">Save Deposit</button>
|
||
<button type="button" id="btn-cancel-deposit" class="btn-ghost">Cancel</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<script src="/js/app.js"></script>
|
||
</body>
|
||
</html>
|