function SettingsChatwootPage() { const { AppBootstrap } = window.__CRM__; const { Container, Paper, Typography, TextField, Button, Stack, MenuItem, Divider, Chip, Grid, Snackbar, Alert, Switch, FormControlLabel } = MaterialUI; // Toast const [toast, setToast] = React.useState({ open:false, sev:'info', msg:'' }); const notify = (msg, sev='info') => setToast({ open:true, sev, msg }); // Chatwoot settings const [loading, setLoading] = React.useState(true); const [form, setForm] = React.useState({ base_url: 'https://chatwoot.falandobot.com.br', account_id: '', access_token: '', default_inbox_id: '', default_inbox_name: '', }); const [hasToken, setHasToken] = React.useState(false); const [inboxes, setInboxes] = React.useState([]); // Throttling per inbox const [selectedInbox, setSelectedInbox] = React.useState(''); const [iboxCfg, setIboxCfg] = React.useState({ enabled: 1, rate_per_min: 20, batch_size: 50, interval_sec: 60, daily_cap: 2000, quiet_start: '22:00', quiet_end: '08:00', jitter_min_ms: 200, jitter_max_ms: 1500 }); // Load Chatwoot core settings + default inbox on mount async function loadCore() { try { const r = await fetch('/api/settings_chatwoot_get.php', { credentials:'include', cache:'no-store' }); const j = await r.json(); if (r.ok && j.ok && j.config) { setForm(f=>({ ...f, base_url: j.config.base_url || f.base_url, account_id: String(j.config.account_id || ''), default_inbox_id: j.config.default_inbox_id ? String(j.config.default_inbox_id) : '', default_inbox_name: j.config.default_inbox_name || '' })); setHasToken(!!j.config.has_token); if (j.config.default_inbox_id) setSelectedInbox(String(j.config.default_inbox_id)); } } catch { notify('Failed to load Chatwoot settings', 'error'); } } // Load inbox list async function loadInboxes() { try{ const r = await fetch('/api/settings_chatwoot_inboxes.php',{ credentials:'include' }); const j = await r.json(); if(!j.ok) { notify('Could not fetch inboxes', 'error'); return; } setInboxes(j.items || []); notify(`Loaded ${j.items?.length||0} inbox(es)`, 'success'); }catch{ notify('Network error while loading inboxes', 'error'); } } // Initial load React.useEffect(()=>{ (async ()=>{ setLoading(true); await Promise.all([loadCore(), loadInboxes().catch(()=>{})]); setLoading(false); })(); },[]); // Persist Chatwoot settings async function saveChatwoot() { const fd = new FormData(); fd.append('base_url', form.base_url.trim()); fd.append('account_id', String(form.account_id||'')); if (form.access_token.trim()!=='') fd.append('access_token', form.access_token.trim()); if (form.default_inbox_id) { fd.append('default_inbox_id', form.default_inbox_id); fd.append('default_inbox_name', inboxes.find(i=>String(i.id)===String(form.default_inbox_id))?.name || form.default_inbox_name || '' ); } try { const r = await fetch('/api/settings_chatwoot_save.php',{ method:'POST', body:fd, credentials:'include' }); const j = await r.json(); if (!r.ok || !j?.ok) { notify('Failed to save Chatwoot settings', 'error'); return; } setHasToken(!!(j.config?.has_token)); setForm(prev => ({ ...prev, base_url: j.config?.base_url || prev.base_url, account_id: String(j.config?.account_id || ''), access_token: '', default_inbox_id: j.config?.default_inbox_id ? String(j.config.default_inbox_id) : '', default_inbox_name: j.config?.default_inbox_name || '' })); if (j.config?.default_inbox_id) setSelectedInbox(String(j.config.default_inbox_id)); notify('Chatwoot settings saved', 'success'); } catch { notify('Network error while saving Chatwoot', 'error'); } } function selectDefaultInbox(idStr){ const found = inboxes.find(i=>String(i.id)===String(idStr)); setForm({...form, default_inbox_id: idStr, default_inbox_name: found?.name || ''}); } // Load throttling for selected inbox React.useEffect(()=>{ if (!selectedInbox) return; (async ()=>{ try{ const r = await fetch(`/api/delivery_inbox_get.php?inbox_id=${encodeURIComponent(selectedInbox)}`, { credentials:'include', cache:'no-store' }); const j = await r.json(); if (!r.ok || !j?.ok) { notify('Failed to load inbox delivery settings', 'error'); return; } const s = j.settings || {}; const next = { ...iboxCfg, ...s }; ['enabled','rate_per_min','batch_size','interval_sec','daily_cap','jitter_min_ms','jitter_max_ms'].forEach(k=> next[k] = Number(next[k])); setIboxCfg(next); }catch{ notify('Network error while loading inbox settings', 'error'); } })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedInbox]); // Save throttling for selected inbox async function saveInboxCfg(){ if (!selectedInbox) { notify('Pick an inbox first', 'warning'); return; } const fd = new FormData(); fd.append('inbox_id', selectedInbox); Object.entries(iboxCfg).forEach(([k,v])=>fd.append(k, String(v))); try{ const r = await fetch('/api/delivery_inbox_save.php',{ method:'POST', body:fd, credentials:'include' }); const j = await r.json().catch(()=>null); if (!r.ok || !j?.ok) { notify(j?.err || 'Failed to save inbox settings', 'error'); return; } notify('Inbox delivery settings saved', 'success'); // Reload to reflect persisted values exactly const r2 = await fetch(`/api/delivery_inbox_get.php?inbox_id=${encodeURIComponent(selectedInbox)}`, { credentials:'include', cache:'no-store' }); const j2 = await r2.json(); if (r2.ok && j2.ok) setIboxCfg(prev => ({ ...prev, ...j2.settings })); }catch{ notify('Network error while saving inbox settings', 'error'); } } const Num = ({label, k, min=0, step=1}) => ( setIboxCfg({...iboxCfg, [k]: Number(e.target.value)})} inputProps={{ step, min }} fullWidth /> ); const Time = ({label, k}) => ( setIboxCfg({...iboxCfg, [k]: e.target.value})} InputLabelProps={{ shrink:true }} fullWidth /> ); return ( Settings {/* Chatwoot core settings */} Chatwoot setForm({...form, base_url:e.target.value})} fullWidth /> setForm({...form, account_id:e.target.value})} fullWidth /> setForm({...form, access_token:e.target.value})} fullWidth helperText={hasToken ? 'Token stored. Leave blank to keep current.' : 'Paste your API access token.'} /> selectDefaultInbox(e.target.value)} fullWidth helperText="Optional. Used as default when creating campaigns." > — none — {inboxes.map(i=>( {i.name} ({i.channel||'channel'}) ))} {form.default_inbox_name && ( Selected: {form.default_inbox_name} )} {/* Delivery / Throttling per Inbox */} Delivery · Throttling per Inbox Define throttling and quiet hours per Chatwoot inbox. setSelectedInbox(e.target.value)} fullWidth > — pick an inbox — {inboxes.map(i=>( {i.name} ({i.channel||'channel'}) ))} setIboxCfg({...iboxCfg, enabled: e.target.checked ? 1 : 0})} /> } label="Enabled" /> setToast(t=>({ ...t, open:false }))} anchorOrigin={{ vertical:'bottom', horizontal:'right' }} > setToast(t=>({ ...t, open:false }))} severity={toast.sev} variant="filled" sx={{ width:'100%' }}> {toast.msg} ); } window.SettingsChatwootPage = SettingsChatwootPage;