Add one-off next check number override

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).
This commit is contained in:
2026-03-18 10:56:05 -06:00
parent 830a7ca686
commit 2f2646fb78
4 changed files with 115 additions and 1 deletions
+20
View File
@@ -64,6 +64,26 @@ header {
line-height: 1.4;
}
.btn-header-icon:hover { background: rgba(255,255,255,0.28); }
.btn-header-inline {
background: none;
border: none;
color: rgba(255,255,255,0.5);
font-size: 11px;
cursor: pointer;
padding: 0 0 0 4px;
line-height: 1;
vertical-align: middle;
}
.btn-header-inline:hover { color: #fff; }
.warning-box {
background: #fef9c3;
border: 1px solid #ca8a04;
border-radius: 4px;
padding: 10px 12px;
font-size: 12px;
color: #713f12;
line-height: 1.5;
}
/* ── Toolbar ── */
.toolbar {
+24 -1
View File
@@ -13,7 +13,7 @@
<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></span>
<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 -->
@@ -383,6 +383,29 @@
</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">
+53
View File
@@ -642,6 +642,49 @@ async function saveAccountSettings() {
}
}
// ── Set next check number ─────────────────────────────────────────────────────
function openSetCheckNo() {
const current = state.account ? state.account.current_check_no + 1 : 1;
document.getElementById('set-check-no-input').value = current;
document.getElementById('set-check-no-error').hidden = true;
document.getElementById('set-check-no-overlay').classList.add('open');
document.getElementById('set-check-no-modal').classList.add('open');
document.getElementById('set-check-no-input').focus();
document.getElementById('set-check-no-input').select();
}
function closeSetCheckNo() {
document.getElementById('set-check-no-overlay').classList.remove('open');
document.getElementById('set-check-no-modal').classList.remove('open');
}
async function saveSetCheckNo() {
const errEl = document.getElementById('set-check-no-error');
const input = document.getElementById('set-check-no-input');
const next = parseInt(input.value, 10);
if (isNaN(next) || next < 1) {
errEl.textContent = 'Enter a valid check number (1 or higher).';
errEl.hidden = false;
return;
}
const btn = document.getElementById('btn-confirm-set-check-no');
btn.disabled = true;
btn.textContent = 'Saving…';
try {
await apiFetch('PUT', `/api/account/${state.activeAccountId}/check-no`, { next_check_no: next });
state.account.current_check_no = next - 1;
renderHeader();
closeSetCheckNo();
} catch (err) {
errEl.textContent = err.message;
errEl.hidden = false;
} finally {
btn.disabled = false;
btn.textContent = 'Set Number';
}
}
// ── Deposits ─────────────────────────────────────────────────────────────────
const depState = {
@@ -1013,6 +1056,16 @@ function init() {
document.getElementById('btn-cancel-acct-settings').addEventListener('click', closeAccountSettings);
document.getElementById('acct-settings-overlay').addEventListener('click', closeAccountSettings);
document.getElementById('btn-save-acct-settings').addEventListener('click', saveAccountSettings);
document.getElementById('btn-set-check-no').addEventListener('click', openSetCheckNo);
document.getElementById('btn-close-set-check-no').addEventListener('click', closeSetCheckNo);
document.getElementById('btn-cancel-set-check-no').addEventListener('click', closeSetCheckNo);
document.getElementById('set-check-no-overlay').addEventListener('click', closeSetCheckNo);
document.getElementById('btn-confirm-set-check-no').addEventListener('click', saveSetCheckNo);
document.getElementById('set-check-no-input').addEventListener('keydown', e => {
if (e.key === 'Enter') saveSetCheckNo();
if (e.key === 'Escape') closeSetCheckNo();
});
document.getElementById('as-logo').addEventListener('change', e => {
const file = e.target.files[0];
if (!file) { acctSettings.logoData = null; return; }
+18
View File
@@ -84,6 +84,24 @@ app.get('/api/account/:id', (req, res) => {
res.json(account);
});
// PUT /api/account/:id/check-no - override the next check number
app.put('/api/account/:id/check-no', (req, res) => {
const db = require('./db/database');
const account = db.prepare('SELECT id FROM account WHERE id = ?').get(req.params.id);
if (!account) return res.status(404).json({ error: 'Account not found.' });
const next = parseInt(req.body.next_check_no, 10);
if (isNaN(next) || next < 1) {
return res.status(400).json({ error: 'Next check number must be a positive integer.' });
}
// current_check_no is the last-used number; next check will be current_check_no + 1
db.prepare("UPDATE account SET current_check_no = ?, updated_at = datetime('now') WHERE id = ?")
.run(next - 1, req.params.id);
res.json({ next_check_no: next });
});
// POST /api/account/setup - create a new account (wizard)
app.post('/api/account/setup', (req, res) => {
const db = require('./db/database');