PageSourceSearch

https://sentinel-365-c9d4f.web.app/assets/WhatsAppManager-DS4D8ULT.js

js sentinel-365-c9d4f.web.app collected 2026-10-03 12:39:13 UTC 18,198 bytes, 1 lines download raw bytes

1import{r as l,j as e,N as V}from"./react-vendor-pafHdoJx.js";import{a as H,u as K,d as u,M as Q}from"./index-Db0fDLGN.js";import{M as q,as as $,x as W,l as P,L as F,o as J,be as X,k as L,aw as Y,a7 as Z,Q as ee,a6 as ae,bf as se,c as te,bg as le,bh as ne,b8 as oe,at as re,b9 as ie}from"./ui-vendor-DLXJn6s3.js";import"./map-vendor-Dr8zbd0c.js";import"./firebase-vendor-D3UzkAhn.js";const _={open:{label:"Conectado",className:"bg-emerald-500/15 text-emerald-400",icon:L},close:{label:"Desconectado",className:"bg-slate-500/15 text-slate-400",icon:X},connecting:{label:"Conectando",className:"bg-amber-500/15 text-amber-400",icon:J},unknown:{label:"Desconhecido",className:"bg-slate-500/15 text-slate-400",icon:P}};function he(){const{role:s}=H(),{toast:i}=K(),[h,p]=l.useState([]),[x,r]=l.useState(!0),[b,c]=l.useState(null),[y,g]=l.useState(!1),[N,S]=l.useState(!1),[v,A]=l.useState(""),[w,R]=l.useState(""),[o,j]=l.useState(null),d=l.useCallback(async()=>{var a;r(!0),c(null);try{const n=await u.waInstances();p(n)}catch(n){(a=n==null?void 0:n.message)!=null&&a.includes("disabled")?p([]):c((n==null?void 0:n.message)||"Erro ao carregar")}finally{r(!1)}},[]);l.useEffect(()=>{d()},[d]);const E=async()=>{if(v){S(!0);try{const a=await u.waProvisionInstance({number:v,label:w||void 0});j({id:a.id,instanceName:a.instanceName,base64:a.qrcode,code:null}),g(!1),A(""),R(""),d(),i({title:"Instância provisionada",kind:"success"})}catch(a){i({title:"Erro ao provisionar",description:a==null?void 0:a.message,kind:"error"})}finally{S(!1)}}},k=async(a,n)=>{try{const m=await u.waInstanceQR(a);j({id:a,instanceName:n,base64:m.base64,code:m.code})}catch(m){i({title:"QR indisponível",description:m==null?void 0:m.message,kind:"error"})}},I=async a=>{try{await u.waInstanceState(a),d()}catch{}},f=async a=>{confirm("Desconectar a instância? Será preciso re-escanear o QR para reconectar.")&&(await u.waInstanceLogout(a).catch(()=>{}),d())},U=async a=>{confirm("Apagar a instância completamente? Histórico fica, mas o número precisa ser reprovisionado.")&&(await u.waInstanceDelete(a).catch(()=>{}),d())},D=async a=>{if(confirm("Tirar da quarentena? Confirme que a causa raiz foi resolvida (taxa de erro / opt-out / desconexão) antes de retomar envios."))try{await u.waInstanceUnquarantine(a),d(),i({title:"Instância retirada da quarentena",kind:"success"})}catch(n){i({title:"Falha ao retirar da quarentena",description:n==null?void 0:n.message,kind:"error"})}};return s!=="super_admin"?e.jsx(V,{to:"/v2/painel",replace:!0}):e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-10 h-10 rounded-xl flex items-center justify-center",style:{background:"rgba(37,211,102,0.12)"},children:e.jsx(q,{className:"w-5 h-5",style:{color:"#25D366"}})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-bold",style:{color:"var(--page-text)"},children:"WhatsApp Outreach"}),e.jsx("p",{className:"text-xs",style:{color:"var(--page-text-secondary)"},children:"Instâncias Evolution API · ritmo seguro · cap 50/dia com warm-up"})]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:d,className:"p-2 rounded-lg",style:{color:"var(--page-text-muted)"},children:e.jsx($,{className:"w-4 h-4"})}),e.jsxs("button",{onClick:()=>g(!0),className:"flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-semibold text-white",style:{background:"#25D366"},children:[e.jsx(W,{className:"w-4 h-4"})," Nova Instância"]})]})]}),e.jsx(ce,{}),e.jsx("div",{className:"rounded-xl p-4 border",style:{background:"rgba(245,158,11,0.05)",borderColor:"rgba(245,158,11,0.25)"},children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(P,{className:"w-5 h-5 flex-shrink-0 mt-0.5 text-amber-400"}),e.jsxs("div",{className:"text-sm",style:{color:"var(--page-text)"},children:[e.jsx("p",{className:"font-semibold mb-1",children:"Política de envio"}),e.jsxs("ul",{className:"text-xs space-y-0.5",style:{color:"var(--page-text-muted)"},children:[e.jsx("li",{children:"• Warm-up em 14 dias: 5 → 50 mensagens/dia (ramp gradual)"}),e.jsx("li",{children:"• Intervalo aleatório de 90-300s entre envios (sem rajadas)"}),e.jsx("li",{children:"• Apenas em horário comercial: seg-sex, 9h-18h BRT"}),e.jsx("li",{children:"• 5 variações de template + personalização por nome/empresa"}),e.jsx("li",{children:"• Opt-out automático via PARAR/SAIR/STOP/CANCELAR no inbound"}
1),e.jsx("li",{children:"• Quarentena automática: 5 erros seguidos OU 10% opt-out em 24h"})]})]})]})}),b&&e.jsxs("div",{className:"rounded-xl p-3 text-sm flex items-center gap-2",style:{background:"rgba(239,68,68,0.08)",color:"#FCA5A5",border:"1px solid rgba(239,68,68,0.25)"},children:[e.jsx(P,{className:"w-4 h-4"})," ",b]}),x?e.jsx("div",{className:"flex justify-center py-12",children:e.jsx(F,{className:"w-6 h-6 animate-spin text-slate-400"})}):h.length===0?e.jsxs("div",{className:"text-center py-12 text-sm",style:{color:"var(--page-text-muted)"},children:[e.jsx(q,{className:"w-10 h-10 mx-auto mb-3 opacity-30"}),e.jsx("p",{children:"Nenhuma instância configurada."})]}):e.jsx("div",{className:"space-y-2",children:h.map(a=>{const n=_[a.state]||_.unknown,m=n.icon;return e.jsxs("div",{className:"card p-4 flex items-center justify-between flex-wrap gap-3",children:[e.jsxs("div",{className:"flex items-center gap-3 min-w-0",children:[e.jsxs("div",{className:`px-2 py-1 rounded-lg text-[10px] font-bold flex items-center gap-1 ${n.className}`,children:[e.jsx(m,{className:"w-3 h-3"})," ",n.label]}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-mono font-medium truncate",style:{color:"var(--page-text)"},children:a.instanceName}),e.jsxs("p",{className:"text-xs",style:{color:"var(--page-text-muted)"},children:[a.number||"sem número",a.warmupDay&&e.jsxs(e.Fragment,{children:[" · Warm-up dia ",a.warmupDay," · ",a.sentToday,"/",a.dailyCap||"?"," hoje"]})]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[a.quarantined&&e.jsxs(e.Fragment,{children:[e.jsxs("span",{className:"px-2 py-1 rounded-lg text-[10px] font-bold bg-red-500/15 text-red-400 flex items-center gap-1",children:[e.jsx(Y,{className:"w-3 h-3"})," Quarentena: ",a.quarantineReason||"desconhecido"]}),e.jsx("button",{onClick:()=>D(a.id),className:"p-2 rounded-lg hover:bg-emerald-500/10",title:"Tirar da quarentena",children:e.jsx(Z,{className:"w-4 h-4 text-emerald-400"})})]}),e.jsx("button",{onClick:()=>k(a.id,a.instanceName),className:"p-2 rounded-lg hover:bg-slate-800/50",title:"Mostrar QR",children:e.jsx(ee,{className:"w-4 h-4 text-slate-400"})}),e.jsx("button",{onClick:()=>I(a.id),className:"p-2 rounded-lg hover:bg-slate-800/50",title:"Atualizar status",children:e.jsx(ae,{className:"w-4 h-4 text-slate-400"})}),e.jsx("button",{onClick:()=>f(a.id),className:"p-2 rounded-lg hover:bg-amber-500/10",title:"Logout",children:e.jsx(se,{className:"w-4 h-4 text-amber-400"})}),e.jsx("button",{onClick:()=>U(a.id),className:"p-2 rounded-lg hover:bg-red-500/10",title:"Apagar",children:e.jsx(te,{className:"w-4 h-4 text-red-400"})})]})]},a.id)})}),e.jsx(Q,{open:y,onClose:()=>g(!1),title:"Nova Instância WhatsApp",description:"O número será associado ao Evolution API. Você precisará escanear o QR no celular após criar.",size:"md",children:e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-slate-400 mb-1 block",children:"Número (com DDI)"}),e.jsx("input",{value:v,onChange:a=>A(a.target.value),placeholder:"5511999999999",className:"input w-full"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-slate-400 mb-1 block",children:"Rótulo (opcional)"}),e.jsx("input",{value:w,onChange:a=>R(a.target.value),placeholder:"Outreach principal",className:"input w-full"})]})]}),e.jsxs("div",{className:"flex gap-3 mt-5",children:[e.jsx("button",{onClick:()=>g(!1),className:"flex-1 px-4 py-2.5 rounded-xl border border-slate-700 text-sm text-slate-300",children:"Cancelar"}),e.jsxs("button",{onClick:E,disabled:N||!v,className:"flex-1 px-4 py-2.5 rounded-xl text-sm font-semibold text-white flex items-center justify-center gap-2",style:{background:"#25D366"},children:[N?e.jsx(F,{className:"w-4 h-4 animate-spin"}):e.jsx(W,{className:"w-4 h-4"}),"Provisionar"]})]})]})}),e.jsx(Q,{open:!!o,onClose:()=>j(null),title:"Escaneie no WhatsApp",description:o==null?void 0:o.instanceName,size:"md",bodyClassName:"text-center",children:o&&e.jsxs(e.Fragment,{children:[o.base64?e.jsx("img",{src:o.base64.startsWith("data:")?o.base64:`data:image/png;base64,${o.base64}`,alt:"QR Code",className:"w-64 h-64 mx-auto bg-white rounded-xl p-2"}):e.jsx("div",{className:"h-64 flex items-center justify-center text-sm text-slate-400",children:'QR não disponível. Aguarde alguns segundos e clique em "Atualizar QR".'}),e.jsxs("div",{className:"flex gap-3 mt-5",children:[e.jsx("button",{onClick:()=>k(o.id,o.instanceName),className:"flex-1 px-4 py-2.5 rounded-xl border border-slate-700 text-sm text-slate-300",children:"Atualizar QR"}),e.jsx("button",{onClick:()=>j(null),className:"flex-1 px-4 py-2.5 rounded-xl text-sm font-semibold text-white",style:{background:"#25D366"},children:"Fechar"})]})]})})]})}function ce(){const[s,i]=l.useState(null),[h,p]=l.useState(!0),[x,r]=l.useState(!1),[b,c]=l.useState(null),[y,g]=l.useState(null),[N,S]=l.useState(""),[v,A]=l.useState(""),[w,R]=l.useState(""),[o,j]=l.useState(""),[d,E]=l.useState(""),[k,I]=l.useState(""),[f,U]=l.useState(!1),[D,a]=l.useState({}),[n,m]=l.useState(!1),O=l.useCallback(async()=>{p(!0),c(null);try{const t=await u.waGetConfig();i(t),S(t.evolutionBaseUrl||""),A(t.publicApiUrl||""),R(t.publicOptoutUrl||""),j(""),E(""),I(""),a(t.features||{}),m(t.dryRun||!1)}catch(t){c((t==null?void 0:t.message)||"Falha ao carregar config")}finally{p(!1)}},[]);l.useEffect(()=>{O()},[O]);const B=async()=>{r(!0),c(null),g(null);try{const t={};if(N&&(t.evolutionBaseUrl=N.trim()),v&&(t.publicApiUrl=v.trim()),w&&(t.publicOptoutUrl=w.trim()),o&&(t.evolutionGlobalKey=o),d&&(t.evolutionWebhookSecret=d),k&&(t.phoneSalt=k),t.features=D,t.dryRun=n,Object.keys(t).length===0){c("Nada para salvar — preencha ao menos um c
1ampo."),r(!1);return}await u.waSaveConfig(t),g("Configuração salva. As mudanças entram em vigor em até 60s."),j(""),E(""),I(""),await O()}catch(t){c((t==null?void 0:t.message)||"Falha ao salvar")}finally{r(!1)}},z=async t=>{if(!(t&&!(s!=null&&s.ready)&&!confirm("Faltam campos obrigatórios (URL, chave, secret, salt, public API URL). Tem certeza que quer ativar agora? Sem todos preenchidos, o módulo vai falhar nas chamadas reais."))){r(!0),c(null);try{await u.waSaveConfig({enabled:t}),g(t?"Módulo ATIVADO. Cron começa a processar a fila em até 60s (respeitando warm-up + jitter).":"Módulo DESATIVADO. Sender para imediatamente; webhooks retornam 503."),await O()}catch(C){c((C==null?void 0:C.message)||"Falha ao alternar")}finally{r(!1)}}};return h?e.jsx("div",{className:"card p-4 flex justify-center",children:e.jsx(F,{className:"w-5 h-5 animate-spin text-slate-400"})}):e.jsxs("div",{className:"card p-5",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 flex-wrap mb-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(le,{className:"w-5 h-5",style:{color:"var(--page-text-muted)"}}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-base font-semibold",style:{color:"var(--page-text)"},children:"Configuração de Conexão"}),e.jsx("p",{className:"text-xs mt-0.5",style:{color:"var(--page-text-muted)"},children:"Parâmetros para conectar à Evolution API self-hosted. Mudanças refletem em até 60s."})]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"text-xs font-medium",style:{color:s!=null&&s.enabled?"#22c55e":"var(--page-text-muted)"},children:s!=null&&s.enabled?"ATIVO":"INATIVO"}),e.jsxs("button",{onClick:()=>z(!(s!=null&&s.enabled)),disabled:x,className:"flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-semibold disabled:opacity-50",style:{background:s!=null&&s.enabled?"#dc2626":"#22c55e",color:"#ffffff"},children:[e.jsx(ne,{className:"w-4 h-4"}),s!=null&&s.enabled?"Desativar":"Ativar"]})]})]}),!(s!=null&&s.ready)&&e.jsxs("div",{className:"rounded-lg p-3 mb-4 text-xs flex items-center gap-2",style:{background:"rgba(245,158,11,0.08)",color:"#FCD34D",border:"1px solid rgba(245,158,11,0.25)"},children:[e.jsx(P,{className:"w-4 h-4 flex-shrink-0"}),"Configuração incompleta — preencha todos os campos abaixo antes de ativar."]}),(s==null?void 0:s.ready)&&(s==null?void 0:s.enabled)&&e.jsxs("div",{className:"rounded-lg p-3 mb-4 text-xs flex items-center gap-2",style:{background:"rgba(34,197,94,0.08)",color:"#86EFAC",border:"1px solid rgba(34,197,94,0.25)"},children:[e.jsx(L,{className:"w-4 h-4 flex-shrink-0"}),"Módulo ativo. Sender cron rodando, webhook validando assinaturas, opt-out aceitando submissões."]}),b&&e.jsxs("div",{className:"rounded-lg p-3 mb-4 text-xs flex items-center gap-2",style:{background:"rgba(239,68,68,0.08)",color:"#FCA5A5"},children:[e.jsx(P,{className:"w-4 h-4"})," ",b]}),y&&e.jsxs("div",{className:"rounded-lg p-3 mb-4 text-xs flex items-center gap-2",style:{background:"rgba(34,197,94,0.08)",color:"#86EFAC"},children:[e.jsx(L,{className:"w-4 h-4"})," ",y]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3",children:[e.jsx(M,{label:"Evolution API URL",value:N,onChange:S,placeholder:"https://evolution-api-xxx-uc.a.run.app",help:"URL privada do Cloud Run da Evolution"}),e.jsx(M,{label:"Cloud Functions API URL",value:v,onChange:A,placeholder:"https://api-xxx-uc.a.run.app",help:"Para a Evolution chamar nosso webhook"}),e.jsx(M,{label:"URL pública de opt-out",value:w,onChange:R,placeholder:"https://www.sentinel365.ai/whatsapp/optout",help:"Footer das mensagens insere link com hash do telefone"}),e.jsx(T,{label:"Evolution Global API Key",existingMask:s==null?void 0:s.evolutionGlobalKeyMasked,value:o,onChange:j,show:f,help:"Da config da Evolution; gera instância e gerencia"}),e.jsx(T,{label:"Webhook Secret (HMAC)",existingMask:s==null?void 0:s.evolutionWebhookSecretMasked,value:d,onChange:E,show:f,help:"Compartilhado: Evolution → Sentinel autentica via Bearer"}),e.jsx(T,{label:"Phone Hash Salt",existingMask:s==null?void 0:s.phoneSaltMasked,value:k,onChange:I,show:f,help:"Salt para SHA-256 dos telefones na lista de opt-out"})]}),e.jsxs("div",{className:"mt-6 pt-4",style:{borderTop:"1px solid var(--border-primary)"},children:[e.jsx("h3",{className:"text-sm font-semibold mb-1",style:{color:"var(--page-text)"},children:"Notificações transacionais"}),e.jsx("p",{className:"text-xs mb-3",style:{color:"var(--page-text-muted)"},children:"Liga/desliga cada tipo individualmente. Desligado = sender pula a mensagem ao tentar enviar."}),e.jsx("div",{className:"grid grid-cols-2 gap-2 text-xs",children:[{key:"dispatch_assigned",label:"Novo despacho ao motorista"},{key:"dispatch_status",label:"Status ao embarcador"},{key:"document_expiring",label:"Vencimento de docs (CNH, etc.)"},{key:"compliance_alert",label:"Alerta de compliance (CIOT, MDF-e)"},{key:"invoice_reminder",label:"Cobrança Stripe"},{key:"onboarding_step",label:"Onboarding conversacional"},{key:"bot_reply",label:"Bot motorista (Gemini)"},{key:"nps_survey",label:"NPS pós-entrega"},{key:"operational_alert",label:"Alertas operacionais"},{key:"pod_request",label:"Solicitação de POD"}].map(t=>{const C=D[t.key]!==!1;return e.jsxs("label",{className:"flex items-center gap-2 px-2 py-1.5 rounded hover-surface cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:C,onChange:G=>
1a({...D,[t.key]:G.target.checked})}),e.jsx("span",{style:{color:"var(--page-text)"},children:t.label})]},t.key)})}),e.jsxs("div",{className:"mt-3 pt-3 flex items-center gap-2 text-xs",style:{borderTop:"1px dashed var(--border-primary)"},children:[e.jsx("input",{type:"checkbox",id:"dryRun",checked:n,onChange:t=>m(t.target.checked)}),e.jsxs("label",{htmlFor:"dryRun",className:"cursor-pointer",style:{color:"var(--page-text)"},children:[e.jsx("strong",{children:"Dry-run mode"}),": sender simula envio (marca como sent + log) mas NÃO chama Evolution. Útil pra testes."]})]})]}),e.jsxs("div",{className:"flex items-center justify-between mt-4 pt-4",style:{borderTop:"1px solid var(--border-primary)"},children:[e.jsxs("button",{type:"button",onClick:()=>U(!f),className:"flex items-center gap-1.5 text-xs",style:{color:"var(--page-text-muted)"},children:[f?e.jsx(oe,{className:"w-3 h-3"}):e.jsx(re,{className:"w-3 h-3"}),f?"Ocultar campos":"Mostrar campos para edição"]}),e.jsxs("button",{onClick:B,disabled:x,className:"flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-semibold text-white disabled:opacity-50",style:{background:"#3B82F6"},children:[x?e.jsx(F,{className:"w-4 h-4 animate-spin"}):e.jsx(ie,{className:"w-4 h-4"}),"Salvar configuração"]})]})]})}function M({label:s,value:i,onChange:h,placeholder:p,help:x}){return e.jsxs("label",{className:"block",children:[e.jsx("span",{className:"text-xs font-medium",style:{color:"var(--page-text)"},children:s}),e.jsx("input",{type:"text",value:i,onChange:r=>h(r.target.value),placeholder:p,className:"input mt-1 w-full text-sm"}),x&&e.jsx("span",{className:"text-[10px] mt-1 block",style:{color:"var(--page-text-muted)"},children:x})]})}function T({label:s,existingMask:i,value:h,onChange:p,show:x,help:r}){const b=!!i,c=b?`${i} (deixe vazio p/ manter)`:"não configurado";return e.jsxs("label",{className:"block",children:[e.jsxs("span",{className:"text-xs font-medium",style:{color:"var(--page-text)"},children:[s,b&&e.jsx("span",{className:"ml-1.5 text-[10px] font-normal",style:{color:"#22c55e"},children:"● configurado"})]}),e.jsx("input",{type:x?"text":"password",value:h,onChange:y=>p(y.target.value),placeholder:c,autoComplete:"off",className:"input mt-1 w-full text-sm font-mono"}),r&&e.jsx("span",{className:"text-[10px] mt-1 block",style:{color:"var(--page-text-muted)"},children:r})]})}export{he as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.