import { json } from "@remix-run/node"; import type { LoaderFunctionArgs } from "@remix-run/node"; import { useFetcher, type ShouldRevalidateFunction } from "@remix-run/react"; import { useEffect, useRef } from "react"; import { requireUserId } from "~/services/session.server"; import { getActivePlatformNotifications, verifyOrgMembership, type PlatformNotificationWithPayload, } from "~/services/platformNotifications.server"; export const shouldRevalidate: ShouldRevalidateFunction = () => false; export type PlatformNotificationsLoaderData = { notifications: PlatformNotificationWithPayload[]; unreadCount: number; }; export async function loader({ request }: LoaderFunctionArgs) { const userId = await requireUserId(request); const url = new URL(request.url); const rawOrganizationId = url.searchParams.get("organizationId") ?? undefined; const rawProjectId = url.searchParams.get("projectId") ?? undefined; const { organizationId, projectId } = await verifyOrgMembership({ userId, organizationId: rawOrganizationId, projectId: rawProjectId, }); if (!organizationId) { return json({ notifications: [], unreadCount: 0 }); } const result = await getActivePlatformNotifications({ userId, organizationId, projectId }); return json(result); } const POLL_INTERVAL_MS = 60000; // 1 minute export function usePlatformNotifications(organizationId: string, projectId: string) { const fetcher = useFetcher(); const lastLoadedUrl = useRef(null); useEffect(() => { const url = `/resources/platform-notifications?organizationId=${encodeURIComponent(organizationId)}&projectId=${encodeURIComponent(projectId)}`; if (lastLoadedUrl.current !== url && fetcher.state === "idle") { lastLoadedUrl.current = url; fetcher.load(url); } const interval = setInterval(() => { if (fetcher.state === "idle") { fetcher.load(url); } }, POLL_INTERVAL_MS); return () => clearInterval(interval); }, [organizationId, projectId]); return { notifications: fetcher.data?.notifications ?? [], unreadCount: fetcher.data?.unreadCount ?? 0, isLoading: fetcher.state !== "idle", }; }