import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; import { createContext, useContextSelector } from 'use-context-selector'; import { buildAppHash, parseAppRoute, RouteState, SettingsSection, } from '../utils/appRoute'; interface AppRouteContextProps { route: RouteState; setRoute: (nextRoute: RouteState, options?: { replace?: boolean }) => void; openConversationRoute: (conversationId: string) => void; openHomeRoute: () => void; openSettingsRoute: (section?: SettingsSection) => void; } const defaultRoute = parseAppRoute( typeof window === 'undefined' ? '#/' : window.location.hash, ); const AppRouteContext = createContext({ route: defaultRoute, setRoute: () => {}, openConversationRoute: () => {}, openHomeRoute: () => {}, openSettingsRoute: () => {}, }); export function AppRouteProvider({ children }: { children: ReactNode }) { const [route, setRouteState] = useState(defaultRoute); useEffect(() => { const handleHashChange = () => { setRouteState(parseAppRoute(window.location.hash)); }; window.addEventListener('hashchange', handleHashChange); handleHashChange(); return () => window.removeEventListener('hashchange', handleHashChange); }, []); const setRoute = useCallback((nextRoute: RouteState, options?: { replace?: boolean }) => { const nextHash = buildAppHash(nextRoute); if (window.location.hash === nextHash) { setRouteState(nextRoute); return; } if (options?.replace) { window.history.replaceState(null, '', nextHash); setRouteState(nextRoute); return; } window.location.hash = nextHash; }, []); const openConversationRoute = useCallback((conversationId: string) => { setRoute({ name: 'conversation', conversationId }); }, [setRoute]); const openHomeRoute = useCallback(() => { setRoute({ name: 'home' }); }, [setRoute]); const openSettingsRoute = useCallback((section: SettingsSection = 'account') => { setRoute({ name: 'settings', section }); }, [setRoute]); const value = useMemo(() => ({ route, setRoute, openConversationRoute, openHomeRoute, openSettingsRoute, }), [openConversationRoute, openHomeRoute, openSettingsRoute, route, setRoute]); return ( {children} ); } export const useAppRouteSelector = (selector: (state: AppRouteContextProps) => T): T => ( useContextSelector(AppRouteContext, selector) );