feat(unit-4): Dashboard — availability widget with TanStack Query

- Add @tanstack/react-query 5.101.0; wrap app with QueryClientProvider
- Add AvailabilityStatus type and AvailabilityResponse to api/types.ts
- Implement useAvailabilityStatus (staleTime 30s, stale-on-error preserved)
- Add AvailabilityStatusBadge with green/amber/red states and stale indicator
- Replace DashboardPage placeholder card with live availability widget
- Add MSW availability handler; update test/utils with QueryClientProvider
- 55/55 tests pass (FR-05)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 13:39:29 +02:00
co-authored by Claude Haiku 4.5
parent f476e06691
commit 3c6a06028e
23 changed files with 1219 additions and 22 deletions
@@ -0,0 +1,77 @@
# Business Rules — Unit 4: Dashboard
## Access Rules
| ID | Rule |
|---|---|
| BR-U4-01 | The Dashboard is accessible to all authenticated users regardless of role |
| BR-U4-02 | Unauthenticated users are redirected to `/login` by the existing `authenticatedRoute` guard |
## Data Fetching Rules
| ID | Rule |
|---|---|
| BR-U4-03 | Availability status is fetched via `GET /api/v1/Availability/status` on component mount |
| BR-U4-04 | The query uses TanStack Query with `staleTime: 30_000` (30 seconds) — background refetch triggers automatically when data is stale |
| BR-U4-05 | The endpoint is public (anonymous) — no Bearer token required; the API client still sends credentials for cookie consistency |
## Display Rules
| ID | Rule |
|---|---|
| BR-U4-06 | Status `Available` renders with a **green** visual indicator |
| BR-U4-07 | Status `Maintenance` renders with an **amber/yellow** visual indicator |
| BR-U4-08 | Status `Unavailable` renders with a **red** visual indicator |
| BR-U4-09 | The `message` field is displayed as a subtitle below the status badge when it is a non-empty string |
## Error Handling Rules
| ID | Rule |
|---|---|
| BR-U4-10 | If the initial fetch fails (no cached data): display an error card with a generic message and a **Retry** button |
| BR-U4-11 | If a background refetch fails but cached (stale) data exists: display the stale status badge with a visual "stale" indicator (e.g. amber border, clock icon) AND an error banner with a **Retry** button |
| BR-U4-12 | Clicking the Retry button triggers an immediate refetch via TanStack Query's `refetch()` |
| BR-U4-13 | Network errors and API errors are treated identically from a UI perspective — no internal error details are exposed to the user |
## Loading Rules
| ID | Rule |
|---|---|
| BR-U4-14 | While the initial fetch is in-flight (no cached data): display a skeleton/loading placeholder in the availability widget |
| BR-U4-15 | Background refetches (when cached data exists) do not trigger a loading skeleton — the existing status remains visible |
## Decision Flowchart
```mermaid
graph TD
Mount["Component Mounts"]
HasCache{Cached data exists?}
Loading["Show skeleton loading state"]
FetchSuccess{Fetch successful?}
ShowStatus["Show AvailabilityStatusBadge\n+ message subtitle"]
BackgroundRefetch{Background refetch error?}
ShowStale["Show stale badge\n+ stale indicator\n+ error banner + Retry"]
ShowError["Show error card\n+ Retry button"]
Mount --> HasCache
HasCache -- No --> Loading
HasCache -- Yes --> ShowStatus
Loading --> FetchSuccess
FetchSuccess -- Yes --> ShowStatus
FetchSuccess -- No --> ShowError
ShowStatus --> BackgroundRefetch
BackgroundRefetch -- Yes --> ShowStale
BackgroundRefetch -- No --> ShowStatus
classDef decision fill:#FF9800,stroke:#e65100,color:#000
classDef action fill:#2196F3,stroke:#0d47a1,color:#000
classDef error fill:#F44336,stroke:#b71c1c,color:#000
classDef start fill:#4CAF50,stroke:#2E7D32,color:#000
class Mount start
class HasCache,FetchSuccess,BackgroundRefetch decision
class Loading,ShowStatus action
class ShowError,ShowStale error
```
Flowchart showing dashboard fetch states: skeleton on first load, badge on success, error card (no data) or stale badge + error banner (with data) on failure.