improvement: QRcode and shared link added to cases inorder to make it possible for staff users to share a case info with other staffs or other clinics.

This commit is contained in:
2026-07-14 21:07:05 +03:30
parent 953e609fb8
commit 08df2f71ea
41 changed files with 1535 additions and 83 deletions

View File

@@ -33,3 +33,7 @@ Treatment-type colors and labels: `components/shared/treatmentTypeDisplay.ts` +
## Today dashboard
CLINIC + LAB KPIs/charts in `modules/today/today.service.ts`. Deep links: `components/today/today-deep-links.ts`. Task KPIs need `TAB_TASKS_READ` (no owner bypass). Skill: `.cursor/skills/today-dashboard/SKILL.md`.
## Lab case share link
QR + URL for **sent** cases; focus page `/lab-case/[token]`. Auth redirect via `postAuthRedirect.ts`. Skill: `.cursor/skills/lab-case-share-link/SKILL.md`.

View File

@@ -0,0 +1,18 @@
---
description: Lab case QR share link — token, access API, focus page, auth redirect
globs: frontend/src/app/**/lab-case/**,frontend/src/components/ui/lab/CaseTasksFocusView.tsx,frontend/src/components/ui/lab/LabCaseShareQr*.tsx,frontend/src/lib/api/lab-case-access.ts,frontend/src/lib/auth/postAuthRedirect.ts,frontend/src/app/**/login/page.tsx,backend/src/modules/cases/lab-case-access.*,backend/src/common/lab-case-access-token.ts
alwaysApply: false
---
# Lab case share link
- **Token:** `LabCase.accessToken` on first ship; `shareUrl` on case detail only when sent.
- **QR:** client-side `react-qr-code` in frontend — ❌ no backend QR endpoint.
- **Cases panel:** attachment preview left, QR thumb right, one row; dialog for QR + copy link.
- **Route:** `/lab-case/[token]` → `CaseTasksFocusView` (dashboard layout, auth required).
- **Access:** lab (`TAB_TASKS_*`) or clinic treatment **provider** (`TAB_TREATMENT_EDIT` + `isActorTreatmentProvider`); else `LAB_CASE_ACCESS_DENIED`.
- **Task status on link page:** same assignee rule as Tasks — `canEditLabTaskStatus`; backend `PATCH /tasks/:id` enforces assignee.
- **Auth redirect:** `postAuthRedirect.ts`; dashboard stores path on logout redirect; login consumes **once** after org ready — ❌ do not consume in `useAuth.login()`.
- **Login page:** wrap `useSearchParams` in `<Suspense>` for `next build`.
Skill: `.cursor/skills/lab-case-share-link/SKILL.md`

View File

