Files
dyolink/.cursor/skills/lab-tasks/SKILL.md

6.5 KiB

name, description
name description
dyolink-lab-tasks Lab Tasks tab — list, sort, filters, case grouping, prosthesis colors, step-completed filter. Use when changing TasksPage, tasks API, or lab task list UX.

Lab Tasks

Main UI: frontend/src/components/ui/lab/TasksPage.tsx
Backend: backend/src/modules/tasks/

Default sort (backend)

sortBy=date + sortDir=desc:

  1. labCase.sentAt desc (newest case first)
  2. labCaseId, treatmentDetailId, prosthesisTypeCode asc (stable grouping)
  3. stepOrder asc (steps 1→N within prosthesis group)
  4. id asc

Other sorts use flat list on the frontend; stepOrder asc is still a tiebreaker.

Case grouping (frontend)

  • sortBy === 'date' → grouped view via taskListGrouping.ts: case header → prosthesis sub-header → task rows.
  • Other sorts → flat list; show muted hint (groupingOff* i18n keys). Each row keeps clinic/patient/teeth context.

Components: TaskCaseGroupHeader, TaskProsthesisGroupHeader, TaskRow.

Prosthesis colors

  • Map: catalog-type-colors.tsPROSTHESIS_TYPE_COLORS (one hex per catalog code).
  • Resolve with prosthesisTypeDisplay.ts — use prosthesisTypeBadgeStyleFromCatalog(code, catalog), not list row index.
  • Load catalog via prosthesisCatalogApi.list() on Tasks/Cases/Today dashboard.

Filters

Param API UI
q, clinicOrganizationId, status GET /tasks Search, clinic, status
stepCompleted GET /tasks Workflow step dropdown
pinImportant GET /tasks Important first (sort pin)
assignedToMe GET /tasks Only tasks assigned to current user
prosthesisTypeCode GET /tasks From Today prosthesis chart deep link
unassignedOnly GET /tasks Tasks with no assignee
overdue GET /tasks Cases with due date before today and at least one in-progress task
sortBy=dueDate GET /tasks Sort by LabCase.dueDate (flat list; grouping off)
Clinics + steps options GET /tasks/filter-options Populates dropdowns (not from current page)

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.

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).

  • Important first: pinImportant=true prepends important cases in sort order.
  • Assigned to me: assignedToMe=true filters to current user's assigned tasks only.
  • Overdue cases: overdue=trueLabCase.dueDate before start of UTC day and at least one task still IN_PROGRESS. Shown with error badge on Cases list/detail and task case headers.
  • Sort by due date: sortBy=dueDate — flat list (grouping off); tiebreakers match other non-date sorts.
  • Reset view: resetView restores DEFAULT_TASKS_VIEW from tasksViewDefaults.ts.
  • URL state: parseTasksSearchParams applies Today deep-link query params on mount (importantOnly, overdueOnly, unassignedOnly, prosthesisTypeCode, status, sort).
  • Show in case: flat-sort rows only; resets filters/sort, calls GET /tasks/locate-page to find the correct page in the full default-sorted list, then highlights + scrolls to the task.
  • Complete animation: when marking done under in-progress filter, row plays exit animation + success toast before refetch.

APIs

  • GET /tasks — paginated flat task list (grouping is client-side when sortBy=date)
  • PATCH /tasks/:taskId — update status (only assignee or unassigned task)
  • GET /tasks/filter-options — clinics + workflow steps (localized)
  • GET /tasks/locate-page — page number for a task in the sorted filtered list
  • GET /cases/assignable-staff — staff eligible for task assignment
  • PATCH /cases/:caseId/tasks/:taskId/assign — assign or unassign (assigneeUserId nullable)

List items include caseSentAt, caseDueDate, isCaseOverdue, assignee, assignedAt for case headers / flat rows.

Case due dates (clinic → lab)

  • Schema: LabCase.dueDate (optional DateTime).
  • Clinic set: Treatment lab dispatch panel — date input on unsent shipment (saved with draft/send); on sent cases, blur saves via PATCH /treatments/lab-cases/:labCaseId/due-date.
  • Edit lock: Clinic cannot change due date after all tasks are completed (taskProgress.completed === taskProgress.total).
  • Lab display: Cases list + detail; Tasks case group header when grouped by date.
  • Utils: backend/src/common/lab-case-due-date.ts, frontend/src/components/lab/labCaseDueDateDisplay.ts, LabCaseDueDateBadge.

Mobile UX (Tasks + Treatment dispatch)

Keep changes minimal — match existing sm: breakpoint patterns elsewhere in the app.

  • Task status control: LAB_TASK_STATUS_SELECT_CLASS in formSelectStyles.ts — full-width, min-h-[44px], text-base on mobile; compact on sm+. Read-only status / assignee badges match height on mobile.
  • Sticky case header: TaskCaseGroupHeader uses sticky top-0 z-10 + translucent background when sortBy=date (grouped view). Sticks within dashboard <main> scroll.
  • Tasks filters: filter <select>s use the same 44px mobile height as other form controls.
  • Treatment lab dispatch: shipment card p-3 sm:p-4; Send to lab is w-full sm:w-auto.

Tab badges

See .cursor/skills/lab-notifications/SKILL.md — split lab Cases/Tasks counts, clinic Treatment; useTabBadgeCounts + notifyTabBadgesChanged.

Permissions

TAB_TASKS_READ / TAB_TASKS_EDIT; LabOrgGuard on all task routes.