improvement: notify counter badge added to treatment and tasks tabs for upadted and edited cases.
This commit is contained in:
19
frontend/src/lib/api/notifications.ts
Normal file
19
frontend/src/lib/api/notifications.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { apiClient } from '@/lib/api/client';
|
||||
import type { LabCaseTabReadTarget, TabBadgeCounts } from '@/lib/tabBadgeUtils';
|
||||
|
||||
export const notificationsApi = {
|
||||
tabCounts: async (): Promise<{ success: boolean; data: TabBadgeCounts }> => {
|
||||
const response = await apiClient.get('/notifications/tab-counts');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
markTabRead: async (tab: LabCaseTabReadTarget): Promise<{ success: boolean }> => {
|
||||
const response = await apiClient.post('/notifications/mark-tab-read', { tab });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
markCaseRead: async (labCaseId: string): Promise<{ success: boolean }> => {
|
||||
const response = await apiClient.post('/notifications/mark-case-read', { labCaseId });
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
60
frontend/src/lib/hooks/useTabBadgeCounts.ts
Normal file
60
frontend/src/lib/hooks/useTabBadgeCounts.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { usePathname } from '@/i18n/navigation';
|
||||
import { notificationsApi } from '@/lib/api/notifications';
|
||||
import {
|
||||
tabBadgesChangedEventName,
|
||||
tabFromPathname,
|
||||
type TabBadgeCounts,
|
||||
} from '@/lib/tabBadgeUtils';
|
||||
import { useAuth } from '@/lib/hooks/useAuth';
|
||||
|
||||
const EMPTY_COUNTS: TabBadgeCounts = {};
|
||||
|
||||
export function useTabBadgeCounts(): TabBadgeCounts {
|
||||
const pathname = usePathname();
|
||||
const { currentOrganization } = useAuth();
|
||||
const [counts, setCounts] = useState<TabBadgeCounts>(EMPTY_COUNTS);
|
||||
|
||||
const fetchCounts = useCallback(async () => {
|
||||
if (!currentOrganization?.id) {
|
||||
setCounts(EMPTY_COUNTS);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await notificationsApi.tabCounts();
|
||||
setCounts(res.data ?? EMPTY_COUNTS);
|
||||
} catch {
|
||||
setCounts(EMPTY_COUNTS);
|
||||
}
|
||||
}, [currentOrganization?.id]);
|
||||
|
||||
useEffect(() => {
|
||||
void fetchCounts();
|
||||
}, [fetchCounts, pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
const onChanged = () => void fetchCounts();
|
||||
window.addEventListener(tabBadgesChangedEventName(), onChanged);
|
||||
return () => window.removeEventListener(tabBadgesChangedEventName(), onChanged);
|
||||
}, [fetchCounts]);
|
||||
|
||||
return counts;
|
||||
}
|
||||
|
||||
export function useMarkTabReadOnVisit() {
|
||||
const pathname = usePathname();
|
||||
const { currentOrganization } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
const tab = tabFromPathname(pathname);
|
||||
// Cases tab badge clears per opened case (mark-case-read), not on tab visit.
|
||||
if (!tab || tab === 'CASES' || !currentOrganization?.id) return;
|
||||
|
||||
void notificationsApi.markTabRead(tab).then(() => {
|
||||
window.dispatchEvent(new Event(tabBadgesChangedEventName()));
|
||||
});
|
||||
}, [pathname, currentOrganization?.id]);
|
||||
}
|
||||
31
frontend/src/lib/tabBadgeUtils.ts
Normal file
31
frontend/src/lib/tabBadgeUtils.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
export type TabBadgeCounts = {
|
||||
cases?: number;
|
||||
tasks?: number;
|
||||
treatment?: number;
|
||||
};
|
||||
|
||||
export type LabCaseTabReadTarget = 'CASES' | 'TASKS' | 'TREATMENT';
|
||||
|
||||
const TAB_BADGES_CHANGED_EVENT = 'tab-badges-changed';
|
||||
|
||||
export function notifyTabBadgesChanged() {
|
||||
window.dispatchEvent(new Event(TAB_BADGES_CHANGED_EVENT));
|
||||
}
|
||||
|
||||
export function tabBadgesChangedEventName() {
|
||||
return TAB_BADGES_CHANGED_EVENT;
|
||||
}
|
||||
|
||||
export function tabFromPathname(pathname: string): LabCaseTabReadTarget | null {
|
||||
if (pathname === '/cases' || pathname.startsWith('/cases/')) return 'CASES';
|
||||
if (pathname === '/tasks' || pathname.startsWith('/tasks/')) return 'TASKS';
|
||||
if (pathname === '/treatment' || pathname.startsWith('/treatment/')) return 'TREATMENT';
|
||||
return null;
|
||||
}
|
||||
|
||||
export function badgeCountForPath(counts: TabBadgeCounts, pathname: string): number {
|
||||
if (pathname === '/cases' || pathname.startsWith('/cases/')) return counts.cases ?? 0;
|
||||
if (pathname === '/tasks' || pathname.startsWith('/tasks/')) return counts.tasks ?? 0;
|
||||
if (pathname === '/treatment' || pathname.startsWith('/treatment/')) return counts.treatment ?? 0;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user