# Code Generation Plan — Unit 4: Dashboard **Status**: ✅ Complete ## Unit Context **Unit**: Unit 4 — Dashboard **Type**: Frontend (React/TypeScript) **Depends on**: Unit 3 (AppLayout, AuthContext) — complete **Stories Covered**: FR-05 (availability widget on dashboard) **Key Design Decisions** (from functional design): - `@tanstack/react-query` added as new dependency; `QueryClientProvider` wraps the app in `main.tsx` - `useAvailabilityStatus` uses `useQuery` with `staleTime: 30_000` ms - Error + stale data: show last known status with stale indicator + error banner with Retry - `AvailabilityStatus` type and `AvailabilityResponse` interface added to `api/types.ts` - MSW mock handler created for tests **Files to Modify**: - `frontend/package.json` — add `@tanstack/react-query` - `frontend/src/main.tsx` — wrap with `QueryClientProvider` - `frontend/src/api/types.ts` — add `AvailabilityStatus`, `AvailabilityResponse` - `frontend/src/mocks/index.ts` — register availability handlers - `frontend/src/pages/DashboardPage.tsx` — replace placeholder with availability widget - `frontend/src/i18n/locales/en/translation.json` — add `availability.*` keys - `frontend/src/i18n/locales/nl/translation.json` — add `availability.*` keys **Files to Create**: - `frontend/src/api/useAvailability.ts` - `frontend/src/components/shared/AvailabilityStatusBadge.tsx` - `frontend/src/mocks/availability/handlers.ts` - `frontend/src/api/useAvailability.test.ts` - `frontend/src/components/shared/AvailabilityStatusBadge.test.tsx` - `aidlc-docs/features/cms-frontend/construction/unit-4/code/code-generation-summary.md` --- ## Code Generation Steps ### Step 1: Install `@tanstack/react-query` - [x] Run `pnpm add @tanstack/react-query` in `frontend/` - [x] Verify `package.json` updated with `@tanstack/react-query` ### Step 2: Add `AvailabilityStatus` and `AvailabilityResponse` to `api/types.ts` - [x] Append to `frontend/src/api/types.ts`: ```ts export type AvailabilityStatus = 'Available' | 'Maintenance' | 'Unavailable'; export interface AvailabilityResponse { status: AvailabilityStatus; checkedAt: string; // ISO 8601 message: string; } ``` ### Step 3: Wrap app with `QueryClientProvider` in `main.tsx` - [x] Import `QueryClient`, `QueryClientProvider` from `@tanstack/react-query` - [x] Create `queryClient` instance with `defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: true } }` - [x] Wrap `` with `` ### Step 4: Create `useAvailability.ts` - [x] Create `frontend/src/api/useAvailability.ts` - [x] Implement `useAvailabilityStatus()` using `useQuery`: - `queryKey: ['availability', 'status']` - `queryFn`: `api.get('/api/v1/Availability/status')` - `staleTime: 30_000` - [x] Return full TanStack Query result (`data`, `error`, `isLoading`, `isError`, `isFetching`, `refetch`) ### Step 5: Create `AvailabilityStatusBadge.tsx` - [x] Create `frontend/src/components/shared/AvailabilityStatusBadge.tsx` - [x] Props: `status: AvailabilityStatus`, `message?: string`, `stale?: boolean` - [x] Status → color/icon mapping: - `Available` → `bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200` + `CheckCircle` icon - `Maintenance` → `bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-200` + `AlertTriangle` icon - `Unavailable` → `bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200` + `XCircle` icon - [x] Show `message` as subtitle paragraph when non-empty (`data-testid="availability-message"`) - [x] When `stale={true}`: amber dashed border + `Clock` icon + `t('availability.staleLabel')` label (`data-testid="availability-stale-indicator"`) - [x] Test IDs: `availability-badge` (wrapper), `availability-status-label` ### Step 6: Update `DashboardPage.tsx` - [x] Import `useAvailabilityStatus`, `AvailabilityStatusBadge` and `Card*` components - [x] Replace generic placeholder `Card` with the availability widget: - Card title: `t('availability.title')` - `isLoading` → skeleton placeholder (`data-testid="availability-skeleton"`) - `data` present → `` - `isError && !data` → error-only state: `t('availability.errorTitle')` + Retry button - `isError` (any) → error banner below/above badge with Retry button (`data-testid="availability-error"`, `data-testid="availability-retry"`) - [x] Keep welcome header section unchanged ### Step 7: Add i18n keys - [x] Add to `frontend/src/i18n/locales/en/translation.json`: ```json "availability": { "title": "System Status", "available": "Available", "maintenance": "Maintenance", "unavailable": "Unavailable", "errorTitle": "Could not load status", "staleLabel": "Last known status", "retry": "Retry" } ``` - [x] Add to `frontend/src/i18n/locales/nl/translation.json`: ```json "availability": { "title": "Systeemstatus", "available": "Beschikbaar", "maintenance": "Onderhoud", "unavailable": "Niet beschikbaar", "errorTitle": "Status kon niet worden geladen", "staleLabel": "Laatste bekende status", "retry": "Opnieuw proberen" } ``` ### Step 8: Create MSW availability handler - [x] Create `frontend/src/mocks/availability/handlers.ts`: ```ts import { http, HttpResponse } from 'msw'; export const availabilityHandlers = [ http.get('*/Availability/status', () => HttpResponse.json({ status: 'Available', checkedAt: new Date().toISOString(), message: '', }) ), ]; ``` - [x] Modify `frontend/src/mocks/index.ts`: - Import `availabilityHandlers` - Spread into `handlers` array - Re-export `availabilityHandlers` ### Step 9: Tests — `useAvailabilityStatus` - [x] Create `frontend/src/api/useAvailability.test.ts` - [x] Test cases (using MSW + `renderHook` with `QueryClientProvider` wrapper): - Returns `isLoading=true` initially - Returns `data` on successful fetch (using default MSW handler) - Returns `isError=true` + preserves stale `data` on refetch failure (override handler to return 500) - `refetch()` triggers a new fetch ### Step 10: Tests — `AvailabilityStatusBadge` - [x] Create `frontend/src/components/shared/AvailabilityStatusBadge.test.tsx` - [x] Test cases: - `Available` → green badge, `t('availability.available')` label - `Maintenance` → amber badge, `t('availability.maintenance')` label - `Unavailable` → red badge, `t('availability.unavailable')` label - `message` prop: renders subtitle when non-empty, hidden when empty - `stale={true}`: renders stale indicator - `stale={false}` (default): no stale indicator ### Step 11: Final verification - [x] `pnpm build` — no TypeScript or Vite errors - [x] `pnpm lint` — no ESLint errors - [x] `pnpm test` — all tests pass (existing + new) - [x] Dev server: verify availability widget renders on dashboard, skeleton visible on load, Retry button functional ### Step 12: Write code generation summary - [x] Create `aidlc-docs/features/cms-frontend/construction/unit-4/code/code-generation-summary.md` - [x] List all created/modified files with paths - [x] Record test results ### Step 13: Commit - [x] Commit with message referencing Unit 4 / FR-05 --- ## Total Steps: 13