Adopt TanStack Query: provider, timeouts, useBudget, Budget page

QueryClientProvider (30s staleTime, 1 retry) + Sonner Toaster at the
root. api.ts gains AbortSignal support and a default 30s timeout
(FE-24); query cancellation kills the stale-response races (FE-01,
FE-03). useBudget is now queries + mutations with targeted ['budget']
invalidation and success/error toasts on every mutation (ARCH-13,
UX-01); month navigation keeps the previous month visible while
fetching. Budget's transaction list is a cancellable query with
placeholder data; deferred-toggle gets feedback (UX-05); both panels
render a shared ErrorState with retry instead of failing silently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-06-10 16:24:48 -06:00
parent 396c492f27
commit 65dffdac06
8 changed files with 234 additions and 117 deletions

View File

@@ -0,0 +1,28 @@
import { AlertTriangle, RotateCw } from 'lucide-react';
import { Button } from '@/components/ui/button';
interface Props {
message?: string;
onRetry?: () => void;
}
export default function ErrorState({
message = 'No se pudieron cargar los datos',
onRetry,
}: Props) {
return (
<div
role="alert"
className="flex flex-col items-center justify-center gap-3 rounded-lg border border-destructive/40 bg-destructive/5 p-8 text-center"
>
<AlertTriangle className="h-6 w-6 text-destructive" aria-hidden="true" />
<p className="text-sm text-muted-foreground">{message}</p>
{onRetry && (
<Button variant="outline" size="sm" onClick={onRetry}>
<RotateCw className="mr-2 h-4 w-4" aria-hidden="true" />
Reintentar
</Button>
)}
</div>
);
}