mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 04:33:11 +00:00
Dispatchers see a one-line banner and a one-time toast while a Reactive/Emergency work order is past half of its SEV response window; the banner opens the board on exactly those work orders and dismisses for the session. Missed deadlines stay in the notification center until acknowledged, and Clear all skips them.
59 lines
2.3 KiB
TypeScript
59 lines
2.3 KiB
TypeScript
import { useMemo } from "react";
|
|
import { useNavigate } from "react-router";
|
|
import type { NotificationItem } from "@/domain/notifications/types/notification-feed";
|
|
import { useNotificationSession } from "@/domain/notifications/session/notification-session-context";
|
|
import { useAcknowledgeSlaBreach } from "@/domain/notifications/use-cases/use-acknowledge-sla-breach";
|
|
import { useNotificationFeed } from "@/domain/notifications/use-cases/use-notification-feed";
|
|
import { notificationTargetUrl } from "@/domain/notifications/utils/notification-target-url";
|
|
import {
|
|
isDismissable,
|
|
visibleNotificationSections,
|
|
} from "@/domain/notifications/utils/visible-notification-sections";
|
|
import { useAuthContext } from "@/providers/auth-context";
|
|
|
|
export function useNotificationCenter(onNavigate?: () => void) {
|
|
const navigate = useNavigate();
|
|
const { user } = useAuthContext();
|
|
const feed = useNotificationFeed();
|
|
const { dismissedIds, readIds, dismiss, markRead } = useNotificationSession();
|
|
|
|
const sections = useMemo(
|
|
() => visibleNotificationSections(feed.data?.sections ?? [], dismissedIds),
|
|
[feed.data, dismissedIds],
|
|
);
|
|
const items = useMemo(() => sections.flatMap((section) => section.items), [sections]);
|
|
const unreadIds = useMemo(
|
|
() => new Set(items.filter((item) => !readIds.has(item.id)).map((item) => item.id)),
|
|
[items, readIds],
|
|
);
|
|
|
|
const acknowledgeBreach = useAcknowledgeSlaBreach();
|
|
const acknowledge = (item: NotificationItem) => {
|
|
if (item.rowType !== "acknowledge" || item.target.workOrderId == null) return;
|
|
acknowledgeBreach.mutate(item.target.workOrderId);
|
|
};
|
|
const acknowledgingWorkOrderId = acknowledgeBreach.isPending ? acknowledgeBreach.variables : null;
|
|
|
|
const open = (item: NotificationItem, url = notificationTargetUrl(item, user?.id)) => {
|
|
markRead([item.id]);
|
|
if (url == null) return;
|
|
onNavigate?.();
|
|
navigate(url);
|
|
};
|
|
|
|
return {
|
|
sections,
|
|
unreadIds,
|
|
isLoading: feed.isLoading,
|
|
hasData: feed.data != null,
|
|
error: feed.error,
|
|
open,
|
|
dismiss: (item: NotificationItem) => dismiss([item.id]),
|
|
acknowledge,
|
|
acknowledgingWorkOrderId,
|
|
dismissAll: () => dismiss(items.filter(isDismissable).map((item) => item.id)),
|
|
markAllRead: () => markRead(items.map((item) => item.id)),
|
|
};
|
|
}
|
|
|
|
export type NotificationCenter = ReturnType<typeof useNotificationCenter>;
|