44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useEffect } from 'react';
|
||
|
|
import { usePathname } from 'next/navigation';
|
||
|
|
|
||
|
|
import { type BreadcrumbHint, useBreadcrumbStore } from '@/stores/breadcrumb-store';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Detail pages call this on mount to register their entity hierarchy
|
||
|
|
* for the topbar breadcrumb. Pass a stable hint object (or memoise the
|
||
|
|
* inputs) so the effect doesn't re-fire every render.
|
||
|
|
*
|
||
|
|
* Example (interest detail page):
|
||
|
|
* useBreadcrumbHint({
|
||
|
|
* parents: [{ label: 'Mary Smith', href: '/port/clients/abc' }],
|
||
|
|
* current: 'B17',
|
||
|
|
* });
|
||
|
|
*
|
||
|
|
* The hint clears when the page unmounts so a stale hierarchy doesn't
|
||
|
|
* leak into the next route.
|
||
|
|
*/
|
||
|
|
export function useBreadcrumbHint(hint: BreadcrumbHint | null | undefined): void {
|
||
|
|
const pathname = usePathname();
|
||
|
|
const setHint = useBreadcrumbStore((s) => s.setHint);
|
||
|
|
const clearHint = useBreadcrumbStore((s) => s.clearHint);
|
||
|
|
|
||
|
|
// Stringify for stable equality — caller can pass an object literal
|
||
|
|
// each render without wrecking effect deps. The serialized form is
|
||
|
|
// tiny (handful of strings) so this is cheap.
|
||
|
|
const serialized = hint ? JSON.stringify(hint) : null;
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (!serialized || !hint) return;
|
||
|
|
setHint(pathname, hint);
|
||
|
|
return () => {
|
||
|
|
clearHint(pathname);
|
||
|
|
};
|
||
|
|
// serialized stands in for `hint` value-equality; pathname triggers
|
||
|
|
// re-register if the page navigates without unmounting (rare but
|
||
|
|
// possible on client-side route swaps within the same layout).
|
||
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
|
|
}, [serialized, pathname, setHint, clearHint]);
|
||
|
|
}
|