diff --git a/backend/server.js b/backend/server.js
index 8d81c3b..46a8c57 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -9450,12 +9450,22 @@ app.get('/api/superadmin/secretaria-desligamentos', superadminGuard, async (req,
const email = rows[0]?.email;
if (!email) return res.json({ configurado: true, log: [] });
const limit = Math.min(500, Math.max(1, parseInt(String(req.query.limit || '150'), 10)));
- const r = await fetch(`${cfg.motorUrl}/api/ext/v1/secretaria/session-power/log?limit=${limit}`, {
- headers: { 'x-nw-key': cfg.integrationKey, 'x-nw-email': email },
- });
- if (!r.ok) return res.status(502).json({ error: 'Motor indisponível', status: r.status });
- const log = await r.json();
- res.json({ configurado: true, log: Array.isArray(log) ? log : [] });
+ const headers = { 'x-nw-key': cfg.integrationKey, 'x-nw-email': email };
+ const pull = async (path, escopo) => {
+ try {
+ const r = await fetch(`${cfg.motorUrl}/api/ext/v1${path}?limit=${limit}`, { headers });
+ if (!r.ok) return [];
+ const j = await r.json();
+ return (Array.isArray(j) ? j : []).map((e) => ({ ...e, escopo }));
+ } catch { return []; }
+ };
+ // "global" = botão que desativa a Secretária para TODOS os chats; "sessao" = por número.
+ const [glob, sess] = await Promise.all([
+ pull('/secretaria/power/log', 'global'),
+ pull('/secretaria/session-power/log', 'sessao'),
+ ]);
+ const log = [...glob, ...sess].sort((a, b) => new Date(b.at) - new Date(a.at));
+ res.json({ configurado: true, log });
} catch (err) { res.status(500).json({ error: err.message }); }
});
diff --git a/frontend/views/SuperAdminView.tsx b/frontend/views/SuperAdminView.tsx
index ab166d0..e619092 100644
--- a/frontend/views/SuperAdminView.tsx
+++ b/frontend/views/SuperAdminView.tsx
@@ -113,8 +113,8 @@ const TabSecretaria: React.FC = () => {
-
Secretária IA — motivos de desligamento
-
Contexto GERAL para identificar bugs/estratégias no atendimento da IA e corrigir. Sem dados das clínicas (nem número, nem quem). {totalOff > 0 && `${totalOff} desligamento(s).`}
+
Secretária IA — motivos de desativação
+
Motivos de desativar a Secretária — para TODOS os chats (global) ou por sessão. Contexto GERAL p/ identificar bugs/estratégias no atendimento e corrigir. Sem dados das clínicas. {totalOff > 0 && `${totalOff} desativação(ões).`}
@@ -130,6 +130,7 @@ const TabSecretaria: React.FC = () => {
Ação
+ Escopo
Quando
Motivo
@@ -142,6 +143,11 @@ const TabSecretaria: React.FC = () => {
? Ligou
: Desligou }
+
+ {l.escopo === 'global'
+ ? Todos os chats
+ : Uma sessão }
+
{fmt(l.at)}
{l.reason || — }
diff --git a/frontend/views/newwhats/SecretariaView.tsx b/frontend/views/newwhats/SecretariaView.tsx
index 472b8c4..9f029b9 100644
--- a/frontend/views/newwhats/SecretariaView.tsx
+++ b/frontend/views/newwhats/SecretariaView.tsx
@@ -1617,27 +1617,41 @@ export function SecretariaView(props: { onNavigate?: (view: string) => void } =
const [showFila, setShowFila] = useState(false)
const [pendCount, setPendCount] = useState(0)
- // Liga/desliga GLOBAL da Secretária (kill-switch auto_reply) — todos, sem timer
+ // Liga/desliga GLOBAL da Secretária (kill-switch auto_reply) — todos os chats.
+ // Ao desligar exige MOTIVO (contexto geral p/ o super admin) e guarda histórico.
const [secOn, setSecOn] = useState(true)
const [powerBusy, setPowerBusy] = useState(false)
+ const [powerModal, setPowerModal] = useState(false)
+ const [powerReason, setPowerReason] = useState('')
+ const [powerData, setPowerData] = useState(null)
+ const [powerErr, setPowerErr] = useState(null)
// Boot
useEffect(() => {
store.loadAgents()
store.loadCalendar()
store.loadNumbers()
- secPowerApi.get().then((r) => setSecOn(r.enabled)).catch(() => {})
+ secPowerApi.get().then((r) => { setSecOn(r.enabled); setPowerData(r) }).catch(() => {})
}, [])
- const handleTogglePower = useCallback(async () => {
+ const openPowerModal = useCallback(() => {
+ setPowerErr(null); setPowerReason('')
+ secPowerApi.get().then((r) => { setSecOn(r.enabled); setPowerData(r) }).catch(() => {})
+ setPowerModal(true)
+ }, [])
+
+ const confirmTogglePower = useCallback(async () => {
if (powerBusy) return
const proximo = !secOn
- // Ao DESLIGAR (para todos os chats, sem retorno automático), confirma.
- if (!proximo && !window.confirm('Desligar a Secretária para TODOS os chats? Ela para de responder e só volta quando você ligar de novo.')) return
- setPowerBusy(true)
- try { const r = await secPowerApi.set(proximo); setSecOn(r.enabled) }
- catch { /* mantém estado atual */ } finally { setPowerBusy(false) }
- }, [secOn, powerBusy])
+ if (!proximo && !powerReason.trim()) { setPowerErr('Escreva o motivo para desativar.'); return }
+ setPowerBusy(true); setPowerErr(null)
+ try {
+ const userName = (() => { try { return JSON.parse(localStorage.getItem('SCOREODONTO_USER_DATA') || '{}')?.nome || 'Usuário' } catch { return 'Usuário' } })()
+ const r = await secPowerApi.set(proximo, powerReason.trim(), userName)
+ setSecOn(r.enabled); setPowerReason('')
+ const fresh = await secPowerApi.get().catch(() => null); if (fresh) setPowerData(fresh)
+ } catch (e: any) { setPowerErr(e?.message || 'Não foi possível alterar.') } finally { setPowerBusy(false) }
+ }, [secOn, powerBusy, powerReason])
// Contagem de pendências para o badge (dono) — atualiza ao abrir e a cada 5 min.
useEffect(() => {
@@ -1710,7 +1724,61 @@ export function SecretariaView(props: { onNavigate?: (view: string) => void } =
{/* Thin Nav */}
setShowHelp(true)} onBack={() => props.onNavigate?.('dashboard')}
onPendencias={ehDono ? () => setShowPendencias(true) : undefined} pendenciasBadge={pendCount}
- secOn={secOn} onTogglePower={handleTogglePower} />
+ secOn={secOn} onTogglePower={openPowerModal} />
+
+ {powerModal && (
+ setPowerModal(false)}>
+
e.stopPropagation()}>
+
+
+
+
+
Secretária — todos os chats
+
{secOn ? 'Ativa' : 'Desativada'} · vale para TODAS as sessões
+
+
+
setPowerModal(false)} className="p-2 hover:bg-gray-100 rounded-xl text-gray-400">
+
+ {powerErr &&
{powerErr}
}
+
+ {!secOn && powerData?.reason && (
+
Desativada. Motivo: {powerData.reason}
+ )}
+ {secOn && (
+
+
Motivo para desativar (todos os chats)
+
+ )}
+
+ {powerBusy ? : }
+ {secOn ? 'Desativar (todos os chats)' : 'Ativar (todos os chats)'}
+
+ {!!powerData?.history?.length && (
+
+
Histórico
+
+ {powerData.history.map((h: any, i: number) => (
+
+
+
+
{h.enabled ? 'Ativou' : 'Desativou'}
+
· {h.by || '—'} · {h.at ? new Date(h.at).toLocaleString('pt-BR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }) : ''}
+ {!h.enabled && h.reason &&
{h.reason}
}
+
+
+ ))}
+
+
+ )}
+
+
+
+ )}
{ehDono && (
<>
diff --git a/frontend/views/newwhats/services/secretariaApi.ts b/frontend/views/newwhats/services/secretariaApi.ts
index 05104a5..1f8e556 100644
--- a/frontend/views/newwhats/services/secretariaApi.ts
+++ b/frontend/views/newwhats/services/secretariaApi.ts
@@ -86,8 +86,8 @@ export interface CalendarSlot {
// ─── Power (liga/desliga global — kill-switch auto_reply) ──────────────────────
export const secPowerApi = {
- get: () => api.get<{ enabled: boolean }>(`${BASE}/power`).then((r) => r.data),
- set: (enabled: boolean) => api.post<{ enabled: boolean }>(`${BASE}/power`, { enabled }).then((r) => r.data),
+ get: () => api.get(`${BASE}/power`).then((r) => r.data),
+ set: (enabled: boolean, reason = '', by = '') => api.post<{ enabled: boolean }>(`${BASE}/power`, { enabled, reason, by }).then((r) => r.data),
}
// Liga/desliga a Secretária POR SESSÃO (instância atual do /wa-inbox).