/* global React */ const { useState, useEffect } = React; const WP_EVIDENCE_LABELS = { segment: 'Segments', repeated_behavior: 'Repeated behavior', action: 'Actions', tension: 'Tensions', }; const wpText = (value) => String(value || '').replace(/\s+/g, ' ').trim(); const wpHumanize = (value) => wpText(value).replace(/[_-]+/g, ' ').split(' ').map((w) => (w ? w.charAt(0).toUpperCase() + w.slice(1) : w)).join(' '); const wpQuote = (value, max = 118) => { const text = wpText(value); if (!text) return ''; if (text.length <= max) return text; return text.slice(0, max).replace(/\s+\S*$/, '') + '...'; }; const formatStaleLabel = (hours) => { const value = Number(hours || 0); if (value <= 6) return 'Fresh today'; if (value < 48) return `${Math.round(value)}h old`; const days = Math.round(value / 24); if (days < 14) return `${days}d old`; return `${Math.round(days / 7)}w old`; }; const evidenceCountLabel = (summary = {}) => { const segments = Number(summary.segment_count || 0); const repeated = Number(summary.repeated_behavior_count || 0); const actions = Number(summary.action_count || 0); const parts = []; if (segments) parts.push(`${segments} segment${segments === 1 ? '' : 's'}`); if (repeated) parts.push(`${repeated} repeated`); if (actions) parts.push(`${actions} action${actions === 1 ? '' : 's'}`); return parts.length ? parts.join(' / ') : 'Evidence pending'; }; const groupWaypointEvidence = (wp) => { const grouped = { repeated_behavior: [], action: [], segment: [], tension: [], }; (wp.evidence || []).forEach((item, index) => { const type = grouped[item.type] ? item.type : 'segment'; const isBehavior = (type === 'repeated_behavior' || type === 'tension'); const rawText = wpText(item.label) || wpText(item.excerpt || item.detail || item.text); grouped[type].push({ id: item.id || `${wp.id}-evidence-${index}`, label: isBehavior ? (wpHumanize(rawText) || WP_EVIDENCE_LABELS[type] || 'Evidence') : (wpText(item.label) || WP_EVIDENCE_LABELS[type] || 'Evidence'), excerpt: isBehavior ? '' : wpQuote(item.excerpt || item.detail || item.text, type === 'segment' ? 150 : 110), date: item.date || '', sourceId: item.sourceId || '', }); }); return grouped; }; const PlottingCard = ({ domainKey }) => { const label = (domainKey || 'domain').replace('_', ' '); return ( ); }; const WaypointCard = ({ wp, onOpen }) => { const summary = wp.evidenceSummary || {}; return (
36 ? ' wp--aged' : '')} style={{ '--domain-color': wp.color }} role="button" tabIndex={0} aria-label={`Open waypoint for ${wp.valueGoal}`} onClick={() => onOpen(wp)} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onOpen(wp); } }} > {wp.valueGoal}
{wp.headline}

{wp.description}

{wp.domain} {evidenceCountLabel(summary)} {formatStaleLabel(wp.staleHours)}
View evidence
); }; const WaypointEvidenceList = ({ title, items, emptyText }) => (
{title} {items.length}
{items.length > 0 ? (
{items.map(item => (
{item.label} {item.date ? {item.date} : null}
{item.excerpt ?

{item.excerpt}

: null}
))}
) : (

{emptyText}

)}
); const WaypointDrawer = ({ waypoint, onClose }) => { const [reflection, setReflection] = useState(''); const [showOptional, setShowOptional] = useState(false); useEffect(() => { if (!waypoint) return; setReflection(''); setShowOptional(false); }, [waypoint && waypoint.id]); useEffect(() => { if (!waypoint) return; const prevOverflow = document.body.style.overflow; document.body.style.overflow = 'hidden'; return () => { document.body.style.overflow = prevOverflow; }; }, [waypoint]); useEffect(() => { if (!waypoint) return; const onKey = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [waypoint, onClose]); if (!waypoint) return null; const evidence = groupWaypointEvidence(waypoint); const summary = waypoint.evidenceSummary || {}; return (