Make Destructive Actions Explicit
Deleting financial data deserves a clear decision point. The browser’s built-in window.confirm() is convenient, but it gives the application no control over the visual design, wording, or loading state.
The Ledger uses client/src/components/ConfirmDialog.jsx instead. It is an ordinary React component controlled by state.
The page decides whether the dialog is open:
const [confirmDeleteName, setConfirmDeleteName] = useState(null);
A non-null value identifies the item waiting for confirmation. The dialog then receives the title, explanation, and actions as props:
<ConfirmDialog
open={Boolean(confirmDeleteName)}
title={`Delete “${confirmDeleteName}” category?`}
description="This removes the category from your shared category list."
onCancel={() => setConfirmDeleteName(null)}
onConfirm={() => handleDelete(confirmDeleteName)}
/>
The dialog itself handles Escape and a backdrop click, and disables both actions while the delete request is running. This is important because the user should not be able to submit the same destructive action twice while the server is still responding.
Transaction deletion adds another protection after the request succeeds: the deleted transaction is kept in memory long enough to offer an undo action. Undo is implemented by sending that saved transaction back through the create flow, which means the restoration uses the same validation and persistence path as any other new transaction.
Do not add a browser confirm() call anywhere else. The same custom pattern should be used for categories so destructive actions behave consistently throughout the project.
Test it
Search the project for confirm( or window.confirm. The application should have no browser confirmation calls.
Click a transaction delete button and confirm that the custom dialog appears. Cancel it and verify nothing changes. Delete the transaction, then use Undo and confirm that it returns.
Open Categories and repeat the process for a category that is safe to delete. Then attempt an in-use category and verify the UI explains why deletion is unavailable.
Checkpoint
Every destructive action now has an intentional application-owned confirmation flow, with no native browser dialog.