From 2ad572f4c837492afc693cbdbdf9d47e8676bfef Mon Sep 17 00:00:00 2001 From: Admin Date: Mon, 13 Jul 2026 17:44:44 +0330 Subject: [PATCH] improvement: notify counter badge added to treatment and tasks tabs for upadted and edited cases. --- .cursor/rules/lab-notifications.mdc | 14 + .cursor/skills/lab-notifications/SKILL.md | 56 +++ .cursor/skills/lab-tasks/SKILL.md | 4 + AGENTS.md | 3 +- .../migration.sql | 59 ++++ backend/prisma/schema.prisma | 57 +++ backend/src/app.module.ts | 2 + backend/src/common/lab-case-activity.ts | 20 ++ backend/src/modules/cases/cases.module.ts | 3 +- backend/src/modules/cases/cases.service.ts | 28 +- .../lab-case-comments.module.ts | 2 + .../lab-case-comments.service.ts | 29 +- .../notifications/dto/notifications.dto.ts | 12 + .../lab-case-activity.service.ts | 331 ++++++++++++++++++ .../notifications/notifications.controller.ts | 53 +++ .../notifications/notifications.module.ts | 10 + backend/src/modules/tasks/tasks.module.ts | 3 +- backend/src/modules/tasks/tasks.service.ts | 16 +- .../modules/treatments/treatments.module.ts | 3 +- .../modules/treatments/treatments.service.ts | 16 +- frontend/messages/en.json | 1 + frontend/messages/fa.json | 1 + frontend/messages/nl.json | 1 + frontend/src/components/ui/lab/CasesPage.tsx | 44 ++- frontend/src/components/ui/lab/TaskRow.tsx | 2 + frontend/src/components/ui/lab/TasksPage.tsx | 4 + .../src/components/ui/shared/NavBadgePill.tsx | 17 + frontend/src/components/ui/shared/Sidebar.tsx | 20 +- .../ui/treatment/TreatmentWorkspace.tsx | 17 + frontend/src/lib/api/notifications.ts | 19 + frontend/src/lib/hooks/useTabBadgeCounts.ts | 60 ++++ frontend/src/lib/tabBadgeUtils.ts | 31 ++ frontend/src/types/cases.ts | 1 + 33 files changed, 908 insertions(+), 31 deletions(-) create mode 100644 .cursor/rules/lab-notifications.mdc create mode 100644 .cursor/skills/lab-notifications/SKILL.md create mode 100644 backend/prisma/migrations/20260713160000_lab_case_activity/migration.sql create mode 100644 backend/src/common/lab-case-activity.ts create mode 100644 backend/src/modules/notifications/dto/notifications.dto.ts create mode 100644 backend/src/modules/notifications/lab-case-activity.service.ts create mode 100644 backend/src/modules/notifications/notifications.controller.ts create mode 100644 backend/src/modules/notifications/notifications.module.ts create mode 100644 frontend/src/components/ui/shared/NavBadgePill.tsx create mode 100644 frontend/src/lib/api/notifications.ts create mode 100644 frontend/src/lib/hooks/useTabBadgeCounts.ts create mode 100644 frontend/src/lib/tabBadgeUtils.ts diff --git a/.cursor/rules/lab-notifications.mdc b/.cursor/rules/lab-notifications.mdc new file mode 100644 index 0000000..065781d --- /dev/null +++ b/.cursor/rules/lab-notifications.mdc @@ -0,0 +1,14 @@ +--- +description: Lab tab badges — activity model, tab-counts API, read cursors +globs: backend/src/modules/notifications/**,backend/src/common/lab-case-activity.ts,frontend/src/lib/hooks/useTabBadgeCounts.ts,frontend/src/lib/tabBadgeUtils.ts,frontend/src/lib/api/notifications.ts,frontend/src/components/ui/shared/NavBadgePill.tsx,frontend/src/components/ui/shared/Sidebar.tsx +alwaysApply: false +--- + +# Lab tab badges + +- **Split counts (Option B):** Lab Cases = sent + clinic comments + important; Lab Tasks = completions + lab comments; Clinic Treatment = visible lab comments + completions. +- **API:** `GET /notifications/tab-counts`; Tasks/Treatment mark read on tab visit; Cases uses per-case read + `hasUnread` on list cards. +- **Pattern:** `useTabBadgeCounts` + `notifyTabBadgesChanged()` — same shape as `usePendingConnectionsCount`. +- **Orgs connections badge** stays on separate `pending-count` endpoint. + +Full map: `.cursor/skills/lab-notifications/SKILL.md` diff --git a/.cursor/skills/lab-notifications/SKILL.md b/.cursor/skills/lab-notifications/SKILL.md new file mode 100644 index 0000000..6bd84b0 --- /dev/null +++ b/.cursor/skills/lab-notifications/SKILL.md @@ -0,0 +1,56 @@ +--- +name: dyolink-lab-notifications +description: Lab case activity feed + sidebar tab badge counts. Use when changing notifications API, LabCaseActivity, read state, or Sidebar badges for Cases/Tasks/Treatment. +--- + +# Lab notifications (tab badges) + +Backend: [`backend/src/modules/notifications/`](backend/src/modules/notifications/) +Activity types: [`backend/src/common/lab-case-activity.ts`](backend/src/common/lab-case-activity.ts) +Frontend hook: [`frontend/src/lib/hooks/useTabBadgeCounts.ts`](frontend/src/lib/hooks/useTabBadgeCounts.ts) + +## Models + +- **`LabCaseActivity`** — append-only events: `CASE_SENT`, `CLINIC_COMMENT`, `LAB_COMMENT`, `CASE_IMPORTANT`, `CASE_AMENDED` (stub for Step 7), `TASK_COMPLETED` +- **`LabCaseUserTabReadState`** — per user/org/tab cursor (`TASKS` | `TREATMENT`) for sidebar badge clearing on tab visit. **Cases tab** uses per-case read instead (see below). +- **`LabCaseUserReadState`** — per user/org/labCase cursor; drives Cases tab count and `hasUnread` on case list cards + +## Tab badge buckets (Option B — split lab counts) + +| Org | Tab | Activity types | +|-----|-----|----------------| +| LAB | Cases | `CASE_SENT`, `CLINIC_COMMENT`, `CASE_IMPORTANT` | +| LAB | Tasks | `TASK_COMPLETED`, `LAB_COMMENT` | +| CLINIC | Treatment | `LAB_COMMENT` (only `visibleToClinic`), `TASK_COMPLETED` | + +Counts exclude events where `actorUserId === current user`. Clinic `LAB_COMMENT` counts only when `payload.visibleToClinic === true`. + +## APIs + +- `GET /notifications/tab-counts` → `{ cases?, tasks?, treatment? }` — **Cases** count = number of cases with unread Cases-bucket activity (per-case read cursor) +- `POST /notifications/mark-tab-read` `{ tab }` — Tasks + Treatment only (Cases skips tab-level clear) +- `POST /notifications/mark-case-read` `{ labCaseId }` — opening a case clears that case’s unread dot and updates Cases tab count + +## Emit activity from + +| Event | Service | +|-------|---------| +| First send | `treatments.service` `sendLabCase` → `CASE_SENT` | +| Comment | `lab-case-comments.service` → `CLINIC_COMMENT` / `LAB_COMMENT` | +| Mark important | `cases.service` `updateImportant` (only when set true) → `CASE_IMPORTANT` | +| Task completed | `tasks.service` `updateStatus` → `TASK_COMPLETED` | + +After mutations, frontend calls `notifyTabBadgesChanged()` (window event). + +## Frontend pattern (same as org connections) + +- `useTabBadgeCounts()` — fetch on pathname change + `tab-badges-changed` event +- `useMarkTabReadOnVisit()` — Tasks + Treatment pages only (Cases badge clears when opening unread cases) +- `NavBadgePill` in [`Sidebar.tsx`](frontend/src/components/ui/shared/Sidebar.tsx) +- **Organizations** pending connections still use `usePendingConnectionsCount` (separate pending-state API) + +## Out of scope (later steps) + +- Push / email / websockets +- Activity feed UI (Step 6) +- `CASE_AMENDED` emit (Step 7) diff --git a/.cursor/skills/lab-tasks/SKILL.md b/.cursor/skills/lab-tasks/SKILL.md index ac984cc..d9db181 100644 --- a/.cursor/skills/lab-tasks/SKILL.md +++ b/.cursor/skills/lab-tasks/SKILL.md @@ -86,6 +86,10 @@ Keep changes minimal — match existing `sm:` breakpoint patterns elsewhere in t - **Tasks filters:** filter `