import { useEffect, useState } from 'react' import { api } from '../api/client.js' import { parseJsonSetting } from './settingsJson.js' // The nav overrides for the two authenticated layouts (THEMING_AND_NAV.md §4.2). // // `nav_public` rides along in the public settings payload, but `nav_admin` and // `nav_player` deliberately do not: an anonymous visitor has no use for either, // and the admin nav's labels describe the shape of the admin surface. Their // owners read them from GET /api/v1/settings/nav, which any signed-in account // may call — AdminLayout renders for editors and moderators, who cannot reach // GET /admin/settings at all. // // Failing quiet is the whole posture: a request that errors, a malformed row and // "not fetched yet" are the same state to the caller, `{}`, which // applyNavOverrides turns into the coded nav. A sidebar must never blink empty // because a settings call was slow. // One module-level copy, so the second layout to mount renders the nav it // already knows rather than flashing the coded one, and so the nav editor can // push its save into the sidebar the admin is looking at without a reload. let cache = {} const subscribers = new Set() async function load() { try { const data = await api.navSettings() cache = { nav_admin: parseJsonSetting(data?.nav_admin), nav_player: parseJsonSetting(data?.nav_player), } subscribers.forEach((fn) => fn(cache)) } catch { /* the coded nav is the fallback, and it is already on screen */ } return cache } /** Re-read the rows after a save, so the live sidebar catches up at once. */ export function refreshNavOverrides() { return load() } export function useNavOverrides() { const [overrides, setOverrides] = useState(cache) useEffect(() => { subscribers.add(setOverrides) load() return () => subscribers.delete(setOverrides) }, []) return overrides } export default useNavOverrides