improvement: notification feature polished. feature tabs following the same notification socket emmited data to be updated.
This commit is contained in:
@@ -12,11 +12,28 @@ Permission-free **feature** (every dashboard user sees the bell). **Cards** are
|
||||
| | Inbox (`UserNotification`) | Sidebar badges (`LabCaseActivity`) |
|
||||
|--|--|--|
|
||||
| Entry | Header bell → dropdown + `/notifications` | Sidebar Cases/Tasks/Treatment/Orgs |
|
||||
| Live | Socket.IO (`/realtime`) | REST + `tab-badges-changed` |
|
||||
| Live | Socket.IO (`/realtime`) | Same socket → `notifyTabBadgesChanged()` → REST tab-counts |
|
||||
| Read | Per-card `readAt` only | Per-case / tab cursors |
|
||||
|
||||
Do **not** clear tab badges when marking an inbox card read.
|
||||
|
||||
## Live cascade (one socket)
|
||||
|
||||
On `notification.created`, [`RealtimeProvider`](frontend/src/lib/realtime/RealtimeProvider.tsx):
|
||||
|
||||
1. Updates inbox state (bell list + unread).
|
||||
2. Calls `notifyTabBadgesChanged()` → Sidebar refetches `GET /notifications/tab-counts`.
|
||||
3. For connection-request types, also `notifyPendingConnectionsChanged()`.
|
||||
4. **Currently mounted** feature pages soft-refresh (no remount, no form wipe). Unmounted tabs do **not** fetch list data until opened:
|
||||
- **Cases** — silent list + selected detail reload
|
||||
- **Tasks** — silent task list reload
|
||||
- **Treatment** (`TreatmentWorkspace`, not thin `page.tsx`) — silent patient lab-cases + unread rail
|
||||
- **Organizations** — silent connections list on `pending-connections-changed` only
|
||||
|
||||
Sidebar **badge counts** always refetch (hook lives in the always-mounted Sidebar). Treatment **draft/form state** is not cleared by this cascade.
|
||||
|
||||
Full tab-badge map: `.cursor/skills/tab-badges/SKILL.md`.
|
||||
|
||||
## Backend
|
||||
|
||||
- Model: `UserNotification` + `UserNotificationType` in Prisma
|
||||
@@ -26,10 +43,13 @@ Do **not** clear tab badges when marking an inbox card read.
|
||||
|
||||
## Emit sites (parallel to LabCaseActivity)
|
||||
|
||||
CASE_SENT, CLINIC_COMMENT, LAB_COMMENT (+ LAB_COMMENT_CLINIC), CASE_IMPORTANT, TASK_COMPLETED, TASK_ASSIGNED, CONNECTION_REQUEST, STAFF_INVITE — see plan / service call sites.
|
||||
CASE_SENT, CLINIC_COMMENT, LAB_COMMENT (+ LAB_COMMENT_CLINIC), CASE_IMPORTANT, TASK_COMPLETED, TASK_ASSIGNED, CONNECTION_REQUEST, STAFF_INVITE — see service call sites.
|
||||
|
||||
## Frontend
|
||||
**Inbox card context** is denormalized inside `UserNotificationService.notify()` (`enrichInboxPayload`) from ids already on the payload (`labCaseId`, `taskId`, `fromOrganizationId`). Emit sites stay thin (`{ labCaseId }`, etc.). Inbox list/read does **not** join related tables. Older rows may lack these fields until new events are emitted.
|
||||
|
||||
- `RealtimeProvider` in dashboard layout
|
||||
- `NotificationBell` + `NotificationsPage` + `NotificationCard`
|
||||
**Realtime auth:** after access-token refresh (proactive, axios 401 retry, or `checkAuth`), frontend dispatches `dyolink:access-token-refreshed` so `RealtimeProvider` reconnects with the new cookie.
|
||||
|
||||
## Frontend UI
|
||||
|
||||
- `NotificationBell` + `NotificationsPage` + `NotificationCard` (full-width page list; same card height; extra context truncated on one line)
|
||||
- Deep links: `/cases?caseId=`, `/tasks?taskId=`, `/treatment?labCaseId=`, `/organizations`, `/staff`
|
||||
|
||||
Reference in New Issue
Block a user