40227-vm/frontend/docs/zone-checkin-integration.md

4.0 KiB

Daily Zone Check-in Integration

Purpose

Staff log a daily self-regulation "Emotional Zone" (blue/green/yellow/red). The same state drives the dashboard check-in card, the /zones-of-regulation overview cards, the profile unified results table, leader dashboard completion/risk sections, and a notification-dropdown nudge when an eligible user has not checked in today.

Backend contract

/api/zone_checkins requires explicit ZONE_CHECKIN for personal reads/writes. This personal workflow permission is not implied by globalAccess. The client never computes the date; "today" is computed server-side from the user's campus timezone, falling back to UTC for organization/school-scope staff without a campus.

  • GET /today{ date, zone, isCheckedInToday }
  • POST / { data: { zone } } → record today's zone (upsert)
  • DELETE /today → clear today's zone
  • GET /?from=&to= → history { rows: [{ date, zone }], count }
  • GET /completion → leader/report scoped staff completion { summary, rows } with READ_ZONE_CHECKIN_REPORTS.

Frontend Structure

  • API/types: shared/api/zoneCheckins.ts, shared/types/zoneCheckins.ts
  • Business: business/zone-checkin/hooks.ts (useTodayZoneCheckIn, useZoneCheckInHistory, useZoneCheckInCompletion), business/zone-checkin/selectors.ts (canZoneCheckIn, shouldNudgeZoneCheckIn)
  • Components: components/zone-checkin/ZoneCheckInCard.tsx (shared dashboard card), ZoneCheckInReminder.tsx (banner), ZoneCheckInSection.tsx (composed section), and the /zones-of-regulation overview cards.

Behavior

  • Eligibility/nudge gating requires the effective ZONE_CHECKIN permission. Seed data grants it to staff users expected to complete the daily workflow across organization, school, campus, and class scopes; custom permissions can extend or remove it per user.
  • Dashboard: the card is wired through useDashboardPage (which exposes showZoneCheckIn + needsZoneCheckIn) with an optimistic shell value for snappy selection.
  • Zones page: the main zone overview cards call useTodayZoneCheckIn through useZonesOfRegulationPage; selecting blue/green/yellow/red both opens the zone detail panel and saves the eligible user's daily check-in. Parent drill-down keeps the selection local and does not persist personal state; the backend also rejects personal zone mutations in child scopes.
  • Notifications: business/top-bar derives a single unread notification from shouldNudgeZoneCheckIn (buildTopBarNotifications) — there is no backend notifications store. The notification carries an href (APP_ROUTE_PATHS.zones); clicking it navigates to /zones-of-regulation (a react-router Link) and closes the dropdown.
  • useTodayZoneCheckIn is disabled for users without ZONE_CHECKIN or when the user is drilled into a child scope. Disabled callers receive empty local state instead of stale cached check-in data. Its error surfaces only save/clear failures; non-eligible users should not trigger the /today request.
  • Leader dashboards: useDirectorDashboardPage loads useZoneCheckInCompletion with the effective tenant in its query key and appends Daily Zone Check-In rows to the unified completion table. Non-green completed zones are shown as medium risk in Risk Areas.
  • Profile: the unified quiz/results table includes today's Daily Zone Check-In for eligible users.
  • Content: zone cards and page copy are backend-owned content catalog presets (regulation-zones, zones-of-regulation-page-content) for new organizations.

Tests

  • business/zone-checkin/selectors.test.ts (eligibility + nudge), business/top-bar/selectors.test.ts (notification builder + zones href), business/director-dashboard/selectors.test.ts, business/profile/selectors.test.ts, and shared/api/zoneCheckins.test.ts.
  • Seeded e2e: frontend/tests/e2e/zone-checkins.seeded.e2e.ts (record / read-back / clear today, invalid-zone rejection, external-role lockout).

Verification

  • npm run typecheck, npm run lint, npm run test pass.