diff --git a/src/app/hooks/useSingleSessionTab.ts b/src/app/hooks/useSingleSessionTab.ts new file mode 100644 index 00000000..ab8da517 --- /dev/null +++ b/src/app/hooks/useSingleSessionTab.ts @@ -0,0 +1,36 @@ +import { useEffect, useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { getRootPath } from '../pages/pathUtils'; + +export const useSingleSessionTab = (userId?: string) => { + const broadcast = useMemo(() => new BroadcastChannel('in.cinny.broadcast'), []); + + const tabId = useMemo(() => crypto.randomUUID(), []); + const navigate = useNavigate(); + + useEffect(() => { + const handleBroadcast = (event: MessageEvent) => { + if (!userId) return; + const { type, userId: messageUserId, tabId: messageTabId } = event.data ?? {}; + + if (type === 'session-spawn' && messageUserId === userId && messageTabId !== tabId) { + // Another tab opened the same session + navigate(getRootPath()); + } + }; + + broadcast.addEventListener('message', handleBroadcast); + + if (userId) { + broadcast.postMessage({ + type: 'session-spawn', + userId, + tabId, + }); + } + + return () => { + broadcast.removeEventListener('message', handleBroadcast); + }; + }, [broadcast, userId, tabId, navigate]); +}; diff --git a/src/app/pages/AccountSelector.tsx b/src/app/pages/AccountSelector.tsx index b3c1dfe2..d155096b 100644 --- a/src/app/pages/AccountSelector.tsx +++ b/src/app/pages/AccountSelector.tsx @@ -31,6 +31,7 @@ import { mxcToHttp } from '../../client/mxcToHttp'; import { useSessionRequest } from '../hooks/sw/useSessionRequest'; import { useDocumentVisibilityChange } from '../hooks/useDocumentVisibilityChange'; import { useDocumentFocusChange } from '../hooks/useDocumentFocusChange'; +import { useSingleSessionTab } from '../hooks/useSingleSessionTab'; function AccountCard({ session }: { session: Session }) { const { userId } = session; @@ -185,6 +186,7 @@ export function ClientAccountSelector() { const session = useMemo(() => sessions.find((s) => userId === s.userId), [userId, sessions]); useSessionRequest(session ?? sessions[0]); + useSingleSessionTab(session?.userId); const handleVisibility = useCallback( (visible: boolean) => {