# Business Logic Model — Unit 4: Dashboard ## Process Overview Unit 4 introduces TanStack Query as a shared data-fetching layer and implements the Dashboard page with a live availability widget. The logic splits into three concerns: query infrastructure setup, the availability hook, and the dashboard UI composition. --- ## TanStack Query Setup A `QueryClient` is created once at app startup and provided via `QueryClientProvider` wrapping the `RouterProvider` in `main.tsx`. This is a one-time global change that enables all future units to use `useQuery` / `useMutation`. ```ts // Recommended default options for the QueryClient const queryClient = new QueryClient({ defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: true, }, }, }); ``` --- ## useAvailabilityStatus Hook **Location**: `frontend/src/api/useAvailability.ts` **Query key**: `['availability', 'status']` **Fetch function**: Calls `GET /api/v1/Availability/status` via the shared `api` client. **staleTime**: `30_000` ms — TanStack Query refetches automatically in the background once data is 30 seconds old. **Return shape**: ```ts { data: AvailabilityResponse | undefined; // undefined until first successful fetch error: Error | null; isLoading: boolean; // true only during initial fetch with no data isFetching: boolean; // true during any in-flight refetch isError: boolean; refetch: () => void; // exposed for Retry button } ``` **Stale-with-error state**: When a background refetch fails, TanStack Query preserves the previous `data` value while setting `isError = true`. This enables the dashboard to display the last known status alongside the error state (BR-U4-11). --- ## DashboardPage Composition The DashboardPage composes existing layout primitives with the new availability widget. No routing changes are needed — `DashboardPage` is already registered as the `/dashboard` route component in `router.tsx`. **Sections**: 1. **Header** — welcome message with user name (already implemented; retained as-is) 2. **Availability Widget** — replaces the generic placeholder card --- ## Availability Widget Logic Flow ```mermaid sequenceDiagram box rgba(99,179,237,0.4) Component Layer participant DP as DashboardPage participant Badge as AvailabilityStatusBadge end box rgba(154,230,180,0.4) Query Layer participant Q as useAvailabilityStatus end box rgba(233,213,255,0.4) External participant API as GET /availability/status end DP->>Q: mount — useAvailabilityStatus() Q->>API: fetch on mount API-->>Q: 200 AvailabilityResponse Q-->>DP: data + isLoading=false DP->>Badge: render with status and message Note over Q: staleTime 30s elapses Q->>API: background refetch alt Refetch succeeds API-->>Q: 200 AvailabilityResponse Q-->>DP: updated data DP->>Badge: re-render with fresh data else Refetch fails API-->>Q: network error or 5xx Q-->>DP: isError=true data=stale DP->>Badge: render stale badge with stale indicator DP->>DP: show error banner with Retry button end ``` Sequence showing initial fetch, badge render, background refetch on staleTime expiry, and error handling with stale data preservation. --- ## i18n Keys (additions) New translation keys needed for the availability widget: | Key | English | Dutch | |---|---|---| | `availability.title` | System Status | Systeemstatus | | `availability.available` | Available | Beschikbaar | | `availability.maintenance` | Maintenance | Onderhoud | | `availability.unavailable` | Unavailable | Niet beschikbaar | | `availability.errorTitle` | Could not load status | Status kon niet worden geladen | | `availability.staleLabel` | Last known status | Laatste bekende status | | `availability.retry` | Retry | Opnieuw proberen |