Skip to content

feat(platform): W7 data routers, mutation feedback, pickers and upload (#112-#115) - #161

Open
xsthar wants to merge 4 commits into
DocForum:mainfrom
xsthar:feat/w7-platform-quality-routing-feedback-pickers-upload
Open

xsthar wants to merge 4 commits into
DocForum:mainfrom
xsthar:feat/w7-platform-quality-routing-feedback-pickers-upload

Conversation

@xsthar

@xsthar xsthar commented Oct 19, 2026

Copy link
Copy Markdown

Closes #112
Closes #113
Closes #114
Closes #115

What changed and why

The W7 platform-quality track, built on top of main in one branch. No PRD §4 core-flow behaviour changes — this is shared platform work used by the patient (dependent date of birth), doctor (queue undo, insights range) and admin (audit date filters) screens.

#112 — Data routers with loaders and route-level error elements

  • src/router.tsx replaces the component tree with a createHashRouter data router (GitHub Pages # semantics kept). Every page is a lazy route module; each section has a RouteError element and the root has a RouteLoading hydration fallback.
  • Loaders prefetch React Query data with ensureQueryData using the exact keys and shapes the pages read (including infinite-query InfiniteData for stuck referrals and the wrapped TimedReadiness shape for system health — mismatches here were caught and fixed during this work).
  • RequireAuth and its test are deleted. Loader-based guards await the single-flight POST /auth/refresh restore (restoreSession() in auth-store.ts), so signed-out deep links redirect to /login and wrong-role links redirect to the user's own dashboard without a login flash. The boot refresh is attempted once; login/logout reset that latch.
  • Tests: src/router.test.tsx (restore wait, signed-out redirect, allowed role, role mismatch, loader prefetch) plus admin route tests updated to the real router.

#113 — Mutation feedback: toasts, optimistic updates, undo

  • src/store/toast-store.ts + src/components/Toast.tsx: accessible viewport (role="status" for info/success, role="alert" for errors), dismissible, auto-timeout with pause on hover/focus, optional action button.
  • src/hooks/useOptimisticMutation.ts: per-call cache snapshot, rollback on failure (including clearing an entry that did not exist before), error toast, optional refetch (invalidateOnSettle: false for read receipts).
  • src/hooks/useDeferredAction.ts: delayed-commit undo pattern; Undo cancels the request and reverts the cache, a failed commit rolls back and toasts, and an unmount before the window reverts instead of leaving a phantom change.
  • Applied as examples: message mark-read and invitation revoke (optimistic), doctor queue start/complete (deferred undo, replacing QueuePanel's local undo strip). Payment mutations are excluded, and the rule is documented in useOptimisticMutation.ts and ARCHITECTURE_ESSENTIALS.md.
  • Tests: Toast.test.tsx, useOptimisticMutation.test.tsx, useDeferredAction.test.tsx, plus the existing queue/messaging suites.

#114 — Accessible date and time pickers

  • DatePicker implements the WAI-ARIA date picker dialog pattern (grid, roving tabindex, arrows/PageUp/PageDown/Home/End, Enter/Escape, month header live region, focus trap and return). TimePicker is a listbox with the same keyboard guarantees.
  • Typed manual entry works in both: ISO and locale-ordered dates; 12-hour and 24-hour times. Min/max, arbitrary disabled dates, locale-aware labels, explicit IANA time zone hints, and 44px touch targets.
  • Replaces every native type="date" input: dependent date of birth, audit from/to, insights custom range.
  • Tests: DatePicker.test.tsx, TimePicker.test.tsx; stories: DatePicker.stories.tsx, TimePicker.stories.tsx (plain CSF, Storybook wiring is [Platform] Storybook component library with interaction and accessibility tests #97).

#115 — Shared file upload component

  • Upload supports drag-and-drop plus a file button, a separate mobile camera-capture input, per-file progress, cancel, retry and remove, with polite live-region announcements and accessible progress bars. File contents live only in component state.
  • Client-side validation sniffs magic bytes (JPEG/PNG/GIF/WebP/PDF/ZIP + text) and size before upload; downscaleImage resizes large images with a configurable quality/max dimension.
  • apiUpload in api-client.ts is the only upload path: XHR multipart with credentials: 'include', bearer token, progress and abort.
  • Tests: Upload.test.tsx, upload-utils covered through it, image-downscale.test.ts, api-client.test.ts; stories: Upload.stories.tsx.

Docs / assumptions

Verification

$ npm test
Test Files  48 passed (48)
Tests       419 passed (419)

$ npm run typecheck   # tsc -b --noEmit, clean
$ npm run build       # tsc -b && vite build, clean
$ npm run check:dist  # no mock code in production bundle (60 files scanned)

Manual review notes: screenshots were not attached because this environment has no browser available (the same disclosed gap as previous UI PRs in this repo); keyboard paths are covered by the picker/upload tests. Closes #9 is intentionally not included: this PR implements the single-flight restore behaviour #9 depended on, but the issue stays open for an end-to-end check against the real backend.

@drips-wave

drips-wave Bot commented Oct 19, 2026

Copy link
Copy Markdown

@xsthar Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@xsthar Thanks for the PR. It can't be merged yet. To unblock it:

Merge conflicts: this branch conflicts with main. Please rebase onto the latest main (git fetch upstream && git rebase upstream/main), resolve the conflicts (often ROADMAP.md, ARCHITECTURE*.md or prisma/schema.prisma), and force-push.

Push to this same branch and CI will re-run. Once it's green and conflict-free, it'll be reviewed for merge.

@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 20, 2026
DocForum#112-DocForum#115)

Data routers (DocForum#112): createHashRouter, lazy route modules, React Query loader
prefetch using the same keys/shapes pages read, loader guards that await the
single-flight POST /auth/refresh restore, per-section RouteError and a
hydration fallback; RequireAuth is gone.

Mutation feedback (DocForum#113): toast store + accessible Toaster, useOptimisticMutation
with snapshot rollback and error toasts (message mark-read, invite revoke) and
useDeferredAction for delayed-commit undo (queue start/complete). Money
movements are documented as excluded.

Pickers (DocForum#114): WAI-ARIA DatePicker/TimePicker with keyboard grid/list
navigation, typed entry, min/max, disabled dates, locale formatting, explicit
IANA time zones and 44px targets; every native date input replaced.

Upload (DocForum#115): drag-and-drop/camera Upload with per-file progress, cancel,
retry, signature-based type sniffing, size limits, image downscaling and a new
XHR apiUpload helper with credentials/progress/abort.

Docs updated (ROADMAP W7 + changelog, ARCHITECTURE_ESSENTIALS assumptions).
@xsthar
xsthar force-pushed the feat/w7-platform-quality-routing-feedback-pickers-upload branch from c88bd1a to 5dfd4d2 Compare October 23, 2026 14:45
@github-actions

Copy link
Copy Markdown

@xsthar This PR now has merge conflicts with main, most likely because #136 (feat: medication schedule, availability, verification, referrals) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-web.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

xsthar and others added 2 commits October 24, 2026 21:18
Keep the data-router architecture from DocForum#112 and port upstream's additions
into it: the flag-gated /settings/notifications route, the doctor messages
heading, TimeZoneProvider, profile bootstrap on the patient layout, and the
shared refresh() auth API.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
The extra paragraph was added to make router tests distinguishable, but it
is not part of the dashboard design and shifted the patient-dashboard visual
baseline. Assert on the existing "What needs your attention" heading instead.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@github-actions github-actions Bot added needs-rebase Has merge conflicts with main; the author needs to rebase and removed needs-rebase Has merge conflicts with main; the author needs to rebase labels Oct 24, 2026
@github-actions

Copy link
Copy Markdown

@xsthar This PR now has merge conflicts with main, most likely because #157 (feat(platform): complete W7 API client, errors, PWA, and i18n) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-web.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

Upstream landed the rest of the W7 work (DocForum#151, DocForum#157) while this branch was
open, so re-merge and keep both sides:

- App.tsx keeps the data router and adopts I18nProvider, the app-level
  ErrorBoundary and UpdatePromptContainer around RouterProvider.
- Test helpers keep the memory data router and adopt IntlProvider.
- api-client keeps upstream's transport, retry and error envelope, with
  apiUploadFile as the branch's only addition on top.
- QueuePanel keeps the shared toast undo instead of the inline undo bar,
  on top of upstream's localized labels and live-region announcements.
- PatientDashboardPage stays the layout route; its hub moves to
  PatientHomePage with upstream's translations.
- Date inputs keep DatePicker; the custom date range keeps upstream's
  labelled fieldset around them.

All 161 unit-test files pass under the merged tree; the one failure is the
pre-existing time-of-day flake in PatientDashboardPage.test.tsx, whose 26h
offset crosses two midnights when the suite runs after 22:00 local.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@github-actions github-actions Bot removed the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 27, 2026
@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@xsthar The Browser (journeys + accessibility + visual) job fails the visual regression check: the rendered page no longer matches the committed baseline:

Expected: e2e/__screenshots__/visual-mobile/patient-dashboard.png
Expected: e2e/__screenshots__/visual-mobile/consultation.png

If the visual change is intentional, regenerate those baselines in the same Linux/Playwright setup CI uses (see the visual-testing notes in e2e/) and commit them. If it isn't intentional, fix the layout. Then push.

@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 27, 2026
@github-actions

Copy link
Copy Markdown

@xsthar This PR now has merge conflicts with main, most likely because #210 (chore(changelog): fold changelog.d fragments into ROADMAP.md) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-web.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-rebase Has merge conflicts with main; the author needs to rebase

Projects

None yet

2 participants