From 1d0e5f27d796a9ce178753a461f589b9eccac636 Mon Sep 17 00:00:00 2001 From: Rafael Lopes Date: Mon, 22 Jun 2026 15:22:54 -0300 Subject: [PATCH] FEAT: Modal de Config do Whatsapp adicionado --- .../components/WhatsappConfigModal.jsx | 370 ++++++++++++++++++ src/modules/management/pages/AdminPage.jsx | 8 +- .../services/whatsappConfigService.js | 29 ++ 3 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 src/modules/management/components/WhatsappConfigModal.jsx create mode 100644 src/modules/management/services/whatsappConfigService.js diff --git a/src/modules/management/components/WhatsappConfigModal.jsx b/src/modules/management/components/WhatsappConfigModal.jsx new file mode 100644 index 0000000..0b8fa85 --- /dev/null +++ b/src/modules/management/components/WhatsappConfigModal.jsx @@ -0,0 +1,370 @@ +import { useEffect, useState } from 'react'; +import { + getWhatsappConfig, + saveWhatsappConfig, + validateWhatsappConfig, +} from '../services/whatsappConfigService'; + +const fieldStyle = { + width: '100%', + border: '1px solid var(--color-border)', + borderRadius: 12, + padding: '0.7rem 0.85rem', + background: '#fff', + color: 'var(--color-text)', + fontWeight: 600, + fontSize: '0.92rem', + boxSizing: 'border-box', +}; + +const labelStyle = { + display: 'block', + fontSize: '0.8rem', + fontWeight: 800, + color: 'var(--color-text-soft)', + marginBottom: '0.35rem', + letterSpacing: '0.03em', + textTransform: 'uppercase', +}; + +export function WhatsappConfigModal({ onClose }) { + const [loading, setLoading] = useState(true); + const [currentConfig, setCurrentConfig] = useState(null); + const [saving, setSaving] = useState(false); + const [validating, setValidating] = useState(false); + const [validation, setValidation] = useState(null); + const [saveSuccess, setSaveSuccess] = useState(false); + const [error, setError] = useState(''); + + const [form, setForm] = useState({ + access_token: '', + phone_number_id: '', + api_version: 'v25.0', + webhook_token: '', + }); + + useEffect(() => { + getWhatsappConfig() + .then((data) => { + setCurrentConfig(data); + setForm((f) => ({ + ...f, + phone_number_id: data.phone_number_id || '', + api_version: data.api_version || 'v25.0', + webhook_token: data.webhook_token || '', + })); + }) + .catch(() => setError('Não foi possível carregar a configuração atual.')) + .finally(() => setLoading(false)); + }, []); + + function handleChange(field, value) { + setValidation(null); + setSaveSuccess(false); + setError(''); + setForm((f) => ({ ...f, [field]: value })); + } + + async function handleValidate() { + if (!form.access_token || !form.phone_number_id) return; + setValidating(true); + setValidation(null); + try { + const result = await validateWhatsappConfig({ + access_token: form.access_token, + phone_number_id: form.phone_number_id, + api_version: form.api_version || 'v25.0', + }); + setValidation(result); + } catch { + setValidation({ valid: false, error: 'Erro de conexão com a Meta API' }); + } finally { + setValidating(false); + } + } + + async function handleSave() { + setSaving(true); + setSaveSuccess(false); + setError(''); + try { + await saveWhatsappConfig(form); + setSaveSuccess(true); + setTimeout(onClose, 1200); + } catch { + setError('Erro ao salvar. Verifique os campos e tente novamente.'); + } finally { + setSaving(false); + } + } + + const canValidate = !!(form.access_token && form.phone_number_id); + const canSave = !!(form.access_token || form.phone_number_id) && !saving; + + return ( +
+
e.stopPropagation()} + style={{ + width: 'min(540px, 100%)', + borderRadius: 22, + border: '1px solid var(--color-border)', + background: '#fff', + padding: '1.4rem', + display: 'grid', + gap: '1rem', + boxShadow: 'var(--shadow-lg)', + maxHeight: '90vh', + overflowY: 'auto', + }} + > + {/* Header */} +
+ +
+ + Configurar WhatsApp + + + Meta Cloud API + +
+ +
+ + {/* Status atual */} + {!loading && currentConfig && ( +
+ {currentConfig.is_configured ? '✅' : '⚠️'} +
+ + {currentConfig.is_configured ? 'Integração configurada' : 'Configuração incompleta'} + + {currentConfig.is_configured && ( + + Token via {currentConfig.token_source === 'database' ? 'banco de dados' : 'variável de ambiente'} + {currentConfig.phone_number_id ? ` · ID: ${currentConfig.phone_number_id}` : ''} + + )} + {!currentConfig.is_configured && ( + + Preencha o Token e o Phone Number ID abaixo + + )} +
+
+ )} + + {loading && ( +

+ Carregando configuração atual… +

+ )} + + {/* Formulário */} +
+
+ + handleChange('access_token', e.target.value)} + style={fieldStyle} + /> +
+ +
+ + handleChange('phone_number_id', e.target.value)} + style={fieldStyle} + /> +
+ +
+
+ + handleChange('api_version', e.target.value)} + style={fieldStyle} + /> +
+
+ + handleChange('webhook_token', e.target.value)} + style={fieldStyle} + /> +
+
+
+ + {/* Resultado da validação */} + {validation && ( +
+ {validation.valid ? ( + <> + + ✅ Credenciais válidas + + + {validation.verified_name && `Conta: ${validation.verified_name}`} + {validation.phone_number && ` · ${validation.phone_number}`} + {validation.quality_rating && ` · Qualidade: ${validation.quality_rating}`} + + + ) : ( + <> + + ❌ Credenciais inválidas + + + {validation.error || 'Verifique o Token e o Phone Number ID'} + {validation.code ? ` (código ${validation.code})` : ''} + + + )} +
+ )} + + {/* Feedback de erro geral */} + {error && ( +

+ {error} +

+ )} + + {/* Feedback de sucesso */} + {saveSuccess && ( +

+ ✅ Configuração salva com sucesso! +

+ )} + + {/* Ações */} +
+ + + +
+
+
+ ); +} diff --git a/src/modules/management/pages/AdminPage.jsx b/src/modules/management/pages/AdminPage.jsx index 833c75c..c55a45d 100644 --- a/src/modules/management/pages/AdminPage.jsx +++ b/src/modules/management/pages/AdminPage.jsx @@ -31,6 +31,7 @@ import { } from '../services/adminAccessService'; import { useViewport } from '../../../shared/hooks/useViewport'; import { getCurrentUserDisplay } from '../../auth/services/sessionService'; +import { WhatsappConfigModal } from '../components/WhatsappConfigModal'; const selectStyle = { width: '100%', @@ -256,6 +257,7 @@ export function AdminPage() { const [authConfigModal, setAuthConfigModal] = useState(null); const [integrationNotice, setIntegrationNotice] = useState(''); const [configurationModal, setConfigurationModal] = useState(null); + const [whatsappConfigModal, setWhatsappConfigModal] = useState(false); useEffect(() => { let isMounted = true; @@ -1709,7 +1711,7 @@ export function AdminPage() { type="button" onClick={() => { if (item.id === 'whatsapp') { - navigate('/admin/whatsapp'); + setWhatsappConfigModal(true); return; } @@ -1732,6 +1734,10 @@ export function AdminPage() { })} + {whatsappConfigModal && ( + setWhatsappConfigModal(false)} /> + )} + {configurationModal ? (