docs(ts): mark Phase B complete — every client .jsx converted to .tsx
Records the final 5-page batch (Snowball, BankTransactions, Spending, Bills, Subscriptions) and the dead-total-state find TypeScript surfaced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8229d21ab8
commit
47a9ba98cb
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
- **[Client] Phase A — typed the API response shapes with branded money** — new `client/types.ts` domain module: every money field branded (`Dollars` for bill/payment/tracker/summary amounts; **`Cents` for raw bank-transaction amounts, which stay cents on the wire** — the complement that keeps `formatCentsUSD` and `formatUSD` from being swapped). Reverse-engineered from the server serializers: `TrackerResponse` (summary/bank_tracking/cashflow/rows), `Bill`, `Payment`, `Category`, `DriftBill`, `AutopaySuggestion`, `AmountSuggestion`, `AutopayStats`, `BankTransaction`, `TimelineBill`. `api.tracker/bills/payments/categories/…` now return these, so the brand flows from the fetch layer into `trackerUtils` (row money upgraded from `number` → `Dollars`; `paymentSummary` re-brands via `asDollars`).
|
- **[Client] Phase A — typed the API response shapes with branded money** — new `client/types.ts` domain module: every money field branded (`Dollars` for bill/payment/tracker/summary amounts; **`Cents` for raw bank-transaction amounts, which stay cents on the wire** — the complement that keeps `formatCentsUSD` and `formatUSD` from being swapped). Reverse-engineered from the server serializers: `TrackerResponse` (summary/bank_tracking/cashflow/rows), `Bill`, `Payment`, `Category`, `DriftBill`, `AutopaySuggestion`, `AmountSuggestion`, `AutopayStats`, `BankTransaction`, `TimelineBill`. `api.tracker/bills/payments/categories/…` now return these, so the brand flows from the fetch layer into `trackerUtils` (row money upgraded from `number` → `Dollars`; `paymentSummary` re-brands via `asDollars`).
|
||||||
|
|
||||||
- **[Client] Phase B — converting components/pages `.jsx` → `.tsx` (in progress, ~80/129 files)** — done: **all 22 `ui/*` primitives** + `ThemeContext`; the **entire `components/tracker/` dir** (18 files — the home page) where `fmt(row.expected_amount)` now type-checks against `Dollars`; the **entire `components/bill-modal/` dir + `BillModal.tsx`** (the 1092-line add/edit form reached from 9 entry points); the **app shell** (`App`/`main`/`useAuth`/`Layout`/`Sidebar`/routing; `index.html` entry → `main.tsx`); app-wide commons (`ErrorBoundary` class, `PageTransition`, `StatusBadge`, `MarkdownText`, `SummaryCard`, `ReleaseNotesDialog`); the `snowball/` + `transactions/` dirs; the **entire `components/admin/` dir** (11 cards incl. the OIDC/auth-methods form, bank-sync, backup manager); the **entire `components/data/` dir** (14 files — the Data page's SimpleFIN connect/sync workbench, transaction-matching, and the CSV / OFX / XLSX-spreadsheet / SQLite import flows, with `Cents`-branded bank-transaction amounts flowing through); and several pages. **A required infra fix:** Tailwind's `content` glob was `./client/**/*.{js,jsx}` — it never scanned `.tsx`, so any class used *only* in a converted file generated **no CSS** (the release-notes dialog's `left-[50%] top-[50%]` centering vanished → modal rendered off-screen). typecheck/build/48-tests all passed; only the **e2e probe** caught it. Fixed to `{js,jsx,ts,tsx}`. Remaining: ~18 pages + a few loose components — all mechanical.
|
- **[Client] Phase B — converted every component + page `.jsx` → `.tsx` (COMPLETE — `find client -name '*.jsx'` returns 0)** — done: **all 22 `ui/*` primitives** + `ThemeContext`; the **entire `components/tracker/` dir** (18 files — the home page) where `fmt(row.expected_amount)` now type-checks against `Dollars`; the **entire `components/bill-modal/` dir + `BillModal.tsx`** (the 1092-line add/edit form reached from 9 entry points); the **app shell** (`App`/`main`/`useAuth`/`Layout`/`Sidebar`/routing; `index.html` entry → `main.tsx`); app-wide commons (`ErrorBoundary` class, `PageTransition`, `StatusBadge`, `MarkdownText`, `SummaryCard`, `ReleaseNotesDialog`); the `snowball/` + `transactions/` dirs; the **entire `components/admin/` dir** (11 cards incl. the OIDC/auth-methods form, bank-sync, backup manager); the **entire `components/data/` dir** (14 files — the Data page's SimpleFIN connect/sync workbench, transaction-matching, and the CSV / OFX / XLSX-spreadsheet / SQLite import flows, with `Cents`-branded bank-transaction amounts flowing through); and several pages. **A required infra fix:** Tailwind's `content` glob was `./client/**/*.{js,jsx}` — it never scanned `.tsx`, so any class used *only* in a converted file generated **no CSS** (the release-notes dialog's `left-[50%] top-[50%]` centering vanished → modal rendered off-screen). typecheck/build/48-tests all passed; only the **e2e probe** caught it. Fixed to `{js,jsx,ts,tsx}`. **The final page batch** finished the job: the 5 largest/most-stateful pages — `SnowballPage`, `BankTransactionsPage` (the `Cents`-based bank ledger, with a local `Tx` structurally compatible with `BankTransaction` so it still satisfies `MatchBillDialog`), `SpendingPage` (a `RealCatEntry` narrowing splits the budget-indexed real categories from the `null`/`'other'` pseudo-rows), `BillsPage`, and `SubscriptionsPage` (1814 lines — `useOptimistic<Subscription[]>` reducer, the virtualizer's `FlatItem` discriminated union, and drag-reorder typed via the shared `DragProps`/`MoveControls`). Every page: local domain interfaces, React Query `setQueryData<T>` for the optimistic caches, cast-at-boundary for `api.*` (`Promise<unknown>`) results, and the local `fmt(v: number|null|undefined)` branded-`Dollars` wrapper so page money still type-checks. Verified: `npm run typecheck` (0) + `npm run lint` (0 errors) + `npm run build` + the 17/17 e2e probe (incl. axe on `/`, `/spending`, `/bills`, `/snowball`, `/summary`, `/analytics`, `/categories`, `/data`).
|
||||||
|
|
||||||
### 🏆 What the TypeScript migration caught (real defects, not just types)
|
### 🏆 What the TypeScript migration caught (real defects, not just types)
|
||||||
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
- **A CSS build gap invisible to typecheck/build/tests** — the Tailwind `.tsx` glob omission above; the **e2e probe** was the only gate that caught it, reinforcing that a passing build ≠ runtime-safe for a `.tsx` rename touching many files.
|
- **A CSS build gap invisible to typecheck/build/tests** — the Tailwind `.tsx` glob omission above; the **e2e probe** was the only gate that caught it, reinforcing that a passing build ≠ runtime-safe for a `.tsx` rename touching many files.
|
||||||
- **Dead code with broken calls** — `PrivacyAdminCard` was imported nowhere yet called non-existent `api.privacySettings`/`setPrivacySettings` (the geolocation toggle actually lives on `/profile/settings`). Deleted rather than converted.
|
- **Dead code with broken calls** — `PrivacyAdminCard` was imported nowhere yet called non-existent `api.privacySettings`/`setPrivacySettings` (the geolocation toggle actually lives on `/profile/settings`). Deleted rather than converted.
|
||||||
- **A missing import that crashed a live view** — `ImportTransactionCsvSection` rendered `<CountPill>` **6×** (in the CSV preview + results panels) but never imported it. In the `.jsx` this is a `ReferenceError: CountPill is not defined` the moment you preview a CSV — a runtime crash `react/jsx-no-undef` wasn't configured to catch, but `tsc` flagged immediately as `TS2304: Cannot find name 'CountPill'`. Added the import. (Same file also carried two genuinely-unused imports — `CountPill`/`fmt` in the XLSX section — that TS surfaced and we dropped.)
|
- **A missing import that crashed a live view** — `ImportTransactionCsvSection` rendered `<CountPill>` **6×** (in the CSV preview + results panels) but never imported it. In the `.jsx` this is a `ReferenceError: CountPill is not defined` the moment you preview a CSV — a runtime crash `react/jsx-no-undef` wasn't configured to catch, but `tsc` flagged immediately as `TS2304: Cannot find name 'CountPill'`. Added the import. (Same file also carried two genuinely-unused imports — `CountPill`/`fmt` in the XLSX section — that TS surfaced and we dropped.)
|
||||||
|
- **A dead `total` state on the Spending page** — `IncomeSection` kept a `const [total, setTotal] = useState(0)` and dutifully `setTotal(d.total || 0)` on every income-page load, but nothing ever read `total` — a pointless render-triggering write. The `noUnusedLocals`-adjacent lint surfaced it during the `.tsx` conversion; removed the state and its setter. (The rest of the final 5-page batch type-checked clean on the first or second pass — a good signal the pages were already sound.)
|
||||||
|
|
||||||
### 🧪 Money-service test coverage
|
### 🧪 Money-service test coverage
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue