improvement: users get notified whenever a task is done completely, not per step.

This commit is contained in:
2026-09-07 22:36:33 +03:30
parent e52701dba3
commit 880809fdbe
17 changed files with 79 additions and 29 deletions

View File

@@ -6,7 +6,7 @@ alwaysApply: false
# Tab badges (Cases / Tasks / Treatment) # Tab badges (Cases / Tasks / Treatment)
- **Split counts (Option B):** Lab Cases = sent + clinic comments + important; Lab Tasks = completions + lab comments + assignments (assignee-only); Clinic Treatment = visible lab comments + completions. - **Split counts (Option B):** Lab Cases = sent + clinic comments + important; Lab Tasks = case fully completed + lab comments + assignments (assignee-only); Clinic Treatment = visible lab comments + case fully completed. Per-step `TASK_COMPLETED` is timeline-only (not badges or inbox).
- **API:** `GET /notifications/tab-counts`; **Cases + Treatment** use per-case read + `hasUnread` on list cards; Tasks marks read on tab visit. Treatment rail uses `TreatmentLabCasesPanel` + `LabCaseTrackerCard` + activity feed. - **API:** `GET /notifications/tab-counts`; **Cases + Treatment** use per-case read + `hasUnread` on list cards; Tasks marks read on tab visit. Treatment rail uses `TreatmentLabCasesPanel` + `LabCaseTrackerCard` + activity feed.
- **Pattern:** `useTabBadgeCounts` + `notifyTabBadgesChanged()` — same shape as `usePendingConnectionsCount`. - **Pattern:** `useTabBadgeCounts` + `notifyTabBadgesChanged()` — same shape as `usePendingConnectionsCount`.
- **Live:** inbox Socket.IO `notification.created` → `notifyTabBadgesChanged()` (and org pending event when relevant). **Mounted** Cases/Tasks/Treatment/Orgs pages soft-refetch lists; unmounted tabs do not. Sidebar badge counts always refetch (hook is always mounted). - **Live:** inbox Socket.IO `notification.created` → `notifyTabBadgesChanged()` (and org pending event when relevant). **Mounted** Cases/Tasks/Treatment/Orgs pages soft-refetch lists; unmounted tabs do not. Sidebar badge counts always refetch (hook is always mounted).

View File

@@ -43,7 +43,7 @@ Full tab-badge map: `.cursor/skills/tab-badges/SKILL.md`.
## Emit sites (parallel to LabCaseActivity) ## Emit sites (parallel to LabCaseActivity)
CASE_SENT, CLINIC_COMMENT, LAB_COMMENT (+ LAB_COMMENT_CLINIC), CASE_IMPORTANT, TASK_COMPLETED, TASK_ASSIGNED (assignee only), CONNECTION_REQUEST, STAFF_INVITE — see service call sites. CASE_SENT, CLINIC_COMMENT, LAB_COMMENT (+ LAB_COMMENT_CLINIC), CASE_IMPORTANT, CASE_COMPLETED (all tasks in the case done — not each step), TASK_ASSIGNED (assignee only), CONNECTION_REQUEST, STAFF_INVITE — see service call sites.
**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. **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.

View File

@@ -13,7 +13,7 @@ Frontend hook: [`frontend/src/lib/hooks/useTabBadgeCounts.ts`](frontend/src/lib/
## Models ## Models
- **`LabCaseActivity`** — append-only events: `CASE_SENT`, `CLINIC_COMMENT`, `LAB_COMMENT`, `CASE_IMPORTANT`, `CASE_AMENDED` (stub for Step 7), `TASK_COMPLETED`, `TASK_ASSIGNED` - **`LabCaseActivity`** — append-only events: `CASE_SENT`, `CLINIC_COMMENT`, `LAB_COMMENT`, `CASE_IMPORTANT`, `CASE_AMENDED` (stub for Step 7), `TASK_COMPLETED` (timeline only), `TASK_ASSIGNED`, `CASE_COMPLETED`
- **`LabCaseUserTabReadState`** — per user/org/tab cursor (`TASKS`) for sidebar badge clearing on tab visit. - **`LabCaseUserTabReadState`** — per user/org/tab cursor (`TASKS`) for sidebar badge clearing on tab visit.
- **`LabCaseUserReadState`** — per user/org/labCase cursor; drives Cases tab count and `hasUnread` on case list cards - **`LabCaseUserReadState`** — per user/org/labCase cursor; drives Cases tab count and `hasUnread` on case list cards
@@ -22,8 +22,8 @@ Frontend hook: [`frontend/src/lib/hooks/useTabBadgeCounts.ts`](frontend/src/lib/
| Org | Tab | Activity types | | Org | Tab | Activity types |
|-----|-----|----------------| |-----|-----|----------------|
| LAB | Cases | `CASE_SENT`, `CLINIC_COMMENT`, `CASE_IMPORTANT` | | LAB | Cases | `CASE_SENT`, `CLINIC_COMMENT`, `CASE_IMPORTANT` |
| LAB | Tasks | `TASK_COMPLETED`, `LAB_COMMENT`, `TASK_ASSIGNED` (assignee only) | | LAB | Tasks | `CASE_COMPLETED`, `LAB_COMMENT`, `TASK_ASSIGNED` (assignee only) |
| CLINIC | Treatment | `LAB_COMMENT` (only `visibleToClinic`), `TASK_COMPLETED`**only lab cases for treatments the user provided** | | CLINIC | Treatment | `LAB_COMMENT` (only `visibleToClinic`), `CASE_COMPLETED`**only lab cases for treatments the user provided** |
Counts exclude events where `actorUserId === current user`. Clinic `LAB_COMMENT` counts only when `payload.visibleToClinic === true`. Counts exclude events where `actorUserId === current user`. Clinic `LAB_COMMENT` counts only when `payload.visibleToClinic === true`.
@@ -43,7 +43,8 @@ Counts exclude events where `actorUserId === current user`. Clinic `LAB_COMMENT`
| First send | `treatments.service` `sendLabCase``CASE_SENT` | | First send | `treatments.service` `sendLabCase``CASE_SENT` |
| Comment | `lab-case-comments.service``CLINIC_COMMENT` / `LAB_COMMENT` | | Comment | `lab-case-comments.service``CLINIC_COMMENT` / `LAB_COMMENT` |
| Mark important | `cases.service` `updateImportant` (only when set true) → `CASE_IMPORTANT` | | Mark important | `cases.service` `updateImportant` (only when set true) → `CASE_IMPORTANT` |
| Task completed | `tasks.service` `updateStatus``TASK_COMPLETED` | | Task completed (step) | `tasks.service` `updateStatus``TASK_COMPLETED` **activity only** (case timeline; not inbox or tab badges) |
| Case fully completed | `tasks.service` `updateStatus` when no in-progress tasks remain → `CASE_COMPLETED` activity + inbox |
| Task assigned | `cases.service` `assignTask``TASK_ASSIGNED` (inbox + Tasks badge for **assignee**, including self-assign) | | Task assigned | `cases.service` `assignTask``TASK_ASSIGNED` (inbox + Tasks badge for **assignee**, including self-assign) |
After mutations, frontend calls `notifyTabBadgesChanged()` (window event). After mutations, frontend calls `notifyTabBadgesChanged()` (window event).

View File

@@ -0,0 +1,8 @@
-- AlterEnum
ALTER TYPE "LabCaseActivityType" ADD VALUE 'CASE_COMPLETED';
-- AlterEnum
ALTER TYPE "UserNotificationType" ADD VALUE 'CASE_COMPLETED';
-- Step-level TASK_COMPLETED inbox rows were spam; case-complete uses CASE_COMPLETED going forward.
DELETE FROM "UserNotification" WHERE type = 'TASK_COMPLETED';

View File

@@ -492,6 +492,7 @@ enum LabCaseActivityType {
CASE_AMENDED CASE_AMENDED
TASK_COMPLETED TASK_COMPLETED
TASK_ASSIGNED TASK_ASSIGNED
CASE_COMPLETED
} }
enum LabCaseTabReadTarget { enum LabCaseTabReadTarget {
@@ -508,6 +509,7 @@ enum UserNotificationType {
CASE_IMPORTANT CASE_IMPORTANT
TASK_COMPLETED TASK_COMPLETED
TASK_ASSIGNED TASK_ASSIGNED
CASE_COMPLETED
CONNECTION_REQUEST CONNECTION_REQUEST
STAFF_INVITE STAFF_INVITE
} }

View File

@@ -7,15 +7,15 @@ export const LAB_CASES_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [
LabCaseActivityType.CASE_IMPORTANT, LabCaseActivityType.CASE_IMPORTANT,
]; ];
/** Lab Tasks tab — task completions, lab-side comments, and assignments (assignee-scoped in counts). */ /** Lab Tasks tab — case fully completed, lab-side comments, and assignments (assignee-scoped in counts). */
export const LAB_TASKS_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [ export const LAB_TASKS_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [
LabCaseActivityType.TASK_COMPLETED, LabCaseActivityType.CASE_COMPLETED,
LabCaseActivityType.LAB_COMMENT, LabCaseActivityType.LAB_COMMENT,
LabCaseActivityType.TASK_ASSIGNED, LabCaseActivityType.TASK_ASSIGNED,
]; ];
/** Clinic Treatment tab — visible lab comments and task progress. */ /** Clinic Treatment tab — visible lab comments and case fully completed. */
export const CLINIC_TREATMENT_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [ export const CLINIC_TREATMENT_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [
LabCaseActivityType.LAB_COMMENT, LabCaseActivityType.LAB_COMMENT,
LabCaseActivityType.TASK_COMPLETED, LabCaseActivityType.CASE_COMPLETED,
]; ];

View File

@@ -303,6 +303,7 @@ export class TasksService {
} }
} }
let caseCompleted = false;
if (dto.status === LabTaskStatus.COMPLETED && task.status !== LabTaskStatus.COMPLETED) { if (dto.status === LabTaskStatus.COMPLETED && task.status !== LabTaskStatus.COMPLETED) {
await this.labCaseActivity.record( await this.labCaseActivity.record(
{ {
@@ -321,18 +322,37 @@ export class TasksService {
}, },
tx, tx,
); );
const remainingIncomplete = await tx.labCaseTask.count({
where: {
labCaseId: task.labCaseId,
status: { not: LabTaskStatus.COMPLETED },
},
});
caseCompleted = remainingIncomplete === 0;
if (caseCompleted) {
await this.labCaseActivity.record(
{
labCaseId: task.labCaseId,
type: LabCaseActivityType.CASE_COMPLETED,
actorUserId,
payload: { labCaseId: task.labCaseId },
},
tx,
);
}
} }
return result; return { result, caseCompleted };
}); });
if (dto.status === LabTaskStatus.COMPLETED && task.status !== LabTaskStatus.COMPLETED) { if (updated.caseCompleted) {
void this.userNotifications.notify({ void this.userNotifications.notify({
organizationId: labOrganizationId, organizationId: labOrganizationId,
type: UserNotificationType.TASK_COMPLETED, type: UserNotificationType.CASE_COMPLETED,
href: `/tasks?taskId=${encodeURIComponent(taskId)}&labCaseId=${encodeURIComponent(task.labCaseId)}`, href: `/cases?caseId=${encodeURIComponent(task.labCaseId)}`,
actorUserId, actorUserId,
payload: { labCaseId: task.labCaseId, taskId }, payload: { labCaseId: task.labCaseId },
requiredPermission: 'TAB_TASKS_READ', requiredPermission: 'TAB_TASKS_READ',
}); });
@@ -340,10 +360,10 @@ export class TasksService {
if (clinicOrgId) { if (clinicOrgId) {
void this.userNotifications.notify({ void this.userNotifications.notify({
organizationId: clinicOrgId, organizationId: clinicOrgId,
type: UserNotificationType.TASK_COMPLETED, type: UserNotificationType.CASE_COMPLETED,
href: `/treatment?labCaseId=${encodeURIComponent(task.labCaseId)}`, href: `/treatment?labCaseId=${encodeURIComponent(task.labCaseId)}`,
actorUserId, actorUserId,
payload: { labCaseId: task.labCaseId, taskId }, payload: { labCaseId: task.labCaseId },
requiredPermission: 'TAB_TREATMENT_READ', requiredPermission: 'TAB_TREATMENT_READ',
labCaseIdForProviderScope: task.labCaseId, labCaseIdForProviderScope: task.labCaseId,
}); });
@@ -353,11 +373,11 @@ export class TasksService {
const locale = normalizeCatalogLocale(localeInput); const locale = normalizeCatalogLocale(localeInput);
const prosthesisLabels = await this.catalogLabels.resolveLabels( const prosthesisLabels = await this.catalogLabels.resolveLabels(
CatalogEntityKind.PROSTHESIS_TYPE, CatalogEntityKind.PROSTHESIS_TYPE,
atomicProsthesisCodes([updated.prosthesisTypeCode]), atomicProsthesisCodes([updated.result.prosthesisTypeCode]),
locale, locale,
); );
return { success: true, data: this.mapTaskListItem(updated, prosthesisLabels) }; return { success: true, data: this.mapTaskListItem(updated.result, prosthesisLabels) };
} }
async listFilterOptions( async listFilterOptions(

View File

@@ -846,6 +846,7 @@
"activityTaskCompleted": "{step} completed by {actor} · {date}", "activityTaskCompleted": "{step} completed by {actor} · {date}",
"activityTaskAssigned": "{step} assigned by {actor} · {date}", "activityTaskAssigned": "{step} assigned by {actor} · {date}",
"activityCaseImportant": "Marked important by {actor} · {date}", "activityCaseImportant": "Marked important by {actor} · {date}",
"activityCaseCompleted": "All lab work completed by {actor} · {date}",
"activityCaseAmended": "Case updated by {actor} · {date}", "activityCaseAmended": "Case updated by {actor} · {date}",
"activityGeneric": "Update · {date}", "activityGeneric": "Update · {date}",
"loadingHistory": "Loading history…", "loadingHistory": "Loading history…",
@@ -1105,6 +1106,7 @@
"typeCaseImportant": "Case marked as important", "typeCaseImportant": "Case marked as important",
"typeTaskCompleted": "Lab task completed", "typeTaskCompleted": "Lab task completed",
"typeTaskAssigned": "A task was assigned to you", "typeTaskAssigned": "A task was assigned to you",
"typeCaseCompleted": "Lab case completed",
"typeConnectionRequest": "New organization connection request", "typeConnectionRequest": "New organization connection request",
"typeStaffInvite": "Staff invitation created", "typeStaffInvite": "Staff invitation created",
"typeUnknown": "Notification", "typeUnknown": "Notification",

View File

@@ -847,6 +847,7 @@
"activityTaskCompleted": "{step} توسط {actor} تکمیل شد · {date}", "activityTaskCompleted": "{step} توسط {actor} تکمیل شد · {date}",
"activityTaskAssigned": "{step} توسط {actor} اختصاص داده شد · {date}", "activityTaskAssigned": "{step} توسط {actor} اختصاص داده شد · {date}",
"activityCaseImportant": "مهم علامت‌گذاری شد توسط {actor} · {date}", "activityCaseImportant": "مهم علامت‌گذاری شد توسط {actor} · {date}",
"activityCaseCompleted": "تمام کارهای لابراتوار توسط {actor} تکمیل شد · {date}",
"activityCaseAmended": "پرونده به‌روزرسانی شد توسط {actor} · {date}", "activityCaseAmended": "پرونده به‌روزرسانی شد توسط {actor} · {date}",
"activityGeneric": "به‌روزرسانی · {date}", "activityGeneric": "به‌روزرسانی · {date}",
"loadingHistory": "در حال بارگذاری تاریخچه...", "loadingHistory": "در حال بارگذاری تاریخچه...",
@@ -1106,6 +1107,7 @@
"typeCaseImportant": "پرونده به‌عنوان مهم علامت خورد", "typeCaseImportant": "پرونده به‌عنوان مهم علامت خورد",
"typeTaskCompleted": "وظیفه لابراتوار تکمیل شد", "typeTaskCompleted": "وظیفه لابراتوار تکمیل شد",
"typeTaskAssigned": "یک وظیفه به شما اختصاص داده شد", "typeTaskAssigned": "یک وظیفه به شما اختصاص داده شد",
"typeCaseCompleted": "پرونده لابراتوار تکمیل شد",
"typeConnectionRequest": "درخواست اتصال سازمان جدید", "typeConnectionRequest": "درخواست اتصال سازمان جدید",
"typeStaffInvite": "دعوتنامه کارکنان ایجاد شد", "typeStaffInvite": "دعوتنامه کارکنان ایجاد شد",
"typeUnknown": "اعلان", "typeUnknown": "اعلان",

View File

@@ -846,6 +846,7 @@
"activityTaskCompleted": "{step} voltooid door {actor} · {date}", "activityTaskCompleted": "{step} voltooid door {actor} · {date}",
"activityTaskAssigned": "{step} toegewezen door {actor} · {date}", "activityTaskAssigned": "{step} toegewezen door {actor} · {date}",
"activityCaseImportant": "Als belangrijk gemarkeerd door {actor} · {date}", "activityCaseImportant": "Als belangrijk gemarkeerd door {actor} · {date}",
"activityCaseCompleted": "Al het labwerk voltooid door {actor} · {date}",
"activityCaseAmended": "Case bijgewerkt door {actor} · {date}", "activityCaseAmended": "Case bijgewerkt door {actor} · {date}",
"activityGeneric": "Update · {date}", "activityGeneric": "Update · {date}",
"loadingHistory": "Geschiedenis laden...", "loadingHistory": "Geschiedenis laden...",
@@ -1105,6 +1106,7 @@
"typeCaseImportant": "Case gemarkeerd als belangrijk", "typeCaseImportant": "Case gemarkeerd als belangrijk",
"typeTaskCompleted": "Labtaak voltooid", "typeTaskCompleted": "Labtaak voltooid",
"typeTaskAssigned": "Er is een taak aan u toegewezen", "typeTaskAssigned": "Er is een taak aan u toegewezen",
"typeCaseCompleted": "Labcase voltooid",
"typeConnectionRequest": "Nieuw organisatieverzoek", "typeConnectionRequest": "Nieuw organisatieverzoek",
"typeStaffInvite": "Personeelsuitnodiging aangemaakt", "typeStaffInvite": "Personeelsuitnodiging aangemaakt",
"typeUnknown": "Melding", "typeUnknown": "Melding",

View File

@@ -54,7 +54,7 @@ export default async function LocaleLayout({
setRequestLocale(locale); setRequestLocale(locale);
const messages = await getMessages(); const messages = await getMessages();
const themeInit = `(function(){try{var k=${JSON.stringify(THEME_STORAGE_KEY)};var t=localStorage.getItem(k);document.documentElement.setAttribute('data-theme',t==='light'||t==='dark'?t:'dark');}catch(e){document.documentElement.setAttribute('data-theme','dark');}})();`; const themeInit = `(function(){try{var k=${JSON.stringify(THEME_STORAGE_KEY)};var t=localStorage.getItem(k);document.documentElement.setAttribute('data-theme',t==='light'||t==='dark'?t:'light');}catch(e){document.documentElement.setAttribute('data-theme','light');}})();`;
const dir = isRtlLocale(locale) ? 'rtl' : 'ltr'; const dir = isRtlLocale(locale) ? 'rtl' : 'ltr';
const fontSans = isRtlLocale(locale) const fontSans = isRtlLocale(locale)
? 'var(--font-vazirmatn), var(--font-noto-sans-arabic), system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif' ? 'var(--font-vazirmatn), var(--font-noto-sans-arabic), system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif'
@@ -65,6 +65,7 @@ export default async function LocaleLayout({
lang={localeHtmlLang(locale)} lang={localeHtmlLang(locale)}
dir={dir} dir={dir}
data-locale={locale} data-locale={locale}
data-theme="light"
className={`${vazirmatn.variable} ${notoSansArabic.variable}`} className={`${vazirmatn.variable} ${notoSansArabic.variable}`}
style={{ ['--font-sans' as never]: fontSans }} style={{ ['--font-sans' as never]: fontSans }}
suppressHydrationWarning suppressHydrationWarning

View File

@@ -13,6 +13,7 @@ const TYPE_I18N: Record<UserNotificationType, string> = {
CASE_IMPORTANT: 'typeCaseImportant', CASE_IMPORTANT: 'typeCaseImportant',
TASK_COMPLETED: 'typeTaskCompleted', TASK_COMPLETED: 'typeTaskCompleted',
TASK_ASSIGNED: 'typeTaskAssigned', TASK_ASSIGNED: 'typeTaskAssigned',
CASE_COMPLETED: 'typeCaseCompleted',
CONNECTION_REQUEST: 'typeConnectionRequest', CONNECTION_REQUEST: 'typeConnectionRequest',
STAFF_INVITE: 'typeStaffInvite', STAFF_INVITE: 'typeStaffInvite',
}; };
@@ -74,6 +75,12 @@ export function notificationContextLine(
if (clinicName) parts.push(clinicName); if (clinicName) parts.push(clinicName);
if (prosthesisLabel) parts.push(prosthesisLabel); if (prosthesisLabel) parts.push(prosthesisLabel);
break; break;
case 'CASE_COMPLETED':
if (patientName) parts.push(patientName);
if (clinicName) parts.push(clinicName);
else if (labName) parts.push(labName);
if (prosthesisLabel) parts.push(prosthesisLabel);
break;
case 'LAB_COMMENT_CLINIC': case 'LAB_COMMENT_CLINIC':
if (patientName) parts.push(patientName); if (patientName) parts.push(patientName);
if (labName) parts.push(labName); if (labName) parts.push(labName);

View File

@@ -43,6 +43,8 @@ export function formatLabCaseActivityLine(
}); });
case 'CASE_IMPORTANT': case 'CASE_IMPORTANT':
return t('activityCaseImportant', { actor, date }); return t('activityCaseImportant', { actor, date });
case 'CASE_COMPLETED':
return t('activityCaseCompleted', { actor, date });
case 'CASE_AMENDED': case 'CASE_AMENDED':
return t('activityCaseAmended', { actor, date }); return t('activityCaseAmended', { actor, date });
default: default:

View File

@@ -3,14 +3,14 @@ export const THEME_STORAGE_KEY = 'dyolink-theme';
export type ThemeMode = 'light' | 'dark'; export type ThemeMode = 'light' | 'dark';
export function getStoredTheme(): ThemeMode { export function getStoredTheme(): ThemeMode {
if (typeof window === 'undefined') return 'dark'; if (typeof window === 'undefined') return 'light';
try { try {
const v = localStorage.getItem(THEME_STORAGE_KEY); const v = localStorage.getItem(THEME_STORAGE_KEY);
if (v === 'light' || v === 'dark') return v; if (v === 'light' || v === 'dark') return v;
} catch { } catch {
/* ignore */ /* ignore */
} }
return 'dark'; return 'light';
} }
export function applyTheme(mode: ThemeMode) { export function applyTheme(mode: ThemeMode) {

View File

@@ -262,13 +262,17 @@ body {
} }
html { html {
color-scheme: dark; color-scheme: light;
} }
html[data-theme='light'] { html[data-theme='light'] {
color-scheme: light; color-scheme: light;
} }
html[data-theme='dark'] {
color-scheme: dark;
}
/* Minimal RTL layer — refine incrementally. */ /* Minimal RTL layer — refine incrementally. */
html[dir='rtl'] body { html[dir='rtl'] body {
direction: rtl; direction: rtl;
@@ -338,9 +342,7 @@ select option {
} }
:root[data-theme='dark'] select.form-select, :root[data-theme='dark'] select.form-select,
:root[data-theme='dark'] select, :root[data-theme='dark'] select {
:root:not([data-theme='light']) select.form-select,
:root:not([data-theme='light']) select {
color-scheme: dark; color-scheme: dark;
} }
@@ -358,8 +360,7 @@ select option {
} }
} }
:root[data-theme='dark'] .surface-card, :root[data-theme='dark'] .surface-card {
:root:not([data-theme='light']) .surface-card {
background: color-mix(in srgb, var(--color-card-background) 82%, var(--color-background-primary)); background: color-mix(in srgb, var(--color-card-background) 82%, var(--color-background-primary));
} }

View File

@@ -5,7 +5,8 @@ export type LabCaseActivityType =
| 'CASE_IMPORTANT' | 'CASE_IMPORTANT'
| 'CASE_AMENDED' | 'CASE_AMENDED'
| 'TASK_COMPLETED' | 'TASK_COMPLETED'
| 'TASK_ASSIGNED'; | 'TASK_ASSIGNED'
| 'CASE_COMPLETED';
export interface LabCaseActivityItem { export interface LabCaseActivityItem {
id: string; id: string;

View File

@@ -6,6 +6,7 @@ export type UserNotificationType =
| 'CASE_IMPORTANT' | 'CASE_IMPORTANT'
| 'TASK_COMPLETED' | 'TASK_COMPLETED'
| 'TASK_ASSIGNED' | 'TASK_ASSIGNED'
| 'CASE_COMPLETED'
| 'CONNECTION_REQUEST' | 'CONNECTION_REQUEST'
| 'STAFF_INVITE'; | 'STAFF_INVITE';