diff --git a/client/hooks/useQueries.js b/client/hooks/useQueries.js index 10e6da7..64313e9 100644 --- a/client/hooks/useQueries.js +++ b/client/hooks/useQueries.js @@ -68,6 +68,19 @@ export function useInvalidateTrackerData() { }, [queryClient]); } +// Prefetch a tracker month into the cache (e.g. on month-nav hover) so switching +// to it is instant. No-op if it's already cached and fresh. +export function usePrefetchTracker() { + const queryClient = useQueryClient(); + return useCallback((year, month) => { + queryClient.prefetchQuery({ + queryKey: ['tracker', year, month], + queryFn: () => api.tracker(year, month), + staleTime: 1000 * 60 * 5, + }); + }, [queryClient]); +} + // ── Page data (migrated off manual useEffect + load()) ─────────────────────── // The queryKey encodes the params, so React Query handles caching, request // dedup, cancellation, and out-of-order responses — no manual sequence guards. diff --git a/client/pages/TrackerPage.jsx b/client/pages/TrackerPage.jsx index 06207bb..f6a17f0 100644 --- a/client/pages/TrackerPage.jsx +++ b/client/pages/TrackerPage.jsx @@ -3,7 +3,7 @@ import { useSearchParams } from 'react-router-dom'; import { ChevronLeft, ChevronRight, AlertCircle, CheckCircle2, Plus, Search, RefreshCw, Landmark, ArrowUpToLine, ArrowUp, ArrowDown, BellOff, EyeOff, Settings2 } from 'lucide-react'; import { toast } from 'sonner'; import { api } from '@/api.js'; -import { useTracker, useDriftReport, useInvalidateTrackerData } from '@/hooks/useQueries'; +import { useTracker, useDriftReport, useInvalidateTrackerData, usePrefetchTracker } from '@/hooks/useQueries'; import { useSearchPanelPreference } from '@/hooks/useSearchPanelPreference'; import BillModal from '@/components/BillModal'; import { makeBillDraft } from '@/lib/billDrafts'; @@ -301,12 +301,23 @@ export default function TrackerPage() { return () => window.removeEventListener('tracker:late-attributions', handler); }, []); - function navigate(delta) { + function adjacentMonth(delta) { let nm = month + delta; let ny = year; if (nm > 12) { ny += 1; nm = 1; } if (nm < 1) { ny -= 1; nm = 12; } - updateParams({ year: ny, month: nm }); + return { year: ny, month: nm }; + } + + function navigate(delta) { + updateParams(adjacentMonth(delta)); + } + + // Prefetch the adjacent month on hover/focus so clicking prev/next is instant. + const prefetchTracker = usePrefetchTracker(); + function prefetchAdjacent(delta) { + const { year: ny, month: nm } = adjacentMonth(delta); + prefetchTracker(ny, nm); } function bankSyncMessage(result) { @@ -651,6 +662,8 @@ export default function TrackerPage() {