feat: calendar subscription iOS UI (Slice 4C of calendar sync payload) #250

Merged
owlburtoe merged 1 commit from worktree-feat+calendar-sync-slice-4c-ios-ui into main 2026-05-28 20:07:10 -04:00
Owner

Slice 4C of the Calendar Sync Payload enrichment (spec Section C, "Settings UI") — the iOS counterpart of the web UI (Slice 4B, #249). Builds on merged Slice 4A (#246: token model + ICS feed + dept-scoped subscription endpoints).

What it adds

A Calendar Subscription section in Settings → Preferences (staff-only, mirrors the existing Calendar Sync gate + requires a dept slug):

  • Subscription Link row — the staff member's private HTTPS ICS feed URL (lazily minted on first load).
  • Copy LinkUIPasteboard, with a confirmation notice.
  • Subscribe in Calendar — opens the webcal:// form via @Environment(\.openURL) so the system calendar subscribes.
  • Regenerate Link — gated by a confirmationDialog with the exact spec copy: "Existing calendar subscriptions will stop syncing. You'll need to re-add the URL to each calendar app."

Layers (mirrors existing iOS patterns)

  • ShiftdKitCalendarSubscriptionURL DTO (CalendarSubscriptionAPI.swift) + calendarSubscription(in:) / regenerateCalendarSubscription(in:) on ShiftdAPIClient via the sendAuthenticated seam, mirroring Slice 3's hand-written FacilityAPI pattern (the spec operations are unnamed, so a flat DTO beats a generated type).
  • SettingsViewModelshowsCalendarSubscription derived gate + calendarSubscriptionURL / loading / error / regenerating state and loadCalendarSubscription / regenerateCalendarSubscription, matching the screen's existing notice/error idiom.
  • CalendarSubscriptionURLFormatter — pure webcal:// derivation helper (app-target Shared/Calendar, alongside Slice 3's formatters).

Scope

iOS-only; no backend/schema/OpenAPI change. The endpoints and OpenAPI shipped in 4A.

Testing — all green

  • ShiftdKit 52/52 (+2: CalendarSubscriptionAPITests — DTO decode + equatable).
  • App target 154/154 (+9: CalendarSubscriptionURLFormatterTests https/http/already-webcal/empty/URL-scheme/nil — 6; SettingsViewModelTests staff sees / admin hidden / missing-dept hidden — 3).
  • Built + tested on the iOS 17 simulator (-skipPackagePluginValidation). No iOS CI runs server-side, so this local run is the validation.

This is the final slice of the Calendar Sync Payload feature (1, 2, 3, 4A, 4B all merged).

Slice 4C of the Calendar Sync Payload enrichment (spec Section C, "Settings UI") — the **iOS** counterpart of the web UI (Slice 4B, #249). Builds on merged Slice 4A (#246: token model + ICS feed + dept-scoped subscription endpoints). ## What it adds A **Calendar Subscription** section in Settings → Preferences (staff-only, mirrors the existing Calendar Sync gate + requires a dept slug): - **Subscription Link** row — the staff member's private HTTPS ICS feed URL (lazily minted on first load). - **Copy Link** — `UIPasteboard`, with a confirmation notice. - **Subscribe in Calendar** — opens the `webcal://` form via `@Environment(\.openURL)` so the system calendar subscribes. - **Regenerate Link** — gated by a `confirmationDialog` with the exact spec copy: _"Existing calendar subscriptions will stop syncing. You'll need to re-add the URL to each calendar app."_ ### Layers (mirrors existing iOS patterns) - **ShiftdKit** — `CalendarSubscriptionURL` DTO (`CalendarSubscriptionAPI.swift`) + `calendarSubscription(in:)` / `regenerateCalendarSubscription(in:)` on `ShiftdAPIClient` via the `sendAuthenticated` seam, mirroring Slice 3's hand-written `FacilityAPI` pattern (the spec operations are unnamed, so a flat DTO beats a generated type). - **SettingsViewModel** — `showsCalendarSubscription` derived gate + `calendarSubscriptionURL` / loading / error / regenerating state and `loadCalendarSubscription` / `regenerateCalendarSubscription`, matching the screen's existing notice/error idiom. - **CalendarSubscriptionURLFormatter** — pure `webcal://` derivation helper (app-target Shared/Calendar, alongside Slice 3's formatters). ## Scope iOS-only; no backend/schema/OpenAPI change. The endpoints and OpenAPI shipped in 4A. ## Testing — all green - **ShiftdKit 52/52** (+2: `CalendarSubscriptionAPITests` — DTO decode + equatable). - **App target 154/154** (+9: `CalendarSubscriptionURLFormatterTests` https/http/already-webcal/empty/URL-scheme/nil — 6; `SettingsViewModelTests` staff sees / admin hidden / missing-dept hidden — 3). - Built + tested on the iOS 17 simulator (`-skipPackagePluginValidation`). No iOS CI runs server-side, so this local run is the validation. This is the final slice of the Calendar Sync Payload feature (1, 2, 3, 4A, 4B all merged).
feat(ios): calendar subscription UI in personal settings
All checks were successful
Code Scanning / Gitleaks secret scan (pull_request) Successful in 6s
Code Scanning / Semgrep OSS source scan (pull_request) Successful in 38s
Security, Type Check & Runtime / Dependency Audit (pull_request) Successful in 9m41s
Security, Type Check & Runtime / Migration Guardrails (pull_request) Successful in 9m34s
Security, Type Check & Runtime / Type Check (pull_request) Successful in 10m9s
Security, Type Check & Runtime / Backend Runtime Smoke (pull_request) Successful in 10m9s
dabef8d4e2
Slice 4C of calendar sync payload — the iOS counterpart of the web UI
(4B). Adds a Calendar Subscription section to Settings > Preferences
(staff-only) showing the staff member's private ICS feed URL with Copy,
a webcal:// Subscribe action (opens the system calendar), and a
Regenerate action gated by a confirmation dialog.

- ShiftdKit: CalendarSubscriptionURL DTO + client methods
  calendarSubscription(in:) / regenerateCalendarSubscription(in:) via the
  sendAuthenticated seam, mirroring the FacilityAPI hand-written pattern.
- SettingsViewModel: showsCalendarSubscription gate (staff + dept) plus
  load/regenerate state and methods, matching the existing notice/error
  handling.
- CalendarSubscriptionURLFormatter: pure webcal:// derivation helper.
- SettingsView: Calendar Subscription section with the spec confirmation
  copy on regenerate.

Consumes Slice 4A endpoints. ShiftdKit 52/52, app target 154/154 green.
owlburtoe deleted branch worktree-feat+calendar-sync-slice-4c-ios-ui 2026-05-28 20:07:10 -04:00
Sign in to join this conversation.
No description provided.