@@ -1,6 +1,6 @@
---
description: Lab Cases tab — prosthesis filter, auto-select, list cards
globs: frontend/src/components/ui/lab/CasesPage.tsx,frontend/src/components/ui/lab/CaseDetailPanel.tsx,frontend/src/components/ui/lab/LabCaseProsthesisGroupsList.tsx,frontend/src/components/lab/caseDetailUtils.ts,backend/src/modules/cases/**
globs: frontend/src/components/ui/lab/CasesPage.tsx,frontend/src/components/ui/lab/CaseDetailPanel.tsx,frontend/src/components/ui/lab/LabCaseProsthesisGroupsList.tsx,frontend/src/components/ui/lab/LabCaseShareQr*.tsx,frontend/src/components/lab/caseDetailUtils.ts,backend/src/modules/cases/**
alwaysApply: false
---
@@ -10,5 +10,6 @@ alwaysApply: false
- **Auto-select** newest case on tab open; right panel never empty when list has items; `?caseId=` deep link overrides.
- **List cards:** `LabCaseProsthesisGroupsList` (catalog color + teeth); same component as Treatment shipments rail; no patient mobile on card.
- **Assignment** in detail only (`TAB_CASES_EDIT`); task status changes on Tasks tab.
- **Share link:** QR + URL when case is sent; token API + focus page — see `.cursor/skills/lab-case-share-link/SKILL.md`.
Skill: `.cursor/skills/lab-cases/SKILL.md`

View File

@@ -11,6 +11,8 @@ alwaysApply: false
- **Prosthesis colors:** `PROSTHESIS_TYPE_COLORS` + `prosthesisTypeBadgeStyleFromCatalog` — never row index.
- **Important first:** `pinImportant=true` (sort pin, not filter).
- **Task assignment:** assign in Cases (`TAB_CASES_EDIT`); status edit on Tasks only for assignee or unassigned tasks; others see “Assigned to {name}”.
- **Grouped comments:** when `sortBy=date`, one comments icon on **case header** (not per row); flat sort keeps per-row comments.
- **Share link page** (`/lab-case/[token]`): reuses `TaskRow` + assignee rules; comments via token API — see `.cursor/skills/lab-case-share-link/SKILL.md`.
- **Case due dates:** clinic sets in Treatment lab dispatch; lab sees on Cases/Tasks; `overdue` filter + `sortBy=dueDate` on Tasks.
- **Mobile UX:** `LAB_TASK_STATUS_SELECT_CLASS` (44px tap target on small screens); `TaskCaseGroupHeader` sticky while scrolling grouped tasks; filter selects use same touch sizing on Tasks.
- **Show in case:** `GET /tasks/locate-page` finds page in full list; highlight + scroll.

View File

@@ -0,0 +1,74 @@
---
name: dyolink-lab-case-share-link
description: 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.service` sets `accessToken` + `sentAt` in the same update.
- **Backfill:** `LabCaseAccessService.ensureAccessToken()` for older sent cases when building case detail `shareUrl`.
- **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`).
1. Logged-out user hits `/lab-case/{token}` → dashboard layout stores path + `router.replace('/login?from=…')`.
2. Login page `useSearchParams` (inside **Suspense**) calls `storeAuthRedirectFromPath(from)`.
3. After login + org ready: **one** `consumeAuthRedirect()` on login page (wait for `!isLoading` and org selected).
4. **Do not** `consumeAuthRedirect()` inside `useAuth.login()` — double consume sends user to `/today`.
5. 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 strings
- `errors.LAB_CASE_ACCESS_DENIED` — all three locales
## Verify
- Backend: `npm run build`; apply migration for `accessToken`.
- Frontend: `npx tsc --noEmit`; `next build` (login page Suspense for `useSearchParams`).

View File

@@ -1,6 +1,6 @@
---
name: dyolink-lab-cases
description: Lab Cases tab — list, filters, detail panel, assignment, card UX. Use when changing CasesPage, cases API, or case list cards.
description: Lab Cases tab — list, filters, detail panel, assignment, share QR, card UX. Use when changing CasesPage, cases API, CaseDetailPanel, or case list cards.
---
# Lab Cases tab
@@ -36,6 +36,7 @@ List item shape: `prosthesisGroups: { prosthesisTypeCode, teeth[] }[]` from task
- Task assignment: `PATCH /cases/:caseId/tasks/:taskId/assign` (`TAB_CASES_EDIT`)
- Comments: shared `LabCaseCommentsPanel` + `tasksApi` comment routes
- Mark read: `POST /notifications/mark-case-read` on select (Cases tab badge)
- **Share link (sent cases):** `shareUrl` on detail; attachment preview left + QR thumb right; `LabCaseShareQrDialog` (`react-qr-code`). Full flow: `.cursor/skills/lab-case-share-link/SKILL.md`.
## Permissions

View File

@@ -26,6 +26,8 @@ Other sorts use flat list on the frontend; `stepOrder asc` is still a tiebreaker
Components: `TaskCaseGroupHeader`, `TaskProsthesisGroupHeader`, `TaskRow`.
**Grouped comments (`sortBy=date`):** single comments button on `TaskCaseGroupHeader`; panel expands below header (`expandedCommentsCaseId`). Per-task comments button only in **flat** sort (`showCommentsButton={flatMode}`).
## Prosthesis colors
- Map: [`catalog-type-colors.ts`](frontend/src/components/shared/catalog-type-colors.ts) → `PROSTHESIS_TYPE_COLORS` (one hex per catalog code).
@@ -48,7 +50,7 @@ Components: `TaskCaseGroupHeader`, `TaskProsthesisGroupHeader`, `TaskRow`.
**Task assignment:** Managed in **Cases** (`TAB_CASES_EDIT`), not on Tasks tab. `PATCH /cases/:caseId/tasks/:taskId/assign`; assignable staff via `GET /cases/assignable-staff` (members with `TAB_TASKS_EDIT`, including participating owner). Case detail task row: step label, status badge, assign dropdown, and last-updated line on one compact row.
**Tasks visibility & status edit:** All tasks remain visible to every user with task access (no hiding assigned tasks). **Unassigned** tasks or tasks **assigned to you** → status dropdown when `TAB_TASKS_EDIT`. **Assigned to someone else** → read-only “Assigned to {name}” badge instead of the dropdown (backend rejects status PATCH). Managers assign/monitor in Cases.
**Tasks visibility & status edit:** All tasks remain visible to every user with task access (no hiding assigned tasks). **Unassigned** tasks or tasks **assigned to you** → status dropdown when `TAB_TASKS_EDIT`. **Assigned to someone else** → read-only “Assigned to {name}” badge instead of the dropdown (backend rejects status PATCH). Same rules on **lab case share link** page (`CaseTasksFocusView` + `canEditLabTaskStatus`). Managers assign/monitor in Cases.
**Step completed filter:** Restricts to prosthesis groups `(labCaseId, treatmentDetailId, prosthesisTypeCode)` where that `workflowStepCode` task is `COMPLETED`. Combined with `status=IN_PROGRESS`, returns only in-progress tasks in those groups (completed step row hidden).