/* global React */ const { useState, useRef, useEffect } = React; const HEADER_DOMAINS = [ { id: 'inner', label: 'Inner World', color: 'var(--axis-inner)' }, { id: 'physical', label: 'Physical', color: 'var(--axis-physical)' }, { id: 'creative', label: 'Creative', color: 'var(--axis-creative)' }, { id: 'interpersonal', label: 'Interpersonal', color: 'var(--axis-interpersonal)' }, { id: 'adventure', label: 'Adventure', color: 'var(--axis-adventure)' }, { id: 'admin', label: 'Life Admin', color: 'var(--axis-life-admin)' }, ]; const NEW_ENTRY_OPTIONS = [ { id: 'action', label: 'Action' }, { id: 'practice', label: 'Practice' }, { id: 'log', label: 'Daily Log' }, ]; /* ── Shared drawer hook ──────────────────────────────────────────────────── */ function useDrawer(drawerRef, onClose) { useEffect(() => { const onMouse = (e) => { if (drawerRef.current && !drawerRef.current.contains(e.target)) onClose(); }; const onKey = (e) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('mousedown', onMouse); document.addEventListener('keydown', onKey); return () => { document.removeEventListener('mousedown', onMouse); document.removeEventListener('keydown', onKey); }; }, [onClose]); } /* ── ActionDrawer ────────────────────────────────────────────────────────── */ const ActionDrawer = ({ onClose }) => { const [title, setTitle] = useState(''); const [desc, setDesc] = useState(''); const [saving, setSaving] = useState(false); const drawerRef = useRef(null); const titleRef = useRef(null); useDrawer(drawerRef, onClose); useEffect(() => { titleRef.current?.focus(); }, []); const handleSubmit = () => { if (!title.trim() || saving) return; setSaving(true); fetch('/api/actions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ai_refined_title: title.trim(), ai_refined_description: desc.trim() || null, origin_snippet: title.trim(), domain: 'admin', score: 0.55, horizon_state: 'focus_zone', }), }) .then(() => { window.dispatchEvent(new CustomEvent('soulitics:board-refresh')); setSaving(false); onClose(); }) .catch(() => setSaving(false)); }; return ( <>
> ); }; /* ── DailyLogDrawer ──────────────────────────────────────────────────────── */ const DailyLogDrawer = ({ onClose }) => { const [text, setText] = useState(''); const [saving, setSaving] = useState(false); const drawerRef = useRef(null); const textareaRef = useRef(null); useDrawer(drawerRef, onClose); useEffect(() => { textareaRef.current?.focus(); }, []); const handleSubmit = () => { const body = text.trim(); if (!body || saving) return; setSaving(true); fetch('/api/actions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ai_refined_title: body.slice(0, 80), ai_refined_description: body, origin_snippet: body.slice(0, 80), domain: 'inner', score: 0.55, horizon_state: 'focus_zone', }), }) .then(() => { window.dispatchEvent(new CustomEvent('soulitics:board-refresh')); setSaving(false); onClose(); }) .catch(() => setSaving(false)); }; return ( <> > ); }; /* ── Header ──────────────────────────────────────────────────────────────── */ const Header = ({ activeDomains, onDomainClick }) => { const [menuOpen, setMenuOpen] = useState(false); const [showAction, setShowAction] = useState(false); const [showDailyLog, setShowDailyLog] = useState(false); const [showPracticeForm, setShowPracticeForm] = useState(false); const [practiceRegistry, setPracticeRegistry] = useState([]); const menuRef = useRef(null); const triggerRef = useRef(null); const itemRefs = useRef([]); useEffect(() => { const onMouse = (e) => { if (menuRef.current && !menuRef.current.contains(e.target)) setMenuOpen(false); }; document.addEventListener('mousedown', onMouse); return () => document.removeEventListener('mousedown', onMouse); }, []); useEffect(() => { if (menuOpen) itemRefs.current[0]?.focus(); }, [menuOpen]); const handleMenuKeyDown = (e) => { const items = itemRefs.current.filter(Boolean); const idx = items.indexOf(document.activeElement); if (e.key === 'Escape') { e.preventDefault(); setMenuOpen(false); triggerRef.current?.focus(); } if (e.key === 'ArrowDown') { e.preventDefault(); items[(idx + 1) % items.length]?.focus(); } if (e.key === 'ArrowUp') { e.preventDefault(); items[(idx - 1 + items.length) % items.length]?.focus(); } }; const handleSelect = (type) => { setMenuOpen(false); if (type === 'action') { setShowAction(true); } else if (type === 'practice') { fetch('/api/momentum/registry') .then(r => r.ok ? r.json() : []) .then(reg => { setPracticeRegistry(reg); setShowPracticeForm(true); }) .catch(() => { setPracticeRegistry([]); setShowPracticeForm(true); }); } else { setShowDailyLog(true); } }; return ( <>