From c86acd7d75c2ae8878bdce346ca19743a6f6741f Mon Sep 17 00:00:00 2001 From: null Date: Fri, 3 Jul 2026 21:05:31 -0500 Subject: [PATCH] =?UTF-8?q?docs(history):=20React=20Query=20deeper=20adopt?= =?UTF-8?q?ion=20=E2=80=94=20error=20handling,=20prefetch,=20useMutation?= =?UTF-8?q?=20(P1-P3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- HISTORY.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index ff70ca5..bb1c363 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -9,6 +9,10 @@ - **[Tracker] Killed the getTracker N+1 (was ~2–3 DB round-trips × N bills every home-page load)** — inside `bills.map`, `getTracker` ran a payments query per bill (`fetchPaymentsForBillCycle`) plus `computeAmountSuggestion` per bill, and the suggestion alone fired up to 12 queries per bill (6 months × 2) — roughly 70–450 queries for a 35-bill account on every Tracker load. Now one query fetches all bills' cycle payments (grouped in JS by each bill's own range) and two queries compute all amount suggestions (`computeAmountSuggestionsBatch`), replacing the per-bill loops. Behavior-preserving — `tests/amountSuggestionService.test.js` pins the batched suggestion to be byte-identical to the per-bill function, and the `trackerService` tests still pass unchanged. (Tracker P1) +### ⚛️ React Query — deeper adoption + +- **[Client] Completed the React Query adoption with global error handling, prefetching, and mutations** — building on the page migration: (1) a global `QueryCache.onError` handler surfaces a toast when a *background refetch* fails while stale data is on screen (pages still render inline errors on the initial load), restoring the load-error feedback centrally; (2) `usePrefetchTracker()` warms the adjacent month's cache on month-nav hover/focus, so clicking prev/next is instant; (3) the quick-pay action — previously duplicated verbatim across the desktop and mobile tracker rows — is now a shared `useQuickPay()` `useMutation` hook (its `isPending` replaces a manual busy flag, and the tracker/badge caches invalidate on settle). (React Query mutation follow-ups: pay/skip and other writes can adopt the same hook pattern incrementally.) + ### ⚛️ React Query migration (all manual-fetch pages) - **[Client] Moved the 7 remaining manual-fetch pages onto React Query** — Analytics, Bills, Subscriptions, Summary, Snowball, Spending, and Bank transactions each fetched with hand-rolled `useEffect` + `load()` + `useState(data/loading/error)`. Migrated them all to `useQuery` hooks (in `client/hooks/useQueries.js`) whose keys encode the params, so React Query now provides caching, request dedup, cancellation, and out-of-order-response safety for free — the manual request-sequence guards added earlier were removed. `keepPreviousData` keeps the last result visible while a new month/filter/page loads. Mutations that previously called `load()` now `invalidateQueries`, and optimistic edits (list reorder/delete, categorize, budget/plan changes) write through `queryClient.setQueryData` wrappers so every existing call site works unchanged. Editable form fields seeded from the data (Summary starting-amounts/income, Snowball settings, Spending budgets) are now seeded via a data-synced effect; pagination (Spending/Bank) is a page-keyed query. Bonus: because Bills reuses the shared `['bills']` cache, bill mutations there now also refresh the Tracker/overdue badge live. Each page was its own commit, verified with `npm run lint` (0 errors) + `npm run test:client` + `npm run build`. (R5)