forked from Goutam/lynkeduppro-crm
be50d53c50
Shared RealtimeProvider opens ONE dashboard-wide IIOS message socket reused by the messenger tab and the new NotificationCenter. CrmMessagingAdapter gains setFocus (drives presence/push suppression) and subscribeActivity (joins all of the caller's threads, fans out incoming messages). NotificationCenter shows a clickable toast on new messages when you're not on the messenger tab and deep-links to the conversation. Pulls @insignia/iios-messaging-ui@0.1.7. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
"use client";
|
|
|
|
// One shared IIOS message socket for the whole dashboard, so the messenger tab AND the app-wide
|
|
// notification center use a single connection (not one each). Opened at the dashboard level and
|
|
// kept alive across tab switches; the messenger tab reuses it via useRealtime().
|
|
|
|
import { createContext, useContext, useEffect, useState, type ReactNode } from "react";
|
|
import { useQuery } from "@abe-kap/appshell-sdk/react";
|
|
import { MessageSocket } from "@insignia/iios-kernel-client";
|
|
import { isShellConfigured } from "./appshell";
|
|
|
|
const RealtimeContext = createContext<MessageSocket | null>(null);
|
|
interface RealtimeDTO { url: string; audience: string; token?: string }
|
|
const SHELL = isShellConfigured();
|
|
|
|
function LiveRealtimeProvider({ children }: { children: ReactNode }) {
|
|
const rt = useQuery<RealtimeDTO>("crm.messenger.realtime", {});
|
|
const [socket, setSocket] = useState<MessageSocket | null>(null);
|
|
const url = rt.data?.url;
|
|
const token = rt.data?.token;
|
|
useEffect(() => {
|
|
if (!url || !token) return;
|
|
const s = new MessageSocket({ serviceUrl: url, token, autoConnect: false });
|
|
s.connect();
|
|
setSocket(s);
|
|
return () => {
|
|
s.disconnect();
|
|
setSocket(null);
|
|
};
|
|
}, [url, token]);
|
|
return <RealtimeContext.Provider value={socket}>{children}</RealtimeContext.Provider>;
|
|
}
|
|
|
|
export function RealtimeProvider({ children }: { children: ReactNode }) {
|
|
// SHELL is a build-time constant, so the same branch runs every render (Rules-of-Hooks safe).
|
|
if (!SHELL) return <>{children}</>;
|
|
return <LiveRealtimeProvider>{children}</LiveRealtimeProvider>;
|
|
}
|
|
|
|
/** The shared socket, or null (demo mode / not yet connected). */
|
|
export function useRealtime(): MessageSocket | null {
|
|
return useContext(RealtimeContext);
|
|
}
|