Commit Graph

11 Commits

Author SHA1 Message Date
null 8265b4a97f refactor(ts): type the spending API responses (Track C)
Promoted SpendingPage's local shapes into @/types (SpendingCategoryEntry,
SpendingSummary, SpendingTransaction(s), SpendingIncome*, SpendingRule,
CategoryGroup, CopyBudgetsResponse) and wired the /spending/* + category-
groups endpoints with get<T>/post<T>. Hooks return typed data; 6 casts
removed; 2 orphaned type aliases dropped. typecheck/lint/build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 12:06:40 -05:00
null b267599ba5 refactor(ts): type the bank-ledger API responses (Track C)
Promoted BankTransactionsPage's local Tx/Account/Ledger/... interfaces
into @/types (BankLedgerTransaction extends BankTransaction so amounts
stay branded Cents) and wired bankTransactionsLedger/match/unmatch/
ignore/unignore/apply-merchant-match/auto-categorize with get<T>/post<T>.
useBankLedger data is now typed; all 9 as {...} casts in the page removed.
Dropped a dead Cents import. typecheck/lint/build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 12:02:28 -05:00
null 31ff6adbd9 refactor(ts): convert bill-modal sub-components to TSX (B10)
The 7 BillModal sub-components + transactionDisplay helper: TemplateSection,
AutopayTrustIndicator, PaymentFormFields, PaymentHistoryList, DebtDetailsSection,
LinkedTransactionsSection, UnmatchDialogs. New @/types.BankTransaction — raw bank
amounts stay in CENTS on the wire, so branded `Cents` (formatCentsUSD, not
formatUSD), the complement to the Dollars brand. BulkUnmatchState typed with
null-safe setState callbacks. typecheck 0, lint 0 errors, build green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 20:03:09 -05:00
null c2097efc49 refactor(ts): convert TrackerRow + TrackerBucket to TSX (B6) — tracker/ dir done
The two largest tracker components. TrackerRow (726 ln): typed threshold/
optimistic-actual as branded Dollars, amount_suggestion/autopay_stats now real
@/types (AmountSuggestion/AutopayStats) with null-safe `stats?.` access,
querySelectorAll<HTMLElement> for keyboard nav, Date.now()-getTime() arithmetic,
drag-handler casts for the motion.tr TableRow. TrackerBucket: typed
dragPropsFor/moveControlsFor returns (DragProps/MoveControls), bulkPay result
cast, asDollars at every total's fmt boundary.

client/components/tracker/ is now 100% .tsx (18 components). typecheck 0, lint 0
errors (40 warns), build green, 48 client tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 19:42:26 -05:00
null f4f1dadaab refactor(ts): convert MobileTrackerRow to TSX (B5)
The mobile tracker row (consumes branded TrackerRow + shared payment hooks).
Supporting: TrackerRow.sparkline typed number[]|null; ROW_STATUS_CLS typed
Record<string,string> (it has no `skipped` key, so indexing by TrackerStatus
needed a string index). DragProps/MoveControls interfaces exported. Notable: the
HTML5 drag handlers conflict with framer-motion's own onDrag* gesture types on
motion.div — cast via ComponentProps<typeof motion.div>; quick-pay/remaining
amounts need asDollars at the boundary. typecheck 0, build green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 19:36:01 -05:00
null ee31513dc9 refactor(ts): convert Drift + Overdue panels to TSX (B4)
DriftInsightPanel (new @/types DriftBill — its own row shape, money in dollars)
and OverdueCommandCenter (TrackerRow[]). Note: TS flags `Date - Date`
arithmetic → use .getTime(); the overdue/net-delta totals need asDollars at the
fmt boundary. typecheck 0, build green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 19:32:39 -05:00
null c1ec0a4f2e refactor(ts): convert tracker dialogs + cards to TSX (B3)
Six tracker components consuming the branded domain types:
AutopaySuggestionActions, CashFlowCard (typed TrackerCashflow + TimelineChart/
UpcomingList), MonthlyStateDialog, PaymentModal, PaymentLedgerDialog,
StartingAmountsEditDialog. New @/types: AutopaySuggestion, TimelineBill; Payment
gains method/autopay_failure. Branded money paid off again — fmt(Math.abs(safe))
and the starting-amounts arithmetic correctly required asDollars wraps at the
format boundary. typecheck 0, lint 0 errors (41 warns), build green, 48 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 19:29:42 -05:00
null 1f18a720c4 refactor(ts): convert all UI primitives + ThemeContext to TSX (B2)
Foundational for phase B: the ui/* primitives were untyped .jsx, and TS infers
React-19 ref-as-prop components as *requiring* a ref, so every consumer errored.
Converted all 22 ui primitives (button, input, card, dialog, select, table,
dropdown-menu, tabs, badge, checkbox, switch, tooltip, separator, label,
Skeleton, collapsible, alert-dialog, sonner, save-status, theme-toggle,
input-dialog, confirm-dialog) using ComponentProps<'el'> / ComponentProps<typeof
Radix.X> + VariantProps for cva components — refs now optional, event params
typed. Also converted ThemeContext.tsx (createContext(null) made useContext's
post-guard return `never`, so setTheme was uncallable — fixed with a typed
context value) and three tracker cells (EditableCell/NotesCell/
LowerThisMonthButton) that consume the branded TrackerRow.

Added a shared errMessage(unknown) helper to utils (strict catch → unknown);
usePaymentActions reuses it. TrackerRow gains monthly_notes + amount_suggestion
(real server fields).

typecheck 0, lint 0 errors (42 warns), build green, 48 client tests. NOTE: the
e2e auth-setup probe is currently red on an unrelated, pre-existing
release-notes-modal dismissal race (reproduces on the last known-good commit;
the a11y snapshot shows these converted primitives rendering correctly) —
investigating separately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 22:57:22 -05:00
null 4af738f947 feat(ts): type the shared Category API response (A4)
Adds Category (+ CategoryBillSummary) to @/types and wires categories/
createCategory/updateCategory. Category has no money field of its own (budgets
live on the spending endpoints); the nested per-bill total_paid is a raw SQL sum,
so it's deliberately left unbranded. With categories now typed, useSpending
Categories drops its `any` cast and dead d.categories branch.

Category, Bill, Payment, and the Tracker envelope are the cross-cutting types
used by many components — worth defining upfront. The remaining single-consumer
page responses (summary, analytics, spending, snowball, subscriptions, bank
ledger) are typed alongside their page conversions in phase B, where the exact
fields consumed are visible (more accurate than a speculative interface).

typecheck 0, build green, 48 client tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 22:27:08 -05:00
null 337ad95a3e feat(ts): type Bill + Payment API responses with branded Dollars (A2-A3)
Adds Bill and reuses Payment domain types (money → Dollars, mirroring
serializeBill/serializePayment which spread the DB row and convert the money
columns). Wired: bills/allBills/deletedBills → Bill[], bill/createBill/updateBill
→ Bill; quickPay/createPayment/updatePayment/restorePayment → Payment. Replaced
api.ts's minimal PaymentRecord with the richer @/types Payment (usePaymentActions
still resolves payment.id). typecheck 0, build green, 48 client tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 22:24:35 -05:00
null 3c7a55c3a1 feat(ts): type the Tracker API response with branded Dollars (A1)
New client/types.ts domain-types module. Types the full /tracker response —
TrackerResponse { summary, bank_tracking, cashflow, rows } — with every money
field branded `Dollars` (the server serializes cents→dollars, verified against
statusService.buildTrackerRow + trackerService.getTracker + buildBankTracking +
buildSafeToSpend). api.tracker() now returns Promise<TrackerResponse>.

TrackerRow + TrackerStatus move to @/types (canonical) and are re-exported from
@/lib/trackerUtils for compat; trackerUtils' row money fields upgrade from plain
`number` to branded `Dollars` (rowThreshold -> Dollars, paymentSummary re-brands
its computed amounts via asDollars so callers can fmt() them directly). This is
the first endpoint where the money brand flows end-to-end: fetch layer -> row
helpers, and (in phase B) into the components that format them.

Nested payloads no typed consumer reads yet (summary.trend, autopay_suggestion/
_stats, sparkline) are left `unknown`, to refine when consumed. asDollars is an
identity at runtime, so behavior is unchanged: typecheck 0, lint 0 errors, build
green, 48 client tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 22:21:45 -05:00