Adicionado endpoint e botao para Testar Envio de Template do WhatsApp
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 58s
Details
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 58s
Details
This commit is contained in:
parent
4cc23a9e5b
commit
3b0313d5c0
54
server.ts
54
server.ts
|
|
@ -2562,6 +2562,60 @@ app.post('/api/admin/reply-message', authenticateToken, requireAdmin, async (req
|
|||
}
|
||||
});
|
||||
|
||||
// Admin: Test WhatsApp template message
|
||||
app.post('/api/admin/whatsapp/test-template', authenticateToken, requireAdmin, async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
const { templateId } = req.body;
|
||||
if (!templateId) return res.status(400).json({ error: 'templateId é obrigatório' });
|
||||
|
||||
const adminUser = await prisma.user.findUnique({ where: { id: req.user!.id } });
|
||||
if (!adminUser?.whatsapp) {
|
||||
return res.status(400).json({ error: 'Você precisa ter um número de WhatsApp configurado no seu perfil para receber o teste.' });
|
||||
}
|
||||
|
||||
const settings = await prisma.systemSettings.findFirst();
|
||||
let templateStr = '';
|
||||
|
||||
switch(templateId) {
|
||||
case 'whatsappTemplatePayment':
|
||||
templateStr = settings?.whatsappTemplatePayment || '';
|
||||
break;
|
||||
case 'whatsappTemplateWelcome':
|
||||
templateStr = settings?.whatsappTemplateWelcome || '';
|
||||
break;
|
||||
case 'whatsappTemplateNewContent':
|
||||
templateStr = settings?.whatsappTemplateNewContent || '';
|
||||
break;
|
||||
case 'whatsappTemplatePromo':
|
||||
templateStr = settings?.whatsappTemplatePromo || '';
|
||||
break;
|
||||
}
|
||||
|
||||
if (!templateStr) {
|
||||
return res.status(400).json({ error: 'Este modelo de mensagem ainda não foi configurado ou está vazio.' });
|
||||
}
|
||||
|
||||
const firstName = adminUser.name.split(' ')[0];
|
||||
const msg = processTemplate(templateStr, {
|
||||
nome: firstName,
|
||||
curso: 'Curso de Informática (TESTE)',
|
||||
plano: 'Plano Premium (TESTE)',
|
||||
valor: 'R$ 49,90'
|
||||
});
|
||||
|
||||
const success = await sendWhatsappNotification(adminUser.whatsapp, msg);
|
||||
|
||||
if (success) {
|
||||
res.json({ success: true, message: 'Mensagem de teste enviada com sucesso para o seu número!' });
|
||||
} else {
|
||||
res.status(500).json({ error: 'Falha ao enviar mensagem pela Evolution API. Verifique a conexão e o status da instância.' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error testing template:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Admin: Broadcast WhatsApp message to all students with anti-spam delay
|
||||
app.post('/api/admin/whatsapp/broadcast', authenticateToken, requireAdmin, async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ export default function AdminMessagesView() {
|
|||
const [activeTemplateModal, setActiveTemplateModal] = useState<string | null>(null);
|
||||
const [currentTemplateText, setCurrentTemplateText] = useState('');
|
||||
const [isSavingTemplate, setIsSavingTemplate] = useState(false);
|
||||
const [isTestingTemplate, setIsTestingTemplate] = useState<string | null>(null);
|
||||
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
|
|
@ -202,6 +203,30 @@ export default function AdminMessagesView() {
|
|||
}
|
||||
};
|
||||
|
||||
const handleTestTemplate = async (templateId: string, e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
setIsTestingTemplate(templateId);
|
||||
try {
|
||||
const token = localStorage.getItem('admin_token');
|
||||
const res = await fetch('/api/admin/whatsapp/test-template', {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ templateId })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
setAlertModal({isOpen: true, title: 'Enviado! 📱', message: data.message});
|
||||
} else {
|
||||
setAlertModal({isOpen: true, title: 'Erro no Teste', message: data.error, isError: true});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error testing template:', error);
|
||||
setAlertModal({isOpen: true, title: 'Erro', message: 'Erro interno ao testar template.', isError: true});
|
||||
} finally {
|
||||
setIsTestingTemplate(null);
|
||||
}
|
||||
};
|
||||
|
||||
const insertEmoji = (emoji: string, isForBroadcast = false) => {
|
||||
const ref = isForBroadcast ? broadcastRef : textareaRef;
|
||||
const setter = isForBroadcast ? setBroadcastText : setCurrentTemplateText;
|
||||
|
|
@ -452,11 +477,30 @@ export default function AdminMessagesView() {
|
|||
<span key={tag} className="text-[9px] bg-blue-500/10 text-blue-300 px-1.5 py-0.5 rounded font-mono">{tag}</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-2 flex items-center gap-1.5">
|
||||
<div className={`w-2 h-2 rounded-full ${settings?.[t.id] ? 'bg-green-500' : 'bg-zinc-600'}`}></div>
|
||||
<span className={`text-[10px] font-bold ${settings?.[t.id] ? 'text-green-400' : 'text-zinc-500'}`}>
|
||||
{settings?.[t.id] ? 'Ativo' : 'Não configurado'}
|
||||
</span>
|
||||
<div className="mt-3 flex items-center justify-between">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className={`w-2 h-2 rounded-full ${settings?.[t.id] ? 'bg-green-500' : 'bg-zinc-600'}`}></div>
|
||||
<span className={`text-[10px] font-bold ${settings?.[t.id] ? 'text-green-400' : 'text-zinc-500'}`}>
|
||||
{settings?.[t.id] ? 'Ativo' : 'Não configurado'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{settings?.[t.id] && (
|
||||
<button
|
||||
onClick={(e) => handleTestTemplate(t.id, e)}
|
||||
disabled={isTestingTemplate === t.id}
|
||||
className="bg-zinc-800 hover:bg-zinc-700 text-zinc-300 px-3 py-1 rounded text-[10px] font-bold flex items-center gap-1 transition-colors"
|
||||
>
|
||||
{isTestingTemplate === t.id ? (
|
||||
<div className="w-3 h-3 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||||
) : (
|
||||
<>
|
||||
<Send className="w-3 h-3" />
|
||||
<span>Testar Envio</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
|
|
|||
Loading…
Reference in New Issue