# Logical Components — Unit 3: frontend-cms-page ## Overview ``` src/lib/schemas/ ├── auth.ts (existing — unchanged) ├── users.ts (NEW — migrated from InviteUserDialog inline) └── cms.ts (NEW — addCmsInstanceSchema, setStatusSchema) src/api/ ├── types.ts (extended — CmsInstance, CmsInstanceStatus, CreateCmsInstanceRequest, │ UpdateCmsInstanceStatusRequest, UpdateStatusResult) ├── useCmsInstances.ts (NEW) ├── useAddCmsInstance.ts (NEW) └── useUpdateCmsInstanceStatus.ts (NEW) src/components/cms/ ├── CmsInstanceList.tsx (NEW) ├── AddCmsInstanceDialog.tsx (NEW) └── SetStatusDialog.tsx (NEW) src/components/users/ └── InviteUserDialog.tsx (MODIFIED — schema import + serverError migration) src/pages/ └── CmsPage.tsx (MODIFIED — replace placeholder with full page) src/i18n/locales/ ├── en/translation.json (MODIFIED — cms.* keys added) └── nl/translation.json (MODIFIED — cms.* keys added) src/mocks/ ├── cms/handlers.ts (NEW — GET, POST, PUT MSW handlers) ├── browser.ts (MODIFIED — register cms handlers) └── server.ts (MODIFIED — register cms handlers) Test files: ├── src/lib/schemas/cms.test.ts (NEW) ├── src/lib/schemas/users.test.ts (NEW) ├── src/api/useCmsInstances.test.ts (NEW) ├── src/api/useAddCmsInstance.test.ts (NEW) ├── src/api/useUpdateCmsInstanceStatus.test.ts (NEW) ├── src/components/cms/AddCmsInstanceDialog.test.tsx (NEW) ├── src/components/cms/SetStatusDialog.test.tsx (NEW) └── src/pages/CmsPage.test.tsx (MODIFIED — replace placeholder assertions) ``` --- ## Component Responsibilities ### `src/lib/schemas/cms.ts` — Validation Logic | Export | Validates | |--------|-----------| | `addCmsInstanceSchema` | name (required, max 255), url (z.string().url()), apiKey (required) | | `AddCmsInstanceFormData` | Inferred type | | `setStatusSchema` | status (enum), disableMessage (required when NotAvailable via `.refine()`) | | `SetStatusFormData` | Inferred type | ### `src/lib/schemas/users.ts` — Migrated Schema | Export | Source | |--------|--------| | `inviteUserSchema` | Migrated from `InviteUserDialog.tsx` inline — no behaviour change | | `InviteUserFormData` | Inferred type | ### `src/api/useCmsInstances.ts` — Query Hook | Concern | Implementation | |---------|---------------| | Endpoint | `GET /api/v1/CmsInstances` | | Query key | `['cmsInstances']` | | Stale time | 30 000 ms | | Return type | `UseQueryResult` | ### `src/api/useAddCmsInstance.ts` — Mutation Hook | Concern | Implementation | |---------|---------------| | Endpoint | `POST /api/v1/CmsInstances` | | Body | `CreateCmsInstanceRequest` | | On success | `invalidateQueries(['cmsInstances'])` | | Accepts | Optional `onError` callback (caller sets `serverError` state) | ### `src/api/useUpdateCmsInstanceStatus.ts` — Mutation Hook | Concern | Implementation | |---------|---------------| | Endpoint | `PUT /api/v1/CmsInstances/{id}/status` | | Variables | `{ id: string } & UpdateCmsInstanceStatusRequest` | | Return | `UpdateStatusResult` | | On success | `invalidateQueries(['cmsInstances'])` | | Accepts | Optional `onSuccess` / `onError` callbacks | ### `src/mocks/cms/handlers.ts` — MSW Handlers | Handler | Behaviour | |---------|-----------| | `GET /api/v1/CmsInstances` | Returns in-memory `cmsInstances[]` array | | `POST /api/v1/CmsInstances` | Pushes new instance to array; returns 201 + created instance | | `PUT /api/v1/CmsInstances/:id/status` | Updates instance in array; returns `UpdateStatusResult` | In-memory state initialised with 1-2 seed instances to support development and test scenarios. --- ## Migration Summary | File | Change | Reason | |------|--------|--------| | `InviteUserDialog.tsx` | Import schema from `@/lib/schemas/users` instead of inline | Pattern 1 (centralised schemas) | | `InviteUserDialog.tsx` | Replace `inviteUser.error` with `useState` | Pattern 2 (consistent error handling) | | `src/lib/schemas/users.ts` | New file — migrated `inviteSchema` | Pattern 1 | | `src/lib/schemas/users.test.ts` | New file — tests for `inviteUserSchema` | NFR-FE-04 |