Mobile Doctor Dashboard Redesign — Detailed Changes
Date: 2026-05-20
Repos: Okta-Mobile, OktaPT-API
Branch: development
Scope: ~10,000+ insertions in Okta-Mobile, plus a shared backend service extracted from a new admin tool
Architecture and feature design are documented in mobile-doctor-dashboard.md. The admin Daily Review tool that shares the backend is documented in internal/daily-review.md. This document covers the file-by-file scope.
Summary
The mobile doctor home was rebuilt around a new patient list (PatientSummary model with compliance grades and activity stats), a "seeing today" workflow, a dedicated patient detail screen with action grid, a Quick Analysis screen that surfaces flags and suggested clinical notes, and an in-modal patient re-onboarding flow. The redesign also adds a tenant-wide search, skeleton loading states, and explanatory Section Info modals for movement tests and personalized videos. Backend support was added by extracting gradeFromActivity and getPatientSummaryStats from the admin Daily Review service so doctor patient-list endpoints return the same data inline.
The same release window bundled an Expo/RN SDK upgrade, an eslint config rewrite, and ~140 new translation keys (English + Russian).
New Files (Okta-Mobile)
Doctor Dashboard Components
| File |
Lines |
Purpose |
components/doctor/ComplianceGrade.tsx |
113 |
Letter/chip with palette per grade (A+/A green, B lime, C amber, D orange, F red, NONE gray) |
components/doctor/FlagChip.tsx |
57 |
Generic status flag chip (elevated pain, long inactivity, etc.) |
components/doctor/PatientRow.tsx |
213 |
Patient list cell with avatar, grade chip, last-visit chip, today indicator |
components/doctor/PatientRowSkeleton.tsx |
42 |
Loading placeholder matching the row layout |
components/doctor/PatientSearchModal.tsx |
196 |
Tenant-wide search modal with debounced query |
components/doctor/TodayPickerModal.tsx |
321 |
"Add patient seeing today" picker; preloads full caseload |
components/doctor/ReonboardPatientModal.tsx |
603 |
Re-onboarding modal: loading → DOB required → ready (email/copy/QR) → error |
components/doctor/SectionInfoModal.tsx |
159 |
Generic explanatory popup used for Movement Tests / Personalized Videos sections |
components/doctor/SessionPreviewCard.tsx |
278 |
Session/exercise card reused by patient detail, quick analysis, all-sessions |
components/doctor/PatientTestRow.tsx |
123 |
Recent clinical-assessment row in patient detail |
components/Skeleton.tsx |
48 |
Generic shimmer skeleton primitive |
New Screens
| File |
Lines |
Purpose |
app/(doctor)/patient/[id].tsx |
1,211 |
Patient detail hub: care team, action grid, movement tests, personalized videos, Quick Analysis link, Re-onboard CTA |
app/(doctor)/patient-analysis/[id].tsx |
722 |
Quick Analysis: compliance, flags, suggested notes, next-up, last-completed, footer stats |
app/(doctor)/patient-sessions/[id].tsx |
366 |
All completed sessions, expandable to per-exercise pain/exertion detail |
Services & Hooks
| File |
Lines |
Purpose |
services/doctorPatientsService.ts |
48 |
getMyPatients, getAllTenantPatients, getPatientSummary — typed wrappers around the doctor controller endpoints |
services/patientAnalysisService.ts |
117 |
Quick Analysis payload + ComplianceGrade type |
services/patientInviteService.ts |
35 |
generateInviteLink, sendInviteEmail — re-onboarding endpoints |
services/signedUrlUploadService.ts |
47 |
Shared signed-URL upload helper used by videoUploadService.ts |
hooks/usePatientsSummary.ts |
150 |
Caseload loader with scope toggle (My / All), cache, refresh on focus |
Modified Files (Okta-Mobile)
Existing Dashboard
| File |
Δ |
What changed |
components/doctor/DoctorDashboard.tsx |
+904 / -large |
Full rewrite around SectionList, scope toggle, modals, today section |
app/(doctor)/_layout.tsx |
+3 |
Registered new patient/[id], patient-analysis/[id], patient-sessions/[id] routes |
app/(doctor)/(clinical-assessment)/recent-tests.tsx |
+47 |
Adjusted styling/back-link to fit new patient detail flow |
hooks/useInClinicPatients.ts |
+57 |
Persists "today" patient list per doctor in AsyncStorage |
Personalized Video Library
| File |
Δ |
What changed |
app/(doctor)/(personalized-video)/exercise-search.tsx |
+99 |
Lists all exercises by default (no required search term) + inline "create exercise" header |
app/(doctor)/(personalized-video)/patient-videos.tsx |
+151 |
Polished video list, processing-state placeholders |
app/(doctor)/(personalized-video)/record.tsx |
+352 |
Choose-from-Library improvements, library video duration guard, preview screen |
components/exercises/MediaPicker.tsx |
+18 |
Library mode for video selection |
services/personalizedVideoService.ts |
+19 |
New library-related calls + types |
services/videoUploadService.ts |
+91 |
Uses signedUrlUploadService for reliability |
Onboarding
| File |
Δ |
What changed |
components/doctor/onboarding/OnboardPatientModal.tsx |
+1,785 |
Significant expansion of the in-app onboarding modal (validation, flows, error states) |
components/doctor/onboarding/DOBFieldInput.tsx |
+43 |
Reused inside ReonboardPatientModal |
Translations
| File |
Δ |
What changed |
locales/en.json |
+518 |
New keys under doctorHome, patientDetail, quickAnalysis, inClinic, personalizedVideo |
locales/ru.json |
+518 |
Matching Russian translations |
SDK Upgrade
| File |
Δ |
What changed |
package.json |
+56 / -52 |
Expo / React Native dependency bumps |
package-lock.json |
~12,000 lines |
Regenerated lockfile |
eslint.config.js |
+40 |
New flat-config replacing .eslintrc.js (-41) |
Backend (OktaPT-API)
New Files
| File |
Lines |
Purpose |
src/services/dailyReviewService.ts |
821 |
Compliance grading, suggested notes, payload builders. Exports gradeFromActivity, getPatientSummaryStats, buildDailyReview, computeComplianceForPatient |
src/routes/admin/dailyReview.controllers.ts |
60 |
POST /v2/admin/daily-review handler |
src/routes/personalized-exercise-videos/storageNaming.ts |
64 |
Deterministic S3 / Cloudflare naming for personalized videos |
src/routes/personalized-exercise-videos/__tests__/storageNaming.test.ts |
81 |
Storage naming tests |
src/routes/personalized-exercise-videos/__tests__/uploadComplete.test.ts |
246 |
Upload-complete pipeline tests |
src/services/__tests__/personalizedVideoService.test.ts |
120 |
Service-level tests |
Modified Files
| File |
Δ |
What changed |
src/routes/doctor/controller.ts |
+757 / -large |
Patient list endpoints now compute compliance grades + activity stats via gradeFromActivity + getPatientSummaryStats; added single-patient summary endpoint used by Quick Analysis |
src/routes/doctor/index.ts |
+6 |
New routes registered |
src/routes/admin/index.ts |
+4 |
POST /v2/admin/daily-review registered |
src/routes/user/onboarding.controllers.ts |
-208 net |
Token hashing migrated from bcrypt to SHA-256 + indexed unique lookup (separately documented in internal/patient-onboarding.md) |
src/routes/personalized-exercise-videos/controllers.ts |
+59 |
Use new storage naming + signed-URL response shape |
src/routes/personalized-exercise-videos/personalizedVideoProcessor.ts |
+8 |
Naming refactor pickups |
src/services/personalizedVideoService.ts |
+76 |
Updated to consume new naming |
prisma/schema.prisma |
+4 |
Added indexing for invite token lookup |
prisma/migrations/20260516153612_added_indexing/migration.sql |
11 |
PatientInviteToken.token index |
Frontend (OktaPT-FE)
While this changeset is mobile-centric, the same release shipped FE files supporting the admin Daily Review tool and a separate web logout bug fix. Documented separately in CHANGELOG.
Daily Review Page
| File |
Lines |
Purpose |
pages/admin/daily-review.tsx |
863 |
Admin page: tenant → therapist → date → patient multi-select → generate → PDF |
lib/pdf/components/DailyReviewPDF.tsx |
556 |
React-PDF document |
lib/pdf/components/DailyReviewDownloadButton.tsx |
220 |
Blob provider + download button |
lib/pdf/styles.ts |
362 |
Shared PDF stylesheet |
components/admin/PatientPicker.tsx |
150 |
Patient multi-select |
components/admin/TenantMultiSelect.tsx |
142 |
Tenant multi-select |
Auth Refactor (Logout Bug Fix)
| File |
Δ |
What changed |
components/AuthStateHandler.tsx |
+29 |
Reworked logout/login auth-state handling |
lib/stores/auth.ts |
+56 |
Auth Zustand store updates |
lib/utils/cookie.ts |
48 (new) |
Cookie helpers used by logout |
lib/utils/routes.ts |
42 (new) |
Route helpers shared by header/login |
lib/api/httpClient.ts |
+28 |
Auth-aware request helper |
components/Header.tsx, header/AuthSection.tsx, header/LogoBrand.tsx, header/MobileMenu.tsx, pages/login.tsx |
small |
Wire-up |
Migration Notes
- The bcrypt → SHA-256 invite-token migration invalidates all pre-2026-05-14 invite tokens. Welcome and confirm pages display
invalidLinkMigrationMessage / invalidQRMigrationMessage strings that ask patients to request a new link from their therapist. Therapists can re-issue invites from the new Re-onboard patient flow on mobile, or via the existing resend endpoints on web.
- The personalized video storage naming change is forward-only — existing Cloudflare assets keep their old names. Only new uploads use the new region/env/tenant-scoped paths.
usePatientsSummary falls back gracefully when the allActivePatientsDashboard feature flag is off: the "All patients" tab is hidden and the picker only loads the doctor's own caseload.