Add Delete Account button with confirmation modal
Red "Delete Account" button at top of Account Settings. Clicking opens a second modal with an irreversibility warning and the account name, requiring a second explicit confirmation before deletion. Deletes the account row plus all associated checks and deposits. Redirects to the setup wizard if no accounts remain.
This commit is contained in:
@@ -174,6 +174,9 @@ button:disabled { opacity: 0.45; cursor: not-allowed; }
|
|||||||
|
|
||||||
.btn-ghost { background: transparent; color: var(--text-muted); }
|
.btn-ghost { background: transparent; color: var(--text-muted); }
|
||||||
.btn-ghost:hover { color: var(--text); background: var(--bg); }
|
.btn-ghost:hover { color: var(--text); background: var(--bg); }
|
||||||
|
.btn-danger { background: #dc2626; color: #fff; font-weight: 500; }
|
||||||
|
.btn-danger:not(:disabled):hover { background: #b91c1c; }
|
||||||
|
.delete-account-row { margin-bottom: 18px; padding-bottom: 16px; border-bottom: 1px solid var(--border); }
|
||||||
|
|
||||||
.btn-icon {
|
.btn-icon {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|||||||
@@ -300,6 +300,10 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form id="acct-settings-form" novalidate>
|
<form id="acct-settings-form" novalidate>
|
||||||
|
|
||||||
|
<div class="delete-account-row">
|
||||||
|
<button type="button" id="btn-delete-account" class="btn-danger">Delete Account</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p class="settings-section-label">Organization</p>
|
<p class="settings-section-label">Organization</p>
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<label for="as-company1">Name</label>
|
<label for="as-company1">Name</label>
|
||||||
@@ -413,6 +417,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Delete account confirmation modal -->
|
||||||
|
<div id="delete-account-overlay" class="modal-overlay"></div>
|
||||||
|
<div id="delete-account-modal" class="modal" role="dialog" aria-labelledby="delete-account-title">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 id="delete-account-title">Delete Account</h2>
|
||||||
|
<button id="btn-close-delete-account" class="btn-icon" title="Close">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="warning-box" style="background:#fef2f2;border-color:#f87171;color:#7f1d1d">
|
||||||
|
<strong>This cannot be undone.</strong> Deleting this account will permanently remove all checks, deposits, and account settings. There is no recovery.
|
||||||
|
</div>
|
||||||
|
<p style="margin-top:14px;font-size:13px">Are you sure you want to delete <strong id="delete-account-name"></strong>?</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button id="btn-confirm-delete-account" class="btn-danger">Yes, Delete Account</button>
|
||||||
|
<button id="btn-cancel-delete-account" class="btn-ghost">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- QBO Import modal -->
|
<!-- QBO Import modal -->
|
||||||
<div id="qbo-import-overlay" class="modal-overlay"></div>
|
<div id="qbo-import-overlay" class="modal-overlay"></div>
|
||||||
<div id="qbo-import-modal" class="modal modal-wide" role="dialog" aria-labelledby="qbo-import-title">
|
<div id="qbo-import-modal" class="modal modal-wide" role="dialog" aria-labelledby="qbo-import-title">
|
||||||
|
|||||||
@@ -644,6 +644,40 @@ async function saveAccountSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Delete account ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function openDeleteAccount() {
|
||||||
|
const name = (state.account && state.account.company1) || 'this account';
|
||||||
|
document.getElementById('delete-account-name').textContent = name;
|
||||||
|
document.getElementById('delete-account-overlay').classList.add('open');
|
||||||
|
document.getElementById('delete-account-modal').classList.add('open');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDeleteAccount() {
|
||||||
|
document.getElementById('delete-account-overlay').classList.remove('open');
|
||||||
|
document.getElementById('delete-account-modal').classList.remove('open');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function confirmDeleteAccount() {
|
||||||
|
const btn = document.getElementById('btn-confirm-delete-account');
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.textContent = 'Deleting…';
|
||||||
|
try {
|
||||||
|
await apiFetch('DELETE', `/api/account/${state.activeAccountId}`);
|
||||||
|
closeDeleteAccount();
|
||||||
|
closeAccountSettings();
|
||||||
|
state.account = null;
|
||||||
|
state.activeAccountId = null;
|
||||||
|
state.checks = [];
|
||||||
|
localStorage.removeItem('activeAccountId');
|
||||||
|
await loadAccounts(); // will open wizard if no accounts remain
|
||||||
|
} catch (err) {
|
||||||
|
alert('Delete failed: ' + err.message);
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = 'Yes, Delete Account';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── QBO Import ────────────────────────────────────────────────────────────────
|
// ── QBO Import ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
let qboChecksRecords = null;
|
let qboChecksRecords = null;
|
||||||
@@ -1241,6 +1275,12 @@ function init() {
|
|||||||
document.getElementById('acct-settings-overlay').addEventListener('click', closeAccountSettings);
|
document.getElementById('acct-settings-overlay').addEventListener('click', closeAccountSettings);
|
||||||
document.getElementById('btn-save-acct-settings').addEventListener('click', saveAccountSettings);
|
document.getElementById('btn-save-acct-settings').addEventListener('click', saveAccountSettings);
|
||||||
|
|
||||||
|
document.getElementById('btn-delete-account').addEventListener('click', openDeleteAccount);
|
||||||
|
document.getElementById('btn-close-delete-account').addEventListener('click', closeDeleteAccount);
|
||||||
|
document.getElementById('btn-cancel-delete-account').addEventListener('click', closeDeleteAccount);
|
||||||
|
document.getElementById('delete-account-overlay').addEventListener('click', closeDeleteAccount);
|
||||||
|
document.getElementById('btn-confirm-delete-account').addEventListener('click', confirmDeleteAccount);
|
||||||
|
|
||||||
document.getElementById('btn-set-check-no').addEventListener('click', openSetCheckNo);
|
document.getElementById('btn-set-check-no').addEventListener('click', openSetCheckNo);
|
||||||
document.getElementById('btn-close-set-check-no').addEventListener('click', closeSetCheckNo);
|
document.getElementById('btn-close-set-check-no').addEventListener('click', closeSetCheckNo);
|
||||||
document.getElementById('btn-cancel-set-check-no').addEventListener('click', closeSetCheckNo);
|
document.getElementById('btn-cancel-set-check-no').addEventListener('click', closeSetCheckNo);
|
||||||
|
|||||||
+16
@@ -104,6 +104,22 @@ app.put('/api/account/:id/check-no', (req, res) => {
|
|||||||
res.json({ next_check_no: next });
|
res.json({ next_check_no: next });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// DELETE /api/account/:id - delete account and all associated data
|
||||||
|
app.delete('/api/account/:id', (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.' });
|
||||||
|
|
||||||
|
db.transaction(() => {
|
||||||
|
// deposit_items deleted via ON DELETE CASCADE from deposits
|
||||||
|
db.prepare('DELETE FROM deposits WHERE account_id = ?').run(req.params.id);
|
||||||
|
db.prepare('DELETE FROM checks WHERE account_id = ?').run(req.params.id);
|
||||||
|
db.prepare('DELETE FROM account WHERE id = ?').run(req.params.id);
|
||||||
|
})();
|
||||||
|
|
||||||
|
res.status(204).end();
|
||||||
|
});
|
||||||
|
|
||||||
// POST /api/account/setup - create a new account (wizard)
|
// POST /api/account/setup - create a new account (wizard)
|
||||||
app.post('/api/account/setup', (req, res) => {
|
app.post('/api/account/setup', (req, res) => {
|
||||||
const db = require('./db/database');
|
const db = require('./db/database');
|
||||||
|
|||||||
Reference in New Issue
Block a user