geocrop-platform./apps/nextgen/.harness/changelogs/2026-07-17-p1-4-finance-par...

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 in finance/*, after: 13 in finance/*. (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.