Files
temetro/frontend/lib/notifications.ts
T
Khalid Abdi eb94c1549a frontend: fix onboarding bounce, mobile sidebar btn, notif deep-links, analysis header
- Fix clinic onboarding loop: refresh session after setActive before navigating,
  surface setActive errors, and guard AppAuthGuard's onboarding redirect race (#1)
- Add a mobile-only floating top-right SidebarTrigger so the sidebar is reachable
  when the offcanvas sidebar is closed on phones (#5)
- Make notifications clickable: navigate to the source (conversation/patient) and
  mark read; MessagesView/PatientsView honor ?conversation= / ?file= deep links (#6)
- Analysis page: add an Overview header with a time-range segmented control and a
  Customize popover that shows/hides sections; range slices month-based charts (#10)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 20:21:05 +03:00

48 lines
1.4 KiB
TypeScript

import { apiFetch } from "@/lib/api-client";
// A notification for the signed-in user. Mirrors the backend
// `src/types/notification.ts`.
export type Notification = {
id: string;
type: string;
text: string;
read: boolean;
entityType: string | null;
entityId: string | null;
actorName: string | null;
actorInitials: string | null;
createdAt: string;
};
export type NotificationsResponse = {
notifications: Notification[];
unread: number;
};
export function listNotifications(): Promise<NotificationsResponse> {
return apiFetch<NotificationsResponse>("/api/notifications");
}
export function markNotificationRead(id: string): Promise<void> {
return apiFetch<void>(`/api/notifications/${id}/read`, { method: "PATCH" });
}
export function markAllNotificationsRead(): Promise<void> {
return apiFetch<void>("/api/notifications/read-all", { method: "POST" });
}
// Maps a notification to the in-app route where the event occurred, so the
// popover can navigate the user there on click. Returns null when there's no
// meaningful destination (the item then renders as non-clickable).
export function notificationHref(n: Notification): string | null {
if (!n.entityId) return null;
switch (n.entityType) {
case "conversation":
return `/messages?conversation=${encodeURIComponent(n.entityId)}`;
case "patient":
return `/patients?file=${encodeURIComponent(n.entityId)}`;
default:
return null;
}
}