// Detail view — Info tab content (shown when user clicks an opdracht card) // Section card wrapper const Section = ({ title, action, children, noPadding = false }) => { const P = window.PICO; return (

{title}

{action}
{children}
); }; // Key-value row inside a section (side-by-side or stacked) const KV = ({ label, value, editable = false, underline = false }) => { const P = window.PICO; return (
{label} {editable && }
{value && (
{value}
)}
); }; // Status dropdown button in the "Opdracht status" row const StatusDropdown = ({ status, onChange }) => { const P = window.PICO; const [open, setOpen] = React.useState(false); const allStatuses = [ { key: 'matchen', label: 'Matchen' }, { key: 'accepteren', label: 'Accepteren' }, { key: 'offerte', label: 'Offerte' }, { key: 'schouwen', label: 'Schouwen' }, { key: 'installeren', label: 'Installeren' }, ]; const map = { offerte: { bg: P.offerteBg, fg: P.offerteFg }, installeren: { bg: P.installerenBg, fg: P.installerenFg }, schouwen: { bg: P.schouwenBg, fg: P.schouwenFg }, accepteren: { bg: P.accepterenBg, fg: P.accepterenFg }, matchen: { bg: P.matchenBg, fg: P.matchenFg }, }; const s = map[status.key]; return (
{open && ( <>
setOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 10 }} />
{allStatuses.map(st => (
{ onChange(st); setOpen(false); }} style={{ padding: '8px 10px', borderRadius: 6, cursor: 'pointer', fontFamily: '"Plus Jakarta Sans", system-ui', fontSize: 14, color: P.ink, letterSpacing: -0.1, background: st.key === status.key ? P.bg : 'transparent', }} onMouseEnter={e => e.currentTarget.style.background = P.bg} onMouseLeave={e => e.currentTarget.style.background = st.key === status.key ? P.bg : 'transparent'} >{st.label}
))}
)}
); }; // Overzicht content (the default sub-tab) const OverzichtTab = ({ item, onStatusChange }) => { const P = window.PICO; return ( <> {/* Oplevering card */}

Oplevering

{/* Klantinfo */}
{/* Opdrachtomschrijving */}
{/* Gekoppelde installateur */}
}>
Installateur keuze {item.installer || '—'}
{/* Afspraken */}
{item.afspraken.length > 0 && (
{item.afspraken.map(a => (
{a.title}
{a.date} · {a.time}
))}
)}
{/* Offertes */}
{item.offertes > 0 ? (
{Array.from({ length: item.offertes }).map((_, i) => (
Offerte #{i + 1}
€ {(3200 + i * 900).toLocaleString('nl-NL')},00 · In behandeling
))}
) : null}
); }; const FotosTab = ({ item }) => { const P = window.PICO; return ( <>
{[0, 1, 2, 3].map(i => (
{i === 0 ? 'Meterkast' : i === 1 ? 'CV ruimte' : i === 2 ? 'Dak' : 'Gevel'}
))}
); }; const CommunicatieTab = ({ item }) => { const P = window.PICO; const messages = [ { from: 'customer', name: item.customer, text: 'Hoi! Kunnen we de schouw verzetten naar donderdag?', time: '09:12' }, { from: 'me', name: 'Jij', text: 'Dag, donderdag 10:00 kan. Stuur ik een nieuwe uitnodiging.', time: '09:34' }, { from: 'customer', name: item.customer, text: 'Super, bedankt!', time: '09:35' }, ]; return (
{messages.map((m, i) => (
{m.text}
{m.name} · {m.time}
))}
); }; const DetailView = ({ item, onBack, onStatusChange }) => { const P = window.PICO; const [mainTab, setMainTab] = React.useState('info'); // info | activiteit const [subTab, setSubTab] = React.useState('overzicht'); // overzicht | foto | comm // Read current status from mutable state (we'll allow change via dropdown) const [status, setStatus] = React.useState(item.status); React.useEffect(() => { setStatus(item.status); }, [item.id]); // Load Chapter chatbot widget only while the detail view is mounted. // Widget is a floating launcher in document.body; we snapshot children // before init and remove everything the widget added on unmount. React.useEffect(() => { const SCRIPT_ID = 'chapter-chatbot-script'; const WIDGET_ID = 'sa30bp9omghqfy6gu2e60732'; const before = new Set(Array.from(document.body.children)); const initWidget = () => { try { window?.ChapterAI?.init?.(WIDGET_ID); } catch (e) {} }; let script = document.getElementById(SCRIPT_ID); if (!script) { script = document.createElement('script'); script.id = SCRIPT_ID; script.async = true; script.defer = true; script.crossOrigin = 'anonymous'; script.src = 'https://cdn.chapter.works/chatbot-widget/chapter-chatbot-widget.js'; script.onload = initWidget; document.head.appendChild(script); } else { initWidget(); } return () => { Array.from(document.body.children).forEach(el => { if (!before.has(el)) el.remove(); }); }; }, []); const iconCatMap = { generic: , heatpump: , solar: , }; return (
{/* Top bar with back + id + tabs */}
#{item.id}
{/* Main tabs: Info / Activiteit */}
{['info', 'activiteit'].map(t => ( ))}
{mainTab === 'activiteit' && (

Nog geen activiteit

Zodra er iets met deze opdracht gebeurt, vind je het hier terug.

)} {mainTab === 'info' && (
{/* Category/partner row */}
{iconCatMap[item.category.icon]} {item.category.label}
{item.partner}
{/* Address */}

{item.address}, {item.postcode} {item.city}

{/* Opdracht status row */}
Opdracht status { setStatus(s); onStatusChange && onStatusChange(s); }} />
{/* Sub-tabs: Overzicht / Foto's / Communicatie */}
{[ { key: 'overzicht', label: 'Overzicht' }, { key: 'foto', label: "Foto's" }, { key: 'comm', label: 'Communicatie', badge: item.unread }, ].map(t => ( ))}
{subTab === 'overzicht' && } {subTab === 'foto' && } {subTab === 'comm' && }
)}
); }; Object.assign(window, { DetailView });