feat(settings): selo Conta Business, aviso de re-scan ao trocar API, log de erro de botões

- Detecta WhatsApp Business (app) via getBusinessProfile no pós-conexão e
  persiste em instances.isBusiness; painel mostra "Conta Business: sim/não"
  (com nota Business App ≠ Business API).
- Painel avisa que trocar de API desconecta e exige escanear o QR novamente,
  com confirmação antes de aplicar a troca.
- sendRichMessage agora monitora e loga erros especificamente quando a mensagem
  tem botões/lista/carrossel (diagnóstico de rejeição de interativos por engine).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Deploy Agent
2026-06-28 05:45:34 +02:00
parent c801d8d820
commit 43f519e7aa
4 changed files with 88 additions and 3 deletions
@@ -1,5 +1,5 @@
import React, { useEffect, useState, useCallback } from 'react';
import { ShieldCheck, LayoutGrid, Check, Loader2, Tag } from 'lucide-react';
import { ShieldCheck, LayoutGrid, Check, Loader2, Tag, AlertTriangle, Briefcase } from 'lucide-react';
interface SettingsPanelProps {
instanceId: string | null;
@@ -28,6 +28,7 @@ const ENGINES: {
export default function SettingsPanel({ instanceId }: SettingsPanelProps) {
const [engine, setEngine] = useState<string | null>(null);
const [isBusiness, setIsBusiness] = useState<boolean | null>(null);
const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
@@ -56,6 +57,7 @@ export default function SettingsPanel({ instanceId }: SettingsPanelProps) {
.then((list) => {
const inst = Array.isArray(list) ? list.find((i: any) => i.id === instanceId) : null;
setEngine(inst?.engine ?? null);
setIsBusiness(inst ? !!inst.isBusiness : null);
})
.catch(() => {})
.finally(() => setLoading(false));
@@ -63,6 +65,12 @@ export default function SettingsPanel({ instanceId }: SettingsPanelProps) {
const selectEngine = useCallback(async (value: string) => {
if (!instanceId || saving || value === engine) return;
// Trocar de engine invalida a sessão (credenciais não migram entre APIs):
// confirma porque exige escanear o QR Code novamente.
if (typeof window !== 'undefined' && !window.confirm(
'Trocar de API vai DESCONECTAR a sessão atual.\n\n' +
'Você precisará escanear o QR Code novamente para reconectar. Continuar?'
)) return;
setSaving(value);
setError(null);
try {
@@ -88,7 +96,14 @@ export default function SettingsPanel({ instanceId }: SettingsPanelProps) {
<div className="relative z-[1] flex-1 h-full overflow-y-auto bg-[#f0f2f5] p-6 md:p-10">
<div className="max-w-2xl mx-auto">
<h1 className="text-3xl font-light text-[#41525d] mb-2">Configurações</h1>
<p className="text-base text-[#667781] mb-8">Escolha a API de conexão do WhatsApp para esta instância.</p>
<p className="text-base text-[#667781] mb-4">Escolha a API de conexão do WhatsApp para esta instância.</p>
<div className="flex items-start gap-3 rounded-xl bg-amber-50 border border-amber-200 p-4 mb-6">
<AlertTriangle className="w-5 h-5 text-amber-500 shrink-0 mt-0.5" />
<p className="text-sm text-[#5b4b1f]">
Trocar de API <strong>desconecta a sessão</strong> será necessário <strong>escanear o QR Code novamente</strong> para reconectar.
</p>
</div>
{!instanceId && (
<p className="text-base text-[#667781] mb-6">Selecione uma instância primeiro.</p>
@@ -136,6 +151,24 @@ export default function SettingsPanel({ instanceId }: SettingsPanelProps) {
{loading && <p className="text-sm text-[#8696a0] mb-4">Carregando configuração atual</p>}
{error && <p className="text-sm text-red-500 mb-4">{error}</p>}
{/* ── Conta Business ──────────────────────────────────────── */}
<div className="rounded-2xl border-2 border-[#e9edef] bg-white p-8 mb-6">
<div className="flex items-center gap-4">
<div className="w-14 h-14 rounded-2xl bg-[#f0f2f5] flex items-center justify-center">
<Briefcase className="w-8 h-8 text-[#54656f]" />
</div>
<div className="flex-1">
<h2 className="text-2xl font-semibold text-[#111b21]">Conta Business</h2>
<p className="text-xl font-medium text-[#41525d] mt-1">
{isBusiness === null ? '—' : isBusiness ? 'Sim (WhatsApp Business)' : 'Não (conta pessoal)'}
</p>
<p className="text-xs text-[#8696a0] mt-1">
Business App Business API botões são garantidos na Business API oficial.
</p>
</div>
</div>
</div>
{/* ── Versão ──────────────────────────────────────────────── */}
<div className="rounded-2xl border-2 border-[#e9edef] bg-white p-8">
<div className="flex items-center gap-4">