Files
SluijsensandClaude Haiku 4.5 3c6a06028e 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>
2026-06-22 13:39:29 +02:00

7.2 KiB

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

  • Run pnpm add @tanstack/react-query in frontend/
  • Verify package.json updated with @tanstack/react-query

Step 2: Add AvailabilityStatus and AvailabilityResponse to api/types.ts

  • Append to frontend/src/api/types.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

  • Import QueryClient, QueryClientProvider from @tanstack/react-query
  • Create queryClient instance with defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: true } }
  • Wrap <AuthProvider> with <QueryClientProvider client={queryClient}>

Step 4: Create useAvailability.ts

  • Create frontend/src/api/useAvailability.ts
  • Implement useAvailabilityStatus() using useQuery:
    • queryKey: ['availability', 'status']
    • queryFn: api.get<AvailabilityResponse>('/api/v1/Availability/status')
    • staleTime: 30_000
  • Return full TanStack Query result (data, error, isLoading, isError, isFetching, refetch)

Step 5: Create AvailabilityStatusBadge.tsx

  • Create frontend/src/components/shared/AvailabilityStatusBadge.tsx
  • Props: status: AvailabilityStatus, message?: string, stale?: boolean
  • Status → color/icon mapping:
    • Availablebg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200 + CheckCircle icon
    • Maintenancebg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-200 + AlertTriangle icon
    • Unavailablebg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200 + XCircle icon
  • Show message as subtitle paragraph when non-empty (data-testid="availability-message")
  • When stale={true}: amber dashed border + Clock icon + t('availability.staleLabel') label (data-testid="availability-stale-indicator")
  • Test IDs: availability-badge (wrapper), availability-status-label

Step 6: Update DashboardPage.tsx

  • Import useAvailabilityStatus, AvailabilityStatusBadge and Card* components
  • Replace generic placeholder Card with the availability widget:
    • Card title: t('availability.title')
    • isLoading → skeleton placeholder (data-testid="availability-skeleton")
    • data present → <AvailabilityStatusBadge status={data.status} message={data.message} stale={isError} />
    • 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")
  • Keep welcome header section unchanged

Step 7: Add i18n keys

  • Add to frontend/src/i18n/locales/en/translation.json:
    "availability": {
      "title": "System Status",
      "available": "Available",
      "maintenance": "Maintenance",
      "unavailable": "Unavailable",
      "errorTitle": "Could not load status",
      "staleLabel": "Last known status",
      "retry": "Retry"
    }
    
  • Add to frontend/src/i18n/locales/nl/translation.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

  • Create frontend/src/mocks/availability/handlers.ts:
    import { http, HttpResponse } from 'msw';
    export const availabilityHandlers = [
        http.get('*/Availability/status', () =>
            HttpResponse.json({
                status: 'Available',
                checkedAt: new Date().toISOString(),
                message: '',
            })
        ),
    ];
    
  • Modify frontend/src/mocks/index.ts:
    • Import availabilityHandlers
    • Spread into handlers array
    • Re-export availabilityHandlers

Step 9: Tests — useAvailabilityStatus

  • Create frontend/src/api/useAvailability.test.ts
  • 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

  • Create frontend/src/components/shared/AvailabilityStatusBadge.test.tsx
  • 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

  • pnpm build — no TypeScript or Vite errors
  • pnpm lint — no ESLint errors
  • pnpm test — all tests pass (existing + new)
  • Dev server: verify availability widget renders on dashboard, skeleton visible on load, Retry button functional

Step 12: Write code generation summary

  • Create aidlc-docs/features/cms-frontend/construction/unit-4/code/code-generation-summary.md
  • List all created/modified files with paths
  • Record test results

Step 13: Commit

  • Commit with message referencing Unit 4 / FR-05

Total Steps: 13