admin / Synapse-Cortex
publicSelf Hosted ITSM Tool with RBAC/Tenanting and MFA
Synapse-Cortex / Synapse-Cortexv2 / frontend / src / layout / PageHeaderContext.tsx
1596 B · main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from 'react' interface HeaderState { header: ReactNode setHeader: (node: ReactNode) => void } const PageHeaderContext = createContext<HeaderState | undefined>(undefined) export function PageHeaderProvider({ children }: { children: ReactNode }) { const [header, setHeader] = useState<ReactNode>(null) const value = useMemo(() => ({ header, setHeader }), [header]) return <PageHeaderContext.Provider value={value}>{children}</PageHeaderContext.Provider> } function usePageHeaderContext(): HeaderState { const ctx = useContext(PageHeaderContext) if (!ctx) throw new Error('usePageHeader must be used within PageHeaderProvider') return ctx } /** Pages call this to set the topbar breadcrumb/title text for the AppShell * they're currently rendered inside - mirrors v1's per-page `{% block header %}`. * * IMPORTANT: this effect is keyed on `node`'s reference identity. A plain * string literal is fine, but if `node` is JSX built with dynamic values * (e.g. a ticket number), wrap it in `useMemo` in the caller with the actual * primitive dependencies - a fresh JSX literal every render never stabilizes * and creates an infinite render loop (setHeader -> Provider re-renders -> * this page re-renders -> new JSX -> setHeader -> ...). */ export function usePageHeader(node: ReactNode) { const { setHeader } = usePageHeaderContext() useEffect(() => { setHeader(node) }, [node, setHeader]) } export function useHeaderValue(): ReactNode { return usePageHeaderContext().header } |