# 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 `` 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: ```tsx } > {/* was the inline form */} ``` `` 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 `
` 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 in `finance/*`, after: 13 in `finance/*`. (9 migrated.) - Manual diff: every inline `
` in the 4 migrated files now wraps `` + ``. No controller-level or store-level changes touched.