From 417c24089b002b855fe86f976780f43ffb0b4b6a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 24 May 2025 14:02:02 +0000 Subject: [PATCH] Run SQL to add WhatsApp columns Adds `instancia_zap` and `status_instancia` columns to the `usuarios` table. --- src/components/ui/alert.tsx | 1 + .../whatsapp/CreateInstanceForm.tsx | 35 ++-- .../whatsappGroups/CreateGroupForm.tsx | 190 ++++++++++++------ src/integrations/supabase/types.ts | 6 + src/services/whatsAppGroupCreationService.ts | 81 ++++++++ src/services/whatsAppInstanceService.ts | 58 ++++++ 6 files changed, 299 insertions(+), 72 deletions(-) create mode 100644 src/services/whatsAppGroupCreationService.ts create mode 100644 src/services/whatsAppInstanceService.ts diff --git a/src/components/ui/alert.tsx b/src/components/ui/alert.tsx index 41fa7e0..c5acc6f 100644 --- a/src/components/ui/alert.tsx +++ b/src/components/ui/alert.tsx @@ -1,3 +1,4 @@ + import * as React from "react" import { cva, type VariantProps } from "class-variance-authority" diff --git a/src/components/whatsapp/CreateInstanceForm.tsx b/src/components/whatsapp/CreateInstanceForm.tsx index 3ce88bc..4626e6b 100644 --- a/src/components/whatsapp/CreateInstanceForm.tsx +++ b/src/components/whatsapp/CreateInstanceForm.tsx @@ -7,6 +7,7 @@ import { Label } from '@/components/ui/label'; import { MessageCircle } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; import { createWhatsAppInstance } from '@/services/whatsAppService'; +import { updateUserWhatsAppInstance } from '@/services/whatsAppInstanceService'; import { WhatsAppInstance } from '@/types/whatsAppTypes'; interface CreateInstanceFormProps { @@ -20,23 +21,19 @@ const CreateInstanceForm = ({ }: CreateInstanceFormProps) => { const { toast } = useToast(); const [loading, setLoading] = useState(false); - const [instanceName, setInstanceName] = useState(initialInstanceName || ''); const [phoneNumber, setPhoneNumber] = useState(''); const currentUserId = localStorage.getItem('userId') || ''; + const userEmail = localStorage.getItem('userEmail') || ''; - // Update instance name if initial value changes - useEffect(() => { - if (initialInstanceName) { - setInstanceName(initialInstanceName); - } - }, [initialInstanceName]); + // Nome da instância será sempre o email do usuário + const instanceName = userEmail; const handleCreateInstance = async () => { // Validate form fields - if (!instanceName.trim()) { + if (!userEmail) { toast({ title: "Erro", - description: "O nome da instância é obrigatório", + description: "Email do usuário não encontrado. Faça login novamente.", variant: "destructive", }); return; @@ -82,6 +79,15 @@ const CreateInstanceForm = ({ console.log('New instance created:', newInstance); + // Atualizar o banco de dados com a instância + try { + await updateUserWhatsAppInstance(userEmail, instanceName, 'desconectado'); + console.log('Instância salva no banco de dados'); + } catch (dbError) { + console.error('Erro ao salvar instância no banco:', dbError); + // Não bloquear o processo se falhar ao salvar no banco + } + // Notify parent component about the new instance onInstanceCreated(newInstance); @@ -122,11 +128,12 @@ const CreateInstanceForm = ({ setInstanceName(e.target.value)} - placeholder="Digite um nome para a instância" - required + disabled + className="bg-gray-100" /> -

O nome será usado para identificar esta conexão

+

+ O nome da instância será automaticamente seu email de login +

@@ -144,7 +151,7 @@ const CreateInstanceForm = ({ diff --git a/src/components/whatsappGroups/CreateGroupForm.tsx b/src/components/whatsappGroups/CreateGroupForm.tsx index 912e298..e4b4a1a 100644 --- a/src/components/whatsappGroups/CreateGroupForm.tsx +++ b/src/components/whatsappGroups/CreateGroupForm.tsx @@ -1,11 +1,14 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -import { Loader2, Plus } from 'lucide-react'; +import { Loader2, Plus, AlertCircle } from 'lucide-react'; +import { Alert, AlertDescription } from '@/components/ui/alert'; import { cadastrarGrupoWhatsApp } from '@/services/gruposWhatsAppService'; +import { getUserWhatsAppInstance } from '@/services/whatsAppInstanceService'; +import { createWhatsAppGroup, updateGroupRemoteJid } from '@/services/whatsAppGroupCreationService'; import { useToast } from '@/hooks/use-toast'; interface CreateGroupFormProps { @@ -17,14 +20,45 @@ const CreateGroupForm = ({ userEmail, onSuccess }: CreateGroupFormProps) => { const { toast } = useToast(); const [cadastrando, setCadastrando] = useState(false); const [nomeGrupo, setNomeGrupo] = useState(''); - const [errorMessage, setErrorMessage] = useState(null); - const [debugInfo, setDebugInfo] = useState(null); + const [hasWhatsAppInstance, setHasWhatsAppInstance] = useState(false); + const [checkingInstance, setCheckingInstance] = useState(true); + const [userInstance, setUserInstance] = useState<{ + instancia_zap: string | null; + status_instancia: string | null; + whatsapp: string | null; + } | null>(null); - // Cadastrar novo grupo ou atualizar workflow se necessário + // Verificar se o usuário tem instância WhatsApp + useEffect(() => { + const checkUserInstance = async () => { + if (!userEmail) return; + + setCheckingInstance(true); + try { + const instanceData = await getUserWhatsAppInstance(userEmail); + console.log('Dados da instância do usuário:', instanceData); + + if (instanceData && instanceData.instancia_zap && instanceData.instancia_zap.trim() !== '') { + setHasWhatsAppInstance(true); + setUserInstance(instanceData); + } else { + setHasWhatsAppInstance(false); + setUserInstance(null); + } + } catch (error) { + console.error('Erro ao verificar instância do usuário:', error); + setHasWhatsAppInstance(false); + setUserInstance(null); + } finally { + setCheckingInstance(false); + } + }; + + checkUserInstance(); + }, [userEmail]); + + // Cadastrar novo grupo const handleCadastrarGrupo = async () => { - setErrorMessage(null); - setDebugInfo(null); - if (!userEmail) { toast({ title: 'Erro', @@ -43,61 +77,78 @@ const CreateGroupForm = ({ userEmail, onSuccess }: CreateGroupFormProps) => { return; } + if (!userInstance || !userInstance.instancia_zap || !userInstance.whatsapp) { + toast({ + title: 'Erro', + description: 'Dados da instância WhatsApp não encontrados', + variant: 'destructive', + }); + return; + } + setCadastrando(true); try { console.log("Iniciando processo de cadastro de grupo..."); + + // 1. Cadastrar grupo no banco de dados local const grupo = await cadastrarGrupoWhatsApp(nomeGrupo.trim()); - if (grupo) { - let successMessage = 'Grupo registrado com sucesso'; - let variant: 'default' | 'destructive' = 'default'; + if (!grupo) { + throw new Error('Não foi possível cadastrar o grupo no banco de dados'); + } + + // 2. Criar grupo no WhatsApp via API + try { + const groupResponse = await createWhatsAppGroup( + userInstance.instancia_zap, + userEmail, + userInstance.whatsapp + ); - if (grupo.workflow_id) { - successMessage = 'Grupo cadastrado e workflow criado com sucesso!'; + console.log('Resposta da criação do grupo:', groupResponse); + + // 3. Atualizar remote_jid no banco de dados + if (groupResponse.id) { + await updateGroupRemoteJid(grupo.id, groupResponse.id); + + toast({ + title: 'Sucesso!', + description: `Grupo "${groupResponse.subject}" criado com sucesso no seu WhatsApp!`, + variant: 'default', + }); } else { - successMessage = 'Grupo cadastrado, mas falha ao criar workflow de automação.'; - setDebugInfo('O grupo foi criado no Supabase, mas houve um problema ao criar o workflow no n8n. Verifique os logs do console para mais detalhes.'); - variant = 'destructive'; + toast({ + title: 'Atenção', + description: 'Grupo cadastrado no sistema, mas não foi possível criar no WhatsApp', + variant: 'destructive', + }); } + } catch (apiError) { + console.error('Erro ao criar grupo via API:', apiError); toast({ - title: grupo.workflow_id ? 'Sucesso' : 'Atenção', - description: successMessage, - variant: variant, - }); - - // Resetar o campo de nome - setNomeGrupo(''); - - // Atualizar a lista de grupos - onSuccess(); - } else { - setErrorMessage('Não foi possível registrar o grupo. Verifique a conexão com o Supabase.'); - toast({ - title: 'Erro', - description: 'Não foi possível registrar o grupo', + title: 'Atenção', + description: 'Grupo cadastrado no sistema, mas houve erro ao criar no WhatsApp. Verifique sua conexão.', variant: 'destructive', }); } + + // Resetar o campo de nome + setNomeGrupo(''); + + // Atualizar a lista de grupos + onSuccess(); + } catch (error) { console.error('Erro ao cadastrar grupo:', error); let errorMsg = 'Erro desconhecido'; if (error instanceof Error) { errorMsg = error.message; - - // Tentar extrair detalhes específicos do erro se existirem - if (errorMsg.includes('Status')) { - const statusMatch = errorMsg.match(/Status (\d+)/); - if (statusMatch && statusMatch[1]) { - setDebugInfo(`Código de status HTTP da API: ${statusMatch[1]}`); - } - } } - setErrorMessage('Erro ao cadastrar grupo: ' + errorMsg); toast({ title: 'Erro', - description: 'Não foi possível registrar o grupo', + description: `Não foi possível registrar o grupo: ${errorMsg}`, variant: 'destructive', }); } finally { @@ -105,6 +156,39 @@ const CreateGroupForm = ({ userEmail, onSuccess }: CreateGroupFormProps) => { } }; + if (checkingInstance) { + return ( + + + + Verificando instância WhatsApp... + + + ); + } + + if (!hasWhatsAppInstance) { + return ( + + + Cadastrar novo grupo + + Para criar um grupo é necessário ter uma instância do WhatsApp conectada + + + + + + + Para criar um grupo é necessário cadastrar e conectar sua instância do WhatsApp. + Acesse o menu de conexão e realize este processo primeiro. + + + + + ); + } + return ( @@ -129,7 +213,7 @@ const CreateGroupForm = ({ userEmail, onSuccess }: CreateGroupFormProps) => {
-

Após cadastrar:

-
    -
  1. Adicione o número (61)99244-4275 ao grupo do WhatsApp que deseja automatizar
  2. -
  3. Envie uma mensagem neste grupo com o seguinte texto:
  4. -
- -
- {userEmail} -
- -

- Copie e cole o email exatamente como aparece acima -

+

Informações importantes:

+
    +
  • O grupo será criado automaticamente no seu WhatsApp
  • +
  • Você será adicionado como participante do grupo
  • +
  • O grupo terá o nome: FinDash - {userEmail.split('@')[0]}
  • +
- - {errorMessage &&

{errorMessage}

} - {debugInfo &&

{debugInfo}

}
); diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index 7539330..12e3391 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -293,9 +293,11 @@ export type Database = { email: string empresa: string | null id: string + instancia_zap: string | null nome: string remote_jid: string | null senha: string + status_instancia: string | null whatsapp: string } Insert: { @@ -303,9 +305,11 @@ export type Database = { email: string empresa?: string | null id?: string + instancia_zap?: string | null nome: string remote_jid?: string | null senha: string + status_instancia?: string | null whatsapp: string } Update: { @@ -313,9 +317,11 @@ export type Database = { email?: string empresa?: string | null id?: string + instancia_zap?: string | null nome?: string remote_jid?: string | null senha?: string + status_instancia?: string | null whatsapp?: string } Relationships: [] diff --git a/src/services/whatsAppGroupCreationService.ts b/src/services/whatsAppGroupCreationService.ts new file mode 100644 index 0000000..d17127b --- /dev/null +++ b/src/services/whatsAppGroupCreationService.ts @@ -0,0 +1,81 @@ + +import { supabase } from "@/integrations/supabase/client"; + +interface CreateGroupResponse { + id: string; + subject: string; + description?: string; + participants?: string[]; +} + +/** + * Cria um grupo WhatsApp via API da Evolution + */ +export async function createWhatsAppGroup( + instanceName: string, + userEmail: string, + userPhone: string +): Promise { + try { + // Extrair a parte antes do @ do email + const emailPrefix = userEmail.split('@')[0]; + const groupSubject = `FinDash - ${emailPrefix}`; + + const url = `https://evolutionapi2.innova1001.com.br/group/create/${instanceName}`; + + const requestBody = { + subject: groupSubject, + description: "Seu sistema financeiro Inteligente e Pratico", + participants: [userPhone] + }; + + console.log('Criando grupo WhatsApp:', { url, requestBody }); + + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestBody) + }); + + if (!response.ok) { + const errorText = await response.text(); + console.error('Erro na resposta da API:', response.status, errorText); + throw new Error(`Falha ao criar grupo: ${response.status} - ${errorText}`); + } + + const data = await response.json(); + console.log('Grupo criado com sucesso:', data); + + return data; + } catch (error) { + console.error('Erro ao criar grupo WhatsApp:', error); + throw error; + } +} + +/** + * Atualiza o remote_jid do grupo no banco de dados + */ +export async function updateGroupRemoteJid( + groupId: number, + remoteJid: string +): Promise { + try { + const { error } = await supabase + .from('grupos_whatsapp') + .update({ remote_jid: remoteJid }) + .eq('id', groupId); + + if (error) { + console.error('Erro ao atualizar remote_jid:', error); + throw error; + } + + console.log(`Remote JID atualizado para o grupo ${groupId}: ${remoteJid}`); + } catch (error) { + console.error('Erro ao atualizar remote_jid no banco:', error); + throw error; + } +} diff --git a/src/services/whatsAppInstanceService.ts b/src/services/whatsAppInstanceService.ts new file mode 100644 index 0000000..72bc0c8 --- /dev/null +++ b/src/services/whatsAppInstanceService.ts @@ -0,0 +1,58 @@ + +import { supabase } from "@/integrations/supabase/client"; + +/** + * Atualiza a instância WhatsApp do usuário no banco de dados + */ +export async function updateUserWhatsAppInstance( + userEmail: string, + instanceName: string, + status: 'conectado' | 'desconectado' +): Promise { + try { + const { error } = await supabase + .from('usuarios') + .update({ + instancia_zap: instanceName, + status_instancia: status + }) + .eq('email', userEmail.trim().toLowerCase()); + + if (error) { + console.error('Erro ao atualizar instância WhatsApp:', error); + throw error; + } + + console.log(`Instância WhatsApp atualizada: ${instanceName} - ${status}`); + } catch (error) { + console.error('Erro ao atualizar instância WhatsApp no banco:', error); + throw error; + } +} + +/** + * Busca a instância WhatsApp do usuário + */ +export async function getUserWhatsAppInstance(userEmail: string): Promise<{ + instancia_zap: string | null; + status_instancia: string | null; + whatsapp: string | null; +} | null> { + try { + const { data, error } = await supabase + .from('usuarios') + .select('instancia_zap, status_instancia, whatsapp') + .eq('email', userEmail.trim().toLowerCase()) + .single(); + + if (error) { + console.error('Erro ao buscar instância WhatsApp:', error); + return null; + } + + return data; + } catch (error) { + console.error('Erro ao buscar instância WhatsApp:', error); + return null; + } +}