NGU-Web/src/lib/adminTitle.tsx
Zaldimmar 2428f4412a Type src/ against API and database shapes, fixing implicit anys
Adds .d.ts declarations beside the untyped JS modules imported from
TS (api.js, navConfig.js, adminSchema.js, adminNav.js, src/data/*),
with shapes taken from the server routes and migrations. get/post/
patch/del now return unknown unless the caller names the response.

Fixes found along the way:
- website/email/instagram are bare strings from splitLinks, not Link
  objects; OrganizationDetail's website and email pills rendered with
  no href or label and now link correctly.
- The chapter map falls back to FALLBACK_COLOR for a region with no
  colour instead of painting its tiles black.

Adds defineSection() so each page manifest entry's props are checked
against its own Component.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 04:13:46 -05:00

32 lines
1.5 KiB
TypeScript

/* ═══════════════════════════════════════════════════════════════
ADMIN TITLE
The layout knows which section you're in; only the page knows
which record is on screen. Rather than have both write
document.title and race — child effects run before parent
effects, so the layout would win and the record name would
never survive — the page publishes a string and the layout is
the single writer.
Null is the normal state. A page that publishes nothing, or one
still loading, simply leaves the section title showing.
═══════════════════════════════════════════════════════════════ */
import { createContext, useContext, useEffect } from "react";
export type AdminTitleValue = { setDetail: (value: string | null) => void };
export const AdminTitleContext = createContext<AdminTitleValue | null>(null);
/* Publish the name of whatever this page is showing. Clears on
unmount, so navigating away can't leave a stale record name in
the tab. */
export function useAdminDetail(name: string | null | undefined) {
const setDetail = useContext(AdminTitleContext)?.setDetail;
useEffect(() => {
if (!setDetail) return undefined;
setDetail(name || null);
return () => setDetail(null);
}, [setDetail, name]);
}