diff --git a/.cursor/rules/lab-tasks.mdc b/.cursor/rules/lab-tasks.mdc index af5e113..4b0e437 100644 --- a/.cursor/rules/lab-tasks.mdc +++ b/.cursor/rules/lab-tasks.mdc @@ -1,6 +1,6 @@ --- description: Lab Tasks tab — sort, grouping, filters, prosthesis colors -globs: frontend/src/components/ui/lab/TasksPage.tsx,frontend/src/components/ui/lab/Task*.tsx,frontend/src/components/ui/lab/Case*.tsx,frontend/src/components/ui/treatment/LabCasesDispatchPanel.tsx,frontend/src/components/lab/taskListGrouping.ts,frontend/src/components/lab/labCaseDueDateDisplay.ts,frontend/src/components/treatment/prosthesisTypeDisplay.ts,frontend/src/components/shared/catalog-type-colors.ts,backend/src/modules/tasks/**,backend/src/common/lab-case-due-date.ts,backend/src/modules/treatments/** +globs: frontend/src/components/ui/lab/TasksPage.tsx,frontend/src/components/ui/lab/Task*.tsx,frontend/src/components/ui/lab/Case*.tsx,frontend/src/components/ui/treatment/LabCasesDispatchPanel.tsx,frontend/src/components/lab/taskListGrouping.ts,frontend/src/components/lab/labCaseDueDateDisplay.ts,frontend/src/components/shared/formSelectStyles.ts,frontend/src/components/treatment/prosthesisTypeDisplay.ts,frontend/src/components/shared/catalog-type-colors.ts,backend/src/modules/tasks/**,backend/src/common/lab-case-due-date.ts,backend/src/modules/treatments/** alwaysApply: false --- @@ -12,6 +12,7 @@ alwaysApply: false - **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}”. - **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. Full map: `.cursor/skills/lab-tasks/SKILL.md` diff --git a/.cursor/skills/lab-tasks/SKILL.md b/.cursor/skills/lab-tasks/SKILL.md index 7908bb3..ac984cc 100644 --- a/.cursor/skills/lab-tasks/SKILL.md +++ b/.cursor/skills/lab-tasks/SKILL.md @@ -75,7 +75,16 @@ List items include `caseSentAt`, `caseDueDate`, `isCaseOverdue`, `assignee`, `as - **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`. +- **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`](frontend/src/components/shared/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 `
` scroll. +- **Tasks filters:** filter ` onStatusUpdate(task.id, e.target.value as LabTaskStatus)} + className={LAB_TASK_STATUS_SELECT_CLASS} + style={labTaskStatusSelectStyle(task.status)} + > + {statusOptions.map((opt) => ( + + ))} + + ) : assignedToOther && !exiting ? ( + + {t('assignedToStaff', { name: task.assignee!.name })} + + ) : ( + + {statusOptions.find((opt) => opt.value === task.status)?.label ?? task.status} + + ); + return (
  • @@ -127,68 +178,25 @@ export function TaskRow({

    -
    - {canEditStatus && !exiting ? ( - - ) : assignedToOther && !exiting ? ( - - {t('assignedToStaff', { name: task.assignee!.name })} - - ) : ( - - {statusOptions.find((opt) => opt.value === task.status)?.label ?? task.status} - - )} +
    +
    {statusControl}
    + {commentsButton}
    -
    - {flatMode && onShowInCase && !exiting ? ( - - ) : null} - {canEdit && !exiting ? ( - - ) : null} - {flatMode ? ( + {flatMode ? ( +
    + {onShowInCase && !exiting ? ( + + ) : null} {task.prosthesisTypeLabel} - ) : null} -
    +
    + ) : null}
    {commentsOpen && canEdit && !exiting ? ( diff --git a/frontend/src/components/ui/lab/TasksPage.tsx b/frontend/src/components/ui/lab/TasksPage.tsx index eba00f4..d7a2044 100644 --- a/frontend/src/components/ui/lab/TasksPage.tsx +++ b/frontend/src/components/ui/lab/TasksPage.tsx @@ -282,7 +282,7 @@ export function TasksPage() { [canEdit, loadTasks, setError, showError, showSuccess, statusFilter, t, tErrors], ); - const filterSelectClass = `${FORM_SELECT_CLASS} w-full rounded-md px-2 py-1.5 text-sm`; + const filterSelectClass = `${FORM_SELECT_CLASS} w-full min-h-[44px] rounded-md px-2 py-2 text-base sm:min-h-0 sm:py-1.5 sm:text-sm`; const sortHintKey = useMemo(() => { switch (sortBy) { @@ -467,7 +467,7 @@ export function TasksPage() { ) : null} -
    +
    {(loading || locatingCase) && tasks.length === 0 ? (

    {locatingCase ? t('locatingCase') : t('loading')} diff --git a/frontend/src/components/ui/treatment/LabCasesDispatchPanel.tsx b/frontend/src/components/ui/treatment/LabCasesDispatchPanel.tsx index b3f9e72..df42ac2 100644 --- a/frontend/src/components/ui/treatment/LabCasesDispatchPanel.tsx +++ b/frontend/src/components/ui/treatment/LabCasesDispatchPanel.tsx @@ -315,7 +315,7 @@ export function LabCasesDispatchPanel({ {!detailAlreadyInShipment ? (

    {t('labDispatchEmpty')}

    ) : activeLabCase ? ( -
    +
    {renderShipmentCardHeader()} {sent ? ( <> @@ -513,6 +513,7 @@ export function LabCasesDispatchPanel({