/* Hierarchy.jsx — 組織架構 (alliance org chart) pyramid: SUPREME 盟主 | VICE 副盟主 | STRATEGIST 軍師團 \ | / six officers: 攻城官 · 外交官 · 司倉官 · 情報官 · 招募官 · 活動官 | bottom band: 盟員 · 主公 · 兄弟 — 同袍同甲 · 共逐山河 Member names per role are live-synced from admin (sw_hierarchy_names_v1). The big middle line (.role-cn) shows the MEMBER NAME when set, else the role title as a fallback. */ const HIER_LS_KEY = "sw_hierarchy_names_v1"; const loadHierNames = () => { try { const v = JSON.parse(localStorage.getItem(HIER_LS_KEY) || "{}"); return v && typeof v === "object" ? v : {}; } catch { return {}; } }; const Hierarchy = () => { const [names, setNames] = React.useState(loadHierNames); React.useEffect(() => { const refresh = () => setNames(loadHierNames()); const onStorage = (e) => { if (e.key === HIER_LS_KEY) refresh(); }; window.addEventListener("storage", onStorage); const t = setInterval(refresh, 8000); return () => { window.removeEventListener("storage", onStorage); clearInterval(t); }; }, []); // Big middle line — name if set, else fallback role title const Title = ({ k, fallback }) => (