feat: calendar subscription web UI (Slice 4B of calendar sync payload) #249

Merged
owlburtoe merged 1 commit from worktree-feat+calendar-sync-slice-4b-web-ui into main 2026-05-28 19:41:24 -04:00
Owner

Slice 4B of the Calendar Sync Payload enrichment (spec Section C, "Settings UI"). Frontend web UI for the staff calendar subscription. Builds on merged Slice 4A (#246, backend token model + ICS feed + dept-scoped subscription endpoints).

What it adds

  • Calendar Subscription card in the Profile tab of the user profile sheet (UserProfileTab, after Role & Assignment):
    • Read-only HTTPS feed URL with a Copy action (navigator.clipboard + success/error toast).
    • Subscribe link using the webcal:// scheme so calendar apps add the feed directly.
    • Regenerate action gated by an AlertDialog with the exact spec confirmation copy: "Existing calendar subscriptions will stop syncing. You'll need to re-add the URL to each calendar app."
  • CalendarSubscriptionCard.tsx follows the repo's FacilityAddressSection pattern: pure exported helpers (toWebcalUrl, getCalendarSubscriptionErrorMessage, CALENDAR_REGENERATE_WARNING) + a presentational CalendarSubscriptionView + a thin data container (useQuery/useMutation, clipboard, toasts). Regenerate writes the new URL straight into the query cache.
  • api.ts: fetchCalendarSubscriptionUrl / regenerateCalendarSubscriptionUrl hitting the 4A endpoints via the existing dept-scoped path auto-rewrite (/api/staff/me/.../api/d/{slug}/staff/me/...).

Scope

Frontend-only. No schema, migration, or OpenAPI change (4A already added the CalendarSubscription schema + the three operations).

Testing — all green

  • CalendarSubscriptionCard.test.tsx (12): toWebcalUrl (https/http/already-webcal/empty), exact warning constant, error mapping (403 → permission / generic / fallback), and the presentational view (URL input, webcal:// href derivation, loading hides URL, Copy + Regenerate present). Pure-helper + headless renderToStaticMarkup style, no jsdom — matches the repo convention.
  • Full frontend suite 713/713 (80 files, +12 vs baseline).
  • pnpm check-types clean; pnpm check:url-generation clean; eslint clean on changed files.

Slice 4C (iOS subscription UI) is the remaining sibling; it also depends only on 4A and is independent of this PR.

Slice 4B of the Calendar Sync Payload enrichment (spec Section C, "Settings UI"). Frontend web UI for the staff calendar subscription. Builds on merged Slice 4A (#246, backend token model + ICS feed + dept-scoped subscription endpoints). ## What it adds - **Calendar Subscription card** in the Profile tab of the user profile sheet (`UserProfileTab`, after Role & Assignment): - Read-only HTTPS feed URL with a **Copy** action (`navigator.clipboard` + success/error toast). - **Subscribe** link using the `webcal://` scheme so calendar apps add the feed directly. - **Regenerate** action gated by an `AlertDialog` with the exact spec confirmation copy: _"Existing calendar subscriptions will stop syncing. You'll need to re-add the URL to each calendar app."_ - **`CalendarSubscriptionCard.tsx`** follows the repo's `FacilityAddressSection` pattern: pure exported helpers (`toWebcalUrl`, `getCalendarSubscriptionErrorMessage`, `CALENDAR_REGENERATE_WARNING`) + a presentational `CalendarSubscriptionView` + a thin data container (`useQuery`/`useMutation`, clipboard, toasts). Regenerate writes the new URL straight into the query cache. - **`api.ts`**: `fetchCalendarSubscriptionUrl` / `regenerateCalendarSubscriptionUrl` hitting the 4A endpoints via the existing dept-scoped path auto-rewrite (`/api/staff/me/...` → `/api/d/{slug}/staff/me/...`). ## Scope Frontend-only. No schema, migration, or OpenAPI change (4A already added the `CalendarSubscription` schema + the three operations). ## Testing — all green - `CalendarSubscriptionCard.test.tsx` (12): `toWebcalUrl` (https/http/already-webcal/empty), exact warning constant, error mapping (403 → permission / generic / fallback), and the presentational view (URL input, `webcal://` href derivation, loading hides URL, Copy + Regenerate present). Pure-helper + headless `renderToStaticMarkup` style, no jsdom — matches the repo convention. - Full frontend suite **713/713** (80 files, +12 vs baseline). - `pnpm check-types` clean; `pnpm check:url-generation` clean; eslint clean on changed files. Slice 4C (iOS subscription UI) is the remaining sibling; it also depends only on 4A and is independent of this PR.
feat(frontend): calendar subscription card in personal settings
All checks were successful
Code Scanning / Gitleaks secret scan (pull_request) Successful in 5s
Code Scanning / Semgrep OSS source scan (pull_request) Successful in 36s
Security, Type Check & Runtime / Dependency Audit (pull_request) Successful in 9m38s
Security, Type Check & Runtime / Migration Guardrails (pull_request) Successful in 9m40s
Security, Type Check & Runtime / Backend Runtime Smoke (pull_request) Successful in 10m17s
Security, Type Check & Runtime / Type Check (pull_request) Successful in 10m22s
Release Artifacts / Validate release candidate (pull_request) Successful in 10m52s
Release Artifacts / Build and push Docker release images (pull_request) Has been skipped
E2E Tests / e2e (pull_request) Successful in 14m46s
c8bedcd119
Slice 4B of calendar sync payload. Adds a Calendar Subscription card to
the Profile tab showing the staff member's private ICS feed URL with a
Copy action and a webcal:// Subscribe link, plus a Regenerate action
gated by a confirmation dialog.

- CalendarSubscriptionCard.tsx: pure helpers (toWebcalUrl, error mapping,
  exact regenerate-warning constant) + presentational CalendarSubscriptionView
  + thin data container (useQuery/useMutation, clipboard, toasts).
- api.ts: fetchCalendarSubscriptionUrl / regenerateCalendarSubscriptionUrl
  hitting the 4A dept-scoped endpoints via path auto-rewrite.
- Wired into UserProfileTab after Role & Assignment.

Consumes Slice 4A endpoints (#246). Frontend-only; no schema/openapi change.
713 frontend tests pass (+12), tsc + url-generation guard clean.
Sign in to join this conversation.
No description provided.