3.8 KiB
name, description
| name | description |
|---|---|
| dyolink-lab-case-share-link | Lab case QR share link — access token, focus page, auth redirect, Cases QR UI. Use when changing share links, /lab-case/[token], lab-case-access API, or post-login redirect from share URLs. |
Lab case share link
Shipped cases get a stable access token and share URL. QR + link open a focused tasks page with comments — not a public page; JWT + org context required.
Data & token lifecycle
- Schema:
LabCase.accessToken(String?,@unique). - On first ship:
treatments.servicesetsaccessToken+sentAtin the same update. - Backfill:
LabCaseAccessService.ensureAccessToken()for older sent cases when building case detailshareUrl. - URL:
buildLabCaseShareUrl(token, locale)→{FRONTEND_URL}/{locale}/lab-case/{token}(backend/src/common/lab-case-access-token.ts).
Backend API (LabCaseAccessController)
Base path: /lab-cases/access/:token (JWT + selected org required).
| Route | Purpose |
|---|---|
GET :token |
Session metadata (access mode, permissions, patient, prosthesis groups) |
GET :token/tasks |
All case tasks (includes assignee for status rules) |
GET/POST :token/comments |
List / add comments |
PATCH :token/comments/:id/visibility |
Lab only — clinic visibility toggle |
Access resolution (lab-case-access.service.ts):
| Actor | View | Edit task status | Comments |
|---|---|---|---|
Lab + TAB_TASKS_READ/EDIT |
✅ | ✅ if TAB_TASKS_EDIT + assignee rules |
Post/toggle if TAB_TASKS_EDIT |
Clinic + TAB_TREATMENT_EDIT + treatment provider |
✅ | ❌ read-only | Post only (no visibility toggle) |
| Everyone else | ❌ LAB_CASE_ACCESS_DENIED |
Task status updates use PATCH /tasks/:id (not token routes) — same assignee rule as Tasks tab: unassigned or assigned-to-you only.
Frontend
| Piece | Path |
|---|---|
| Focus page | app/[locale]/(dashboard)/lab-case/[token]/page.tsx → CaseTasksFocusView |
| API client | lib/api/lab-case-access.ts |
| QR UI | LabCaseShareQrCode, LabCaseShareQrDialog, thumb in CaseDetailPanel |
| QR package | react-qr-code (frontend only — no backend QR generation) |
Cases detail header: attachment preview left, QR thumb right, same row (w-24 sm:w-32). QR opens dialog (large QR + URL + copy); no inline copy on panel. Only when shareUrl present (sent case).
Share focus page: grouped tasks (reuse TaskRow, TaskCaseGroupHeader); comments section via LabCaseCommentsPanel + token API adapters. Access denied → inline message (asApiError for LAB_CASE_ACCESS_DENIED).
Auth redirect (logged out → login → back)
Helpers: lib/auth/postAuthRedirect.ts (sessionStorage key authRedirect).
- Logged-out user hits
/lab-case/{token}→ dashboard layout stores path +router.replace('/login?from=…'). - Login page
useSearchParams(inside Suspense) callsstoreAuthRedirectFromPath(from). - After login + org ready: one
consumeAuthRedirect()on login page (wait for!isLoadingand org selected). - Do not
consumeAuthRedirect()insideuseAuth.login()— double consume sends user to/today. - Multi-org: redirect stays in storage until
selectOrganization()consumes it.
Tasks tab interaction
Grouped sort (sortBy=date): one comments control on case header (expandedCommentsCaseId), not per task row. Flat sort unchanged (showCommentsButton={flatMode}).
i18n
cases.*— QR dialog strings (shareQrDialogTitle,copyShareLink, …)labCaseAccess.*— focus page stringserrors.LAB_CASE_ACCESS_DENIED— all three locales
Verify
- Backend:
npm run build; apply migration foraccessToken. - Frontend:
npx tsc --noEmit;next build(login page Suspense foruseSearchParams).