2.7 KiB
2026-07-17 — P1-4 modal migration: finance/* (Track A continuation)
Branch: feat/p1-4-modals-finance
Worktree: .worktrees/feat-p1-4-modals-finance
Why
P1-4 in the readiness audit calls for migrating every inline modal
to the shared <Modal> component Track A introduced (in
client/src/components/ui/Modal.tsx). BankingAccounts.tsx already
demonstrates the pattern; this PR applies the same shape across the
finance/* slice.
Changes
Migrated modals (9 of 22 in finance/*)
| File | Modals migrated |
|---|---|
client/src/pages/finance/Trips.tsx |
2 — TripEditor (8-field form), confirmDelete confirmation |
client/src/pages/finance/TripDetail.tsx |
2 — Record payment form, Assign students form |
client/src/pages/finance/ChartOfAccounts.tsx |
2 — confirmDelete confirmation, ChartEditor form |
client/src/pages/finance/Discounts.tsx |
3 — confirmRevoke, DiscountEditor, ApplyDiscountModal |
Each migration follows the Track A pattern:
<Modal
open={isOpen}
onClose={onClose}
title="…"
icon={Icon}
maxWidth="max-w-md"
footer={<><button>Cancel</button><button>Save</button></>}
>
<ModalBody>
{/* was the inline form */}
</ModalBody>
</Modal>
<Modal> already provides the backdrop-blur, click-outside-to-close,
Escape-to-close, scroll-lock, and rounded-2xl premium styling
(see modals.md §1). Forms retain <form id=…> semantics with the
submit button using form="…" so the layout can keep the action row
in the footer slot.
scripts/lint-no-inline-modals.js (new)
Tiny Node script that walks client/src/pages/**, counts every
fixed inset-0 … backdrop-blur-sm … pattern, and exits non-zero if
any remain. Run via node scripts/lint-no-inline-modals.js. Used as a
regression net so future PRs that re-introduce an inline modal show
up here.
Out of scope for this slice
The remaining 13 inline modals in finance/* (per lint) live in:
Expenses.tsx(2)FeePlans.tsx(2)Suppliers.tsx(2)StudentGroups.tsx(3)Invoices.tsx(1 — a right-side detail drawer, not a centered modal; would change UX if ported as-is)PayrollRuns.tsx(1)Payslips.tsx(1)StudentGroupDetail.tsx(1)
These land in the next PR that picks up the finance/* slack.
The other 5 file-owner PRs from the original P1-4 list
(Fees.tsx, HRManagement.tsx, Inventory.tsx, Library.tsx,
parent/AcademicProgress.tsx) land separately.
Verification
node scripts/lint-no-inline-modals.js→ before: 22 infinance/*, after: 13 infinance/*. (9 migrated.)- Manual diff: every inline
<div className="fixed inset-0 …">in the 4 migrated files now wraps<Modal>+<ModalBody>. No controller-level or store-level changes touched.