feat: Save WhatsApp instance on creation
- Save the WhatsApp instance name to the 'instancia_zap' column in the 'usuarios' table when a new instance is created. - Update the instance status based on connection status. - Prevent the creation of multiple instances per user.
This commit is contained in:
parent
ead6400404
commit
c004980163
@ -4,11 +4,12 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
|
|||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { MessageCircle } from 'lucide-react';
|
import { MessageCircle, AlertCircle } from 'lucide-react';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { createWhatsAppInstance } from '@/services/whatsAppService';
|
import { createWhatsAppInstance } from '@/services/whatsAppService';
|
||||||
import { updateUserWhatsAppInstance } from '@/services/whatsAppInstanceService';
|
import { updateUserWhatsAppInstance, getUserWhatsAppInstance } from '@/services/whatsAppInstanceService';
|
||||||
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
||||||
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||||
|
|
||||||
interface CreateInstanceFormProps {
|
interface CreateInstanceFormProps {
|
||||||
onInstanceCreated: (instance: WhatsAppInstance) => void;
|
onInstanceCreated: (instance: WhatsAppInstance) => void;
|
||||||
@ -22,12 +23,44 @@ const CreateInstanceForm = ({
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [phoneNumber, setPhoneNumber] = useState('');
|
const [phoneNumber, setPhoneNumber] = useState('');
|
||||||
|
const [hasExistingInstance, setHasExistingInstance] = useState(false);
|
||||||
|
const [checkingExistingInstance, setCheckingExistingInstance] = useState(true);
|
||||||
const currentUserId = localStorage.getItem('userId') || '';
|
const currentUserId = localStorage.getItem('userId') || '';
|
||||||
const userEmail = localStorage.getItem('userEmail') || '';
|
const userEmail = localStorage.getItem('userEmail') || '';
|
||||||
|
|
||||||
// Nome da instância será sempre o email do usuário
|
// Nome da instância será sempre o email do usuário
|
||||||
const instanceName = userEmail;
|
const instanceName = userEmail;
|
||||||
|
|
||||||
|
// Verificar se o usuário já tem uma instância
|
||||||
|
useEffect(() => {
|
||||||
|
const checkExistingInstance = async () => {
|
||||||
|
if (!userEmail) {
|
||||||
|
setCheckingExistingInstance(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('Verificando se usuário já tem instância:', userEmail);
|
||||||
|
const existingInstance = await getUserWhatsAppInstance(userEmail);
|
||||||
|
|
||||||
|
if (existingInstance && existingInstance.instancia_zap) {
|
||||||
|
console.log('Usuário já possui instância:', existingInstance.instancia_zap);
|
||||||
|
setHasExistingInstance(true);
|
||||||
|
} else {
|
||||||
|
console.log('Usuário não possui instância');
|
||||||
|
setHasExistingInstance(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao verificar instância existente:', error);
|
||||||
|
setHasExistingInstance(false);
|
||||||
|
} finally {
|
||||||
|
setCheckingExistingInstance(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkExistingInstance();
|
||||||
|
}, [userEmail]);
|
||||||
|
|
||||||
const handleCreateInstance = async () => {
|
const handleCreateInstance = async () => {
|
||||||
// Validate form fields
|
// Validate form fields
|
||||||
if (!userEmail) {
|
if (!userEmail) {
|
||||||
@ -58,37 +91,46 @@ const CreateInstanceForm = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verificar novamente se já existe instância antes de criar
|
||||||
|
if (hasExistingInstance) {
|
||||||
|
toast({
|
||||||
|
title: "Erro",
|
||||||
|
description: "Você já possui uma instância WhatsApp. Apenas uma instância por usuário é permitida.",
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(`Creating instance with name ${instanceName} and number ${phoneNumber}`);
|
console.log(`Criando instância com nome ${instanceName} e número ${phoneNumber}`);
|
||||||
|
|
||||||
|
// 1. Primeiro atualizar o banco de dados com a instância
|
||||||
|
await updateUserWhatsAppInstance(userEmail, instanceName, 'desconectado');
|
||||||
|
console.log('Instância registrada no banco de dados');
|
||||||
|
|
||||||
|
// 2. Criar instância na API
|
||||||
const data = await createWhatsAppInstance(instanceName, phoneNumber);
|
const data = await createWhatsAppInstance(instanceName, phoneNumber);
|
||||||
|
console.log('Resposta da API de criação de instância:', data);
|
||||||
|
|
||||||
console.log('API response for create instance:', data);
|
// 3. Criar objeto da instância
|
||||||
|
|
||||||
// Create new instance object with user ID
|
|
||||||
const newInstance: WhatsAppInstance = {
|
const newInstance: WhatsAppInstance = {
|
||||||
instanceName,
|
instanceName,
|
||||||
instanceId: instanceName, // Use instanceName as the ID for consistency
|
instanceId: instanceName,
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
userId: currentUserId, // Associate with current user
|
userId: currentUserId,
|
||||||
status: data.instance?.status || 'created',
|
status: data.instance?.status || 'created',
|
||||||
qrcode: data.qrcode?.base64 || null,
|
qrcode: data.qrcode?.base64 || null,
|
||||||
connectionState: 'closed' // Default to closed/disconnected
|
connectionState: 'closed'
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('New instance created:', newInstance);
|
console.log('Nova instância criada:', newInstance);
|
||||||
|
|
||||||
// Atualizar o banco de dados com a instância
|
// 4. Atualizar estado para evitar nova criação
|
||||||
try {
|
setHasExistingInstance(true);
|
||||||
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
|
// 5. Notificar componente pai
|
||||||
onInstanceCreated(newInstance);
|
onInstanceCreated(newInstance);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
@ -100,7 +142,16 @@ const CreateInstanceForm = ({
|
|||||||
setPhoneNumber('');
|
setPhoneNumber('');
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error creating WhatsApp instance:", error);
|
console.error("Erro ao criar instância WhatsApp:", error);
|
||||||
|
|
||||||
|
// Se houve erro na API, remover do banco de dados
|
||||||
|
try {
|
||||||
|
await updateUserWhatsAppInstance(userEmail, '', 'desconectado');
|
||||||
|
console.log('Instância removida do banco devido ao erro na API');
|
||||||
|
} catch (dbError) {
|
||||||
|
console.error('Erro ao remover instância do banco:', dbError);
|
||||||
|
}
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: "Erro na criação da instância",
|
title: "Erro na criação da instância",
|
||||||
description: "Ocorreu um erro ao conectar com a API. Tente novamente mais tarde.",
|
description: "Ocorreu um erro ao conectar com a API. Tente novamente mais tarde.",
|
||||||
@ -111,6 +162,53 @@ const CreateInstanceForm = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (checkingExistingInstance) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardContent className="flex items-center justify-center py-8">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-green-600 mx-auto mb-4"></div>
|
||||||
|
<p>Verificando instâncias existentes...</p>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasExistingInstance) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center mb-2">
|
||||||
|
<MessageCircle className="h-6 w-6 mr-2 text-green-600" />
|
||||||
|
<CardTitle>WhatsApp já Conectado</CardTitle>
|
||||||
|
</div>
|
||||||
|
<CardDescription>
|
||||||
|
Você já possui uma instância WhatsApp vinculada ao seu email
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Alert>
|
||||||
|
<AlertCircle className="h-4 w-4" />
|
||||||
|
<AlertDescription>
|
||||||
|
Apenas uma instância WhatsApp por usuário é permitida.
|
||||||
|
Sua instância atual: <strong>{instanceName}</strong>
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
|
||||||
|
<div className="mt-4 p-4 bg-green-50 border border-green-200 rounded">
|
||||||
|
<p className="text-green-800 text-sm">
|
||||||
|
<strong>✓ Instância ativa:</strong> {instanceName}
|
||||||
|
</p>
|
||||||
|
<p className="text-green-700 text-sm mt-1">
|
||||||
|
Para gerenciar sua instância, utilize os botões na lista de instâncias acima.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
@ -155,6 +253,15 @@ const CreateInstanceForm = ({
|
|||||||
>
|
>
|
||||||
{loading ? "Criando..." : "Criar Instância"}
|
{loading ? "Criando..." : "Criar Instância"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<div className="mt-4 p-4 bg-blue-50 border border-blue-200 rounded">
|
||||||
|
<h4 className="font-medium text-blue-800 mb-2">Importante:</h4>
|
||||||
|
<ul className="text-sm text-blue-700 space-y-1">
|
||||||
|
<li>• Apenas uma instância por usuário é permitida</li>
|
||||||
|
<li>• O nome da instância será seu email de login</li>
|
||||||
|
<li>• Após criar, você precisará escanear o QR Code para conectar</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { useState, useEffect } from 'react';
|
|||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
||||||
import { fetchSpecificInstance } from '@/services/whatsApp/instanceManagement';
|
import { fetchSpecificInstance } from '@/services/whatsApp/instanceManagement';
|
||||||
|
import { getUserWhatsAppInstance } from '@/services/whatsAppInstanceService';
|
||||||
|
|
||||||
// Key used for storing instance name in localStorage
|
// Key used for storing instance name in localStorage
|
||||||
export const WHATSAPP_INSTANCE_KEY = 'whatsapp_instance_name';
|
export const WHATSAPP_INSTANCE_KEY = 'whatsapp_instance_name';
|
||||||
@ -12,19 +13,47 @@ export const useWhatsAppInstance = (
|
|||||||
addInstance: (instance: WhatsAppInstance) => void
|
addInstance: (instance: WhatsAppInstance) => void
|
||||||
) => {
|
) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
// Get instance name from localStorage
|
const userEmail = localStorage.getItem('userEmail') || '';
|
||||||
const [instanceName, setInstanceName] = useState(() => {
|
|
||||||
if (currentUserId) {
|
|
||||||
return localStorage.getItem(`${WHATSAPP_INSTANCE_KEY}_${currentUserId}`) || '';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Get instance name from database/localStorage
|
||||||
|
const [instanceName, setInstanceName] = useState('');
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [instanceFound, setInstanceFound] = useState(false);
|
const [instanceFound, setInstanceFound] = useState(false);
|
||||||
const [shouldShowToast, setShouldShowToast] = useState(false);
|
const [shouldShowToast, setShouldShowToast] = useState(false);
|
||||||
const [toastMessage, setToastMessage] = useState({ title: '', description: '', variant: '' as any });
|
const [toastMessage, setToastMessage] = useState({ title: '', description: '', variant: '' as any });
|
||||||
|
|
||||||
|
// Load instance name from database on component mount
|
||||||
|
useEffect(() => {
|
||||||
|
const loadInstanceFromDatabase = async () => {
|
||||||
|
if (!userEmail || !currentUserId) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('Carregando instância do banco de dados para:', userEmail);
|
||||||
|
const instanceData = await getUserWhatsAppInstance(userEmail);
|
||||||
|
|
||||||
|
if (instanceData && instanceData.instancia_zap) {
|
||||||
|
console.log('Instância encontrada no banco:', instanceData.instancia_zap);
|
||||||
|
setInstanceName(instanceData.instancia_zap);
|
||||||
|
setInstanceFound(true);
|
||||||
|
|
||||||
|
// Also save to localStorage for consistency
|
||||||
|
localStorage.setItem(`${WHATSAPP_INSTANCE_KEY}_${currentUserId}`, instanceData.instancia_zap);
|
||||||
|
} else {
|
||||||
|
console.log('Nenhuma instância encontrada no banco');
|
||||||
|
setInstanceFound(false);
|
||||||
|
|
||||||
|
// Clear localStorage if no instance in database
|
||||||
|
localStorage.removeItem(`${WHATSAPP_INSTANCE_KEY}_${currentUserId}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao carregar instância do banco:', error);
|
||||||
|
setInstanceFound(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadInstanceFromDatabase();
|
||||||
|
}, [userEmail, currentUserId]);
|
||||||
|
|
||||||
// Function to fetch specific instance by name
|
// Function to fetch specific instance by name
|
||||||
const fetchInstanceByName = async () => {
|
const fetchInstanceByName = async () => {
|
||||||
// Skip if no instance name
|
// Skip if no instance name
|
||||||
@ -41,9 +70,9 @@ export const useWhatsAppInstance = (
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(`Fetching specific instance: ${instanceName}`);
|
console.log(`Buscando instância específica: ${instanceName}`);
|
||||||
const data = await fetchSpecificInstance(instanceName);
|
const data = await fetchSpecificInstance(instanceName);
|
||||||
console.log('Fetch specific instance response:', data);
|
console.log('Resposta da busca de instância específica:', data);
|
||||||
|
|
||||||
if (data && data.instance) {
|
if (data && data.instance) {
|
||||||
// Instance found, create or update instance object
|
// Instance found, create or update instance object
|
||||||
@ -57,7 +86,7 @@ export const useWhatsAppInstance = (
|
|||||||
qrcode: data.qrcode?.base64 || null
|
qrcode: data.qrcode?.base64 || null
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('Found instance:', foundInstance);
|
console.log('Instância encontrada:', foundInstance);
|
||||||
addInstance(foundInstance);
|
addInstance(foundInstance);
|
||||||
setInstanceFound(true);
|
setInstanceFound(true);
|
||||||
|
|
||||||
@ -70,10 +99,10 @@ export const useWhatsAppInstance = (
|
|||||||
setShouldShowToast(true);
|
setShouldShowToast(true);
|
||||||
} else {
|
} else {
|
||||||
setInstanceFound(false);
|
setInstanceFound(false);
|
||||||
console.log(`Instance ${instanceName} not found`);
|
console.log(`Instância ${instanceName} não encontrada`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching specific instance:', error);
|
console.error('Erro ao buscar instância específica:', error);
|
||||||
setInstanceFound(false);
|
setInstanceFound(false);
|
||||||
|
|
||||||
// Set toast data instead of calling toast directly
|
// Set toast data instead of calling toast directly
|
||||||
@ -100,7 +129,7 @@ export const useWhatsAppInstance = (
|
|||||||
}
|
}
|
||||||
}, [shouldShowToast, toastMessage, toast]);
|
}, [shouldShowToast, toastMessage, toast]);
|
||||||
|
|
||||||
// Save instance name to localStorage
|
// Save instance name to localStorage and database
|
||||||
const saveInstanceName = (name: string) => {
|
const saveInstanceName = (name: string) => {
|
||||||
if (currentUserId) {
|
if (currentUserId) {
|
||||||
localStorage.setItem(`${WHATSAPP_INSTANCE_KEY}_${currentUserId}`, name);
|
localStorage.setItem(`${WHATSAPP_INSTANCE_KEY}_${currentUserId}`, name);
|
||||||
@ -108,7 +137,7 @@ export const useWhatsAppInstance = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clear instance name from localStorage
|
// Clear instance name from localStorage and database
|
||||||
const clearInstanceName = () => {
|
const clearInstanceName = () => {
|
||||||
if (currentUserId) {
|
if (currentUserId) {
|
||||||
localStorage.removeItem(`${WHATSAPP_INSTANCE_KEY}_${currentUserId}`);
|
localStorage.removeItem(`${WHATSAPP_INSTANCE_KEY}_${currentUserId}`);
|
||||||
@ -117,8 +146,6 @@ export const useWhatsAppInstance = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Don't automatically load the instance - removed the useEffect that called fetchInstanceByName
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
instanceName,
|
instanceName,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|||||||
@ -10,6 +10,8 @@ export async function updateUserWhatsAppInstance(
|
|||||||
status: 'conectado' | 'desconectado'
|
status: 'conectado' | 'desconectado'
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
console.log(`Atualizando instância no banco: ${userEmail} -> ${instanceName} (${status})`);
|
||||||
|
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
.from('usuarios')
|
.from('usuarios')
|
||||||
.update({
|
.update({
|
||||||
@ -23,7 +25,7 @@ export async function updateUserWhatsAppInstance(
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Instância WhatsApp atualizada: ${instanceName} - ${status}`);
|
console.log(`Instância WhatsApp atualizada com sucesso: ${instanceName} - ${status}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erro ao atualizar instância WhatsApp no banco:', error);
|
console.error('Erro ao atualizar instância WhatsApp no banco:', error);
|
||||||
throw error;
|
throw error;
|
||||||
@ -45,7 +47,7 @@ export async function getUserWhatsAppInstance(userEmail: string): Promise<{
|
|||||||
.from('usuarios')
|
.from('usuarios')
|
||||||
.select('instancia_zap, status_instancia, whatsapp')
|
.select('instancia_zap, status_instancia, whatsapp')
|
||||||
.eq('email', userEmail.trim().toLowerCase())
|
.eq('email', userEmail.trim().toLowerCase())
|
||||||
.maybeSingle(); // Use maybeSingle em vez de single para evitar erro quando não encontrar
|
.maybeSingle();
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Erro ao buscar instância WhatsApp:', error);
|
console.error('Erro ao buscar instância WhatsApp:', error);
|
||||||
@ -59,3 +61,43 @@ export async function getUserWhatsAppInstance(userEmail: string): Promise<{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica se o usuário já possui uma instância ativa
|
||||||
|
*/
|
||||||
|
export async function checkUserHasInstance(userEmail: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const instanceData = await getUserWhatsAppInstance(userEmail);
|
||||||
|
return !!(instanceData && instanceData.instancia_zap && instanceData.instancia_zap.trim() !== '');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao verificar se usuário tem instância:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a instância WhatsApp do usuário
|
||||||
|
*/
|
||||||
|
export async function removeUserWhatsAppInstance(userEmail: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
console.log(`Removendo instância do usuário: ${userEmail}`);
|
||||||
|
|
||||||
|
const { error } = await supabase
|
||||||
|
.from('usuarios')
|
||||||
|
.update({
|
||||||
|
instancia_zap: null,
|
||||||
|
status_instancia: 'desconectado'
|
||||||
|
})
|
||||||
|
.eq('email', userEmail.trim().toLowerCase());
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error('Erro ao remover instância WhatsApp:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Instância WhatsApp removida com sucesso');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao remover instância WhatsApp do banco:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user