/* ============================================================ page-collections.jsx — Collections: bot-driven surveys, polls, profile-collection prompts, and acknowledgements (#8) ============================================================ */ /* Re-bind parseDetail — set by primitives.jsx */ const parseDetail = window.parseDetail || ((body, status) => (body && (body.detail || body.message)) || `HTTP ${status}`); const COLL_KIND_LABELS = { text: 'Text', number: 'Number', rating: 'Rating', choice: 'Choice (single)', multi: 'Multi-select', ack: 'Acknowledgement', day_off: 'Day off', whatsapp: 'WhatsApp number', phone: 'Phone number', email: 'Email address', }; const COLL_AUDIENCE_LABELS = { all: 'Everyone', team: 'Team', role: 'Role', users: 'Specific users' }; const COLL_SCHEDULE_LABELS = { once: 'Once', daily: 'Daily', weekly: 'Weekly', monthly: 'Monthly' }; const COLL_STATUS_LABELS = { draft: 'Draft', active: 'Active', paused: 'Paused', done: 'Done' }; const COLL_DOW_LABELS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; function collStatusBadgeKind(s) { if (s === 'active') return 'ok'; if (s === 'paused') return 'warn'; if (s === 'done') return 'mute'; return 'info'; // draft } /* ── Prompt create/edit modal ── */ function CollPromptForm({ prompt, kinds, profileFields, onClose, onSaved }) { const toast = useToast ? useToast() : { push: () => {} }; const isEdit = !!(prompt && prompt.id); const [title, setTitle] = useState(prompt?.title || ''); const [question, setQuestion] = useState(prompt?.question || ''); const [kind, setKind] = useState(prompt?.kind || (kinds[0] || 'text')); const [options, setOptions] = useState(Array.isArray(prompt?.options) ? prompt.options : []); const [optDraft, setOptDraft] = useState(''); const [profileField, setProfileField] = useState(prompt?.profile_field || ''); const [active, setActive] = useState(prompt ? prompt.active !== false : true); const [busy, setBusy] = useState(false); const [err, setErr] = useState(''); const needsOptions = kind === 'choice' || kind === 'multi'; const addOption = () => { const v = optDraft.trim(); if (!v || options.includes(v)) { setOptDraft(''); return; } setOptions([...options, v]); setOptDraft(''); }; const removeOption = (i) => setOptions(options.filter((_, idx) => idx !== i)); const submit = async () => { if (!title.trim()) { setErr((window.appT||(s=>s))('Title required')); return; } if (!question.trim()) { setErr((window.appT||(s=>s))('Question required')); return; } if (needsOptions && options.length < 2) { setErr((window.appT||(s=>s))('Add at least 2 options')); return; } setErr(''); setBusy(true); try { const body = { title: title.trim(), question: question.trim(), kind, options: needsOptions ? options : null, profile_field: profileField || null, active, }; const url = isEdit ? `/api/collections/prompts/${prompt.id}` : '/api/collections/prompts'; const r = await fetch(url, { method: isEdit ? 'PUT' : 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!r.ok) { const b = await r.json().catch(() => null); throw new Error(parseDetail(b, r.status)); } await r.json(); toast.push({ msg: (window.appT||(s=>s))(isEdit ? 'Prompt updated' : 'Prompt created'), kind: 'ok' }); onSaved(); onClose(); } catch (e) { setErr(e.message); } finally { setBusy(false); } }; return (
e.stopPropagation()}>
{(window.appT||(s=>s))(isEdit ? 'Edit prompt' : 'New prompt')}