Refactor: Extract WhatsApp logic into hooks and components
Refactor WhatsApp.tsx to use custom hooks and smaller components, preserving all existing functionality.
This commit is contained in:
parent
b0d6e88a76
commit
66a2cc47a8
40
src/components/whatsapp/InstanceStats.tsx
Normal file
40
src/components/whatsapp/InstanceStats.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
||||||
|
|
||||||
|
interface InstanceStatsProps {
|
||||||
|
instances: WhatsAppInstance[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const InstanceStats = ({ instances }: InstanceStatsProps) => {
|
||||||
|
const totalInstances = instances.length;
|
||||||
|
const connectedInstances = instances.filter(i => i.connectionState === 'open').length;
|
||||||
|
const disconnectedInstances = instances.filter(i => i.connectionState === 'closed').length;
|
||||||
|
const connectingInstances = instances.filter(i => i.connectionState === 'connecting').length;
|
||||||
|
|
||||||
|
if (totalInstances === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 my-4">
|
||||||
|
<div className="bg-card border rounded-lg shadow-sm p-4 text-center">
|
||||||
|
<p className="text-sm text-muted-foreground">Total de instâncias</p>
|
||||||
|
<p className="text-2xl font-bold">{totalInstances}</p>
|
||||||
|
</div>
|
||||||
|
<div className="bg-card border rounded-lg shadow-sm p-4 text-center">
|
||||||
|
<p className="text-sm text-muted-foreground">Conectadas</p>
|
||||||
|
<p className="text-2xl font-bold text-green-600">{connectedInstances}</p>
|
||||||
|
</div>
|
||||||
|
<div className="bg-card border rounded-lg shadow-sm p-4 text-center">
|
||||||
|
<p className="text-sm text-muted-foreground">Desconectadas</p>
|
||||||
|
<p className="text-2xl font-bold text-red-600">{disconnectedInstances}</p>
|
||||||
|
</div>
|
||||||
|
<div className="bg-card border rounded-lg shadow-sm p-4 text-center">
|
||||||
|
<p className="text-sm text-muted-foreground">Conectando</p>
|
||||||
|
<p className="text-2xl font-bold text-orange-600">{connectingInstances}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InstanceStats;
|
||||||
162
src/hooks/useWhatsAppActions.ts
Normal file
162
src/hooks/useWhatsAppActions.ts
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useToast } from '@/hooks/use-toast';
|
||||||
|
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
||||||
|
import {
|
||||||
|
restartInstance,
|
||||||
|
logoutInstance,
|
||||||
|
deleteInstance,
|
||||||
|
setInstancePresence,
|
||||||
|
fetchQrCode
|
||||||
|
} from '@/services/whatsAppService';
|
||||||
|
|
||||||
|
export const useWhatsAppActions = (
|
||||||
|
updateInstance: (instance: WhatsAppInstance) => void,
|
||||||
|
removeInstance: (instanceId: string) => void,
|
||||||
|
checkAllInstancesStatus: () => Promise<void>
|
||||||
|
) => {
|
||||||
|
const { toast } = useToast();
|
||||||
|
const [activeInstance, setActiveInstance] = useState<WhatsAppInstance | null>(null);
|
||||||
|
const [qrDialogOpen, setQrDialogOpen] = useState(false);
|
||||||
|
|
||||||
|
// Handler for quando uma instância é reiniciada
|
||||||
|
const handleRestartInstance = async (instance: WhatsAppInstance) => {
|
||||||
|
try {
|
||||||
|
await restartInstance(instance.instanceName);
|
||||||
|
|
||||||
|
// Atualiza o estado da instância para "connecting"
|
||||||
|
const updatedInstance = {
|
||||||
|
...instance,
|
||||||
|
connectionState: 'connecting' as const
|
||||||
|
};
|
||||||
|
updateInstance(updatedInstance);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Sucesso",
|
||||||
|
description: `Instância ${instance.instanceName} reiniciada com sucesso`
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verifica o status após um breve delay para dar tempo de atualizar
|
||||||
|
setTimeout(() => checkAllInstancesStatus(), 3000);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error restarting instance ${instance.instanceName}:`, error);
|
||||||
|
toast({
|
||||||
|
title: "Erro",
|
||||||
|
description: `Falha ao reiniciar a instância ${instance.instanceName}`,
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handler for quando uma instância é desconectada
|
||||||
|
const handleLogoutInstance = async (instance: WhatsAppInstance) => {
|
||||||
|
try {
|
||||||
|
await logoutInstance(instance.instanceName);
|
||||||
|
|
||||||
|
// Atualiza o estado da instância para "closed"
|
||||||
|
const updatedInstance = {
|
||||||
|
...instance,
|
||||||
|
connectionState: 'closed' as const
|
||||||
|
};
|
||||||
|
updateInstance(updatedInstance);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Sucesso",
|
||||||
|
description: `Instância ${instance.instanceName} desconectada com sucesso`
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error logging out instance ${instance.instanceName}:`, error);
|
||||||
|
toast({
|
||||||
|
title: "Erro",
|
||||||
|
description: `Falha ao desconectar a instância ${instance.instanceName}`,
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handler for quando a presença é alterada
|
||||||
|
const handleSetPresence = async (instance: WhatsAppInstance, presence: 'online' | 'offline') => {
|
||||||
|
try {
|
||||||
|
await setInstancePresence(instance.instanceName, presence);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Sucesso",
|
||||||
|
description: `Instância ${instance.instanceName} agora está ${presence === 'online' ? 'Online' : 'Offline'}`
|
||||||
|
});
|
||||||
|
|
||||||
|
// Não precisamos alterar o estado da instância aqui, pois isso não afeta o connectionState
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error setting presence to ${presence} for instance ${instance.instanceName}:`, error);
|
||||||
|
toast({
|
||||||
|
title: "Erro",
|
||||||
|
description: `Falha ao definir presença ${presence} para ${instance.instanceName}`,
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handler for when an instance is deleted
|
||||||
|
const handleDeleteInstance = async (instanceId: string, instanceName: string) => {
|
||||||
|
console.log(`Deleting instance with ID: ${instanceId}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Call API to delete instance
|
||||||
|
await deleteInstance(instanceName);
|
||||||
|
|
||||||
|
// Remove from local state
|
||||||
|
removeInstance(instanceId);
|
||||||
|
|
||||||
|
// If we're viewing QR code for this instance, close the dialog
|
||||||
|
if (activeInstance?.instanceId === instanceId) {
|
||||||
|
setQrDialogOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Instância removida",
|
||||||
|
description: "A instância do WhatsApp foi removida com sucesso.",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error deleting instance with ID ${instanceId}:`, error);
|
||||||
|
toast({
|
||||||
|
title: "Erro",
|
||||||
|
description: "Falha ao excluir a instância. Tente novamente.",
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handler for when QR code dialog is requested
|
||||||
|
const handleViewQrCode = async (instance: WhatsAppInstance) => {
|
||||||
|
setActiveInstance(instance);
|
||||||
|
setQrDialogOpen(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await fetchQrCode(instance.instanceName);
|
||||||
|
console.log('QR Code API response:', data);
|
||||||
|
|
||||||
|
// If the fetchQrCode call was successful, QrCodeDialog will handle showing the QR code
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error initiating QR code fetch:", error);
|
||||||
|
toast({
|
||||||
|
title: "Erro ao obter QR Code",
|
||||||
|
description: "Falha ao iniciar obtenção de QR Code. Tente novamente.",
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
setQrDialogOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
activeInstance,
|
||||||
|
qrDialogOpen,
|
||||||
|
setQrDialogOpen,
|
||||||
|
handleRestartInstance,
|
||||||
|
handleLogoutInstance,
|
||||||
|
handleSetPresence,
|
||||||
|
handleDeleteInstance,
|
||||||
|
handleViewQrCode
|
||||||
|
};
|
||||||
|
};
|
||||||
161
src/hooks/useWhatsAppInstances.ts
Normal file
161
src/hooks/useWhatsAppInstances.ts
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useToast } from '@/hooks/use-toast';
|
||||||
|
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
||||||
|
import {
|
||||||
|
saveInstancesToLocalStorage,
|
||||||
|
loadInstancesFromLocalStorage,
|
||||||
|
fetchAllInstances,
|
||||||
|
fetchConnectionState
|
||||||
|
} from '@/services/whatsAppService';
|
||||||
|
|
||||||
|
export const useWhatsAppInstances = () => {
|
||||||
|
const { toast } = useToast();
|
||||||
|
const [instances, setInstances] = useState<WhatsAppInstance[]>([]);
|
||||||
|
const [currentUserId, setCurrentUserId] = useState<string>('');
|
||||||
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||||
|
|
||||||
|
// Get current user ID and load instances on component mount
|
||||||
|
useEffect(() => {
|
||||||
|
const userId = localStorage.getItem('userId') || '';
|
||||||
|
console.log("Current userId from localStorage:", userId);
|
||||||
|
setCurrentUserId(userId);
|
||||||
|
|
||||||
|
if (userId) {
|
||||||
|
const userInstances = loadInstancesFromLocalStorage(userId);
|
||||||
|
console.log('Loaded user instances:', userInstances);
|
||||||
|
setInstances(userInstances);
|
||||||
|
}
|
||||||
|
}, []); // Only run once on mount
|
||||||
|
|
||||||
|
// Save instances to localStorage whenever they change
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentUserId) {
|
||||||
|
console.log('Saving instances to localStorage:', instances);
|
||||||
|
saveInstancesToLocalStorage(instances, currentUserId);
|
||||||
|
}
|
||||||
|
}, [instances, currentUserId]);
|
||||||
|
|
||||||
|
// Function to check connection status for all instances
|
||||||
|
const checkAllInstancesStatus = async () => {
|
||||||
|
try {
|
||||||
|
const updatedInstances = await Promise.all(
|
||||||
|
instances.map(async (instance) => {
|
||||||
|
try {
|
||||||
|
const state = await fetchConnectionState(instance.instanceName);
|
||||||
|
return { ...instance, connectionState: state };
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error checking status for ${instance.instanceName}:`, error);
|
||||||
|
return { ...instance, connectionState: 'closed' as const };
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setInstances(updatedInstances);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error checking instances status:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handler para atualizar a lista de instâncias do servidor
|
||||||
|
const refreshInstances = async () => {
|
||||||
|
if (!currentUserId) {
|
||||||
|
toast({
|
||||||
|
title: "Erro de autenticação",
|
||||||
|
description: "Você precisa estar logado para atualizar as instâncias",
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsRefreshing(true);
|
||||||
|
try {
|
||||||
|
const response = await fetchAllInstances();
|
||||||
|
console.log("Fetched instances from server:", response);
|
||||||
|
|
||||||
|
if (response.instances && Array.isArray(response.instances)) {
|
||||||
|
// Filtra instâncias para mostrar apenas as do usuário atual
|
||||||
|
// E mapeia para o formato correto com userId
|
||||||
|
const serverInstances: WhatsAppInstance[] = response.instances
|
||||||
|
.filter(serverInstance => {
|
||||||
|
// Implemente sua lógica de filtro para o usuário atual (se necessário)
|
||||||
|
// Por padrão, vamos assumir que todas as instâncias são do usuário atual
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.map(serverInstance => ({
|
||||||
|
instanceName: serverInstance.instanceName,
|
||||||
|
instanceId: serverInstance.instanceName,
|
||||||
|
phoneNumber: serverInstance.number || 'Desconhecido',
|
||||||
|
userId: currentUserId,
|
||||||
|
connectionState: serverInstance.state || 'closed',
|
||||||
|
status: serverInstance.status || 'unknown'
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mesclando instâncias do servidor com as locais (para não perder dados locais)
|
||||||
|
const localInstanceIds = new Set(instances.map(i => i.instanceId));
|
||||||
|
const newInstances = [
|
||||||
|
...instances,
|
||||||
|
...serverInstances.filter(i => !localInstanceIds.has(i.instanceId))
|
||||||
|
];
|
||||||
|
|
||||||
|
setInstances(newInstances);
|
||||||
|
toast({
|
||||||
|
title: "Sucesso",
|
||||||
|
description: `${serverInstances.length} instâncias encontradas no servidor`,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "Aviso",
|
||||||
|
description: "Nenhuma instância encontrada no servidor",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erro ao buscar instâncias:", error);
|
||||||
|
toast({
|
||||||
|
title: "Erro",
|
||||||
|
description: "Falha ao buscar instâncias do servidor",
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setIsRefreshing(false);
|
||||||
|
// Verificar status após atualizar a lista
|
||||||
|
checkAllInstancesStatus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add a new instance
|
||||||
|
const addInstance = (newInstance: WhatsAppInstance) => {
|
||||||
|
console.log("New instance created, adding to instances list:", newInstance);
|
||||||
|
setInstances(prevInstances => [...prevInstances, newInstance]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove an instance
|
||||||
|
const removeInstance = (instanceId: string) => {
|
||||||
|
setInstances(prevInstances => {
|
||||||
|
const filtered = prevInstances.filter(instance => instance.instanceId !== instanceId);
|
||||||
|
console.log("Updated instances after deletion:", filtered);
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update an instance
|
||||||
|
const updateInstance = (updatedInstance: WhatsAppInstance) => {
|
||||||
|
setInstances(prevInstances =>
|
||||||
|
prevInstances.map(instance =>
|
||||||
|
instance.instanceId === updatedInstance.instanceId
|
||||||
|
? updatedInstance
|
||||||
|
: instance
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
instances,
|
||||||
|
isRefreshing,
|
||||||
|
currentUserId,
|
||||||
|
addInstance,
|
||||||
|
removeInstance,
|
||||||
|
updateInstance,
|
||||||
|
refreshInstances,
|
||||||
|
checkAllInstancesStatus
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,79 +1,35 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import Layout from '@/components/layout/Layout';
|
import Layout from '@/components/layout/Layout';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
|
||||||
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
||||||
import {
|
|
||||||
fetchQrCode,
|
|
||||||
fetchConnectionState,
|
|
||||||
saveInstancesToLocalStorage,
|
|
||||||
loadInstancesFromLocalStorage,
|
|
||||||
fetchAllInstances,
|
|
||||||
restartInstance,
|
|
||||||
logoutInstance,
|
|
||||||
deleteInstance,
|
|
||||||
setInstancePresence
|
|
||||||
} from '@/services/whatsAppService';
|
|
||||||
import CreateInstanceForm from '@/components/whatsapp/CreateInstanceForm';
|
import CreateInstanceForm from '@/components/whatsapp/CreateInstanceForm';
|
||||||
import InstanceList from '@/components/whatsapp/InstanceList';
|
import InstanceList from '@/components/whatsapp/InstanceList';
|
||||||
|
import InstanceStats from '@/components/whatsapp/InstanceStats';
|
||||||
import QrCodeDialog from '@/components/whatsapp/QrCodeDialog';
|
import QrCodeDialog from '@/components/whatsapp/QrCodeDialog';
|
||||||
|
import { useWhatsAppInstances } from '@/hooks/useWhatsAppInstances';
|
||||||
|
import { useWhatsAppActions } from '@/hooks/useWhatsAppActions';
|
||||||
|
|
||||||
const WhatsApp = () => {
|
const WhatsApp = () => {
|
||||||
const { toast } = useToast();
|
const {
|
||||||
const [instances, setInstances] = useState<WhatsAppInstance[]>([]);
|
instances,
|
||||||
const [activeInstance, setActiveInstance] = useState<WhatsAppInstance | null>(null);
|
isRefreshing,
|
||||||
const [qrDialogOpen, setQrDialogOpen] = useState(false);
|
addInstance,
|
||||||
const [statusCheckInterval, setStatusCheckInterval] = useState<NodeJS.Timeout | null>(null);
|
removeInstance,
|
||||||
const [currentUserId, setCurrentUserId] = useState<string>('');
|
updateInstance,
|
||||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
refreshInstances,
|
||||||
|
checkAllInstancesStatus
|
||||||
|
} = useWhatsAppInstances();
|
||||||
|
|
||||||
// Get current user ID and load instances on component mount
|
const {
|
||||||
useEffect(() => {
|
activeInstance,
|
||||||
const userId = localStorage.getItem('userId') || '';
|
qrDialogOpen,
|
||||||
console.log("Current userId from localStorage:", userId);
|
setQrDialogOpen,
|
||||||
setCurrentUserId(userId);
|
handleRestartInstance,
|
||||||
|
handleLogoutInstance,
|
||||||
if (userId) {
|
handleSetPresence,
|
||||||
const userInstances = loadInstancesFromLocalStorage(userId);
|
handleDeleteInstance,
|
||||||
console.log('Loaded user instances:', userInstances);
|
handleViewQrCode
|
||||||
setInstances(userInstances);
|
} = useWhatsAppActions(updateInstance, removeInstance, checkAllInstancesStatus);
|
||||||
}
|
|
||||||
}, []); // Only run once on mount
|
|
||||||
|
|
||||||
// Save instances to localStorage whenever they change
|
|
||||||
useEffect(() => {
|
|
||||||
if (currentUserId) {
|
|
||||||
console.log('Saving instances to localStorage:', instances);
|
|
||||||
saveInstancesToLocalStorage(instances, currentUserId);
|
|
||||||
}
|
|
||||||
}, [instances, currentUserId]);
|
|
||||||
|
|
||||||
// Handle user logout event to clear instances display
|
|
||||||
useEffect(() => {
|
|
||||||
const handleStorageChange = (e: StorageEvent) => {
|
|
||||||
if (e.key === 'autenticado' && e.newValue === null) {
|
|
||||||
// User logged out, clear instances from display
|
|
||||||
setInstances([]);
|
|
||||||
setCurrentUserId('');
|
|
||||||
} else if (e.key === 'userId') {
|
|
||||||
// User ID changed (new login)
|
|
||||||
const newUserId = localStorage.getItem('userId') || '';
|
|
||||||
setCurrentUserId(newUserId);
|
|
||||||
|
|
||||||
// Load instances for the new user
|
|
||||||
if (newUserId) {
|
|
||||||
const userInstances = loadInstancesFromLocalStorage(newUserId);
|
|
||||||
setInstances(userInstances);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('storage', handleStorageChange);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('storage', handleStorageChange);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Set up periodic status checks
|
// Set up periodic status checks
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -89,8 +45,6 @@ const WhatsApp = () => {
|
|||||||
}
|
}
|
||||||
}, 60000); // 60 seconds
|
}, 60000); // 60 seconds
|
||||||
|
|
||||||
setStatusCheckInterval(interval);
|
|
||||||
|
|
||||||
// Clean up interval when component unmounts
|
// Clean up interval when component unmounts
|
||||||
return () => {
|
return () => {
|
||||||
if (interval) {
|
if (interval) {
|
||||||
@ -99,256 +53,24 @@ const WhatsApp = () => {
|
|||||||
};
|
};
|
||||||
}, [instances.length]);
|
}, [instances.length]);
|
||||||
|
|
||||||
// Function to check connection status for all instances
|
|
||||||
const checkAllInstancesStatus = async () => {
|
|
||||||
try {
|
|
||||||
const updatedInstances = await Promise.all(
|
|
||||||
instances.map(async (instance) => {
|
|
||||||
try {
|
|
||||||
const state = await fetchConnectionState(instance.instanceName);
|
|
||||||
return { ...instance, connectionState: state };
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error checking status for ${instance.instanceName}:`, error);
|
|
||||||
return { ...instance, connectionState: 'closed' as const };
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
setInstances(updatedInstances);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error checking instances status:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handler para atualizar a lista de instâncias do servidor
|
|
||||||
const handleRefreshInstances = async () => {
|
|
||||||
if (!currentUserId) {
|
|
||||||
toast({
|
|
||||||
title: "Erro de autenticação",
|
|
||||||
description: "Você precisa estar logado para atualizar as instâncias",
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsRefreshing(true);
|
|
||||||
try {
|
|
||||||
const response = await fetchAllInstances();
|
|
||||||
console.log("Fetched instances from server:", response);
|
|
||||||
|
|
||||||
if (response.instances && Array.isArray(response.instances)) {
|
|
||||||
// Filtra instâncias para mostrar apenas as do usuário atual
|
|
||||||
// E mapeia para o formato correto com userId
|
|
||||||
const serverInstances: WhatsAppInstance[] = response.instances
|
|
||||||
.filter(serverInstance => {
|
|
||||||
// Implemente sua lógica de filtro para o usuário atual (se necessário)
|
|
||||||
// Por padrão, vamos assumir que todas as instâncias são do usuário atual
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
.map(serverInstance => ({
|
|
||||||
instanceName: serverInstance.instanceName,
|
|
||||||
instanceId: serverInstance.instanceName,
|
|
||||||
phoneNumber: serverInstance.number || 'Desconhecido',
|
|
||||||
userId: currentUserId,
|
|
||||||
connectionState: serverInstance.state || 'closed',
|
|
||||||
status: serverInstance.status || 'unknown'
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Mesclando instâncias do servidor com as locais (para não perder dados locais)
|
|
||||||
const localInstanceIds = new Set(instances.map(i => i.instanceId));
|
|
||||||
const newInstances = [
|
|
||||||
...instances,
|
|
||||||
...serverInstances.filter(i => !localInstanceIds.has(i.instanceId))
|
|
||||||
];
|
|
||||||
|
|
||||||
setInstances(newInstances);
|
|
||||||
toast({
|
|
||||||
title: "Sucesso",
|
|
||||||
description: `${serverInstances.length} instâncias encontradas no servidor`,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
toast({
|
|
||||||
title: "Aviso",
|
|
||||||
description: "Nenhuma instância encontrada no servidor",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erro ao buscar instâncias:", error);
|
|
||||||
toast({
|
|
||||||
title: "Erro",
|
|
||||||
description: "Falha ao buscar instâncias do servidor",
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setIsRefreshing(false);
|
|
||||||
// Verificar status após atualizar a lista
|
|
||||||
checkAllInstancesStatus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handler for quando uma instância é reiniciada
|
|
||||||
const handleRestartInstance = async (instance: WhatsAppInstance) => {
|
|
||||||
try {
|
|
||||||
await restartInstance(instance.instanceName);
|
|
||||||
|
|
||||||
// Atualiza o estado da instância para "connecting"
|
|
||||||
setInstances(prev =>
|
|
||||||
prev.map(i =>
|
|
||||||
i.instanceId === instance.instanceId
|
|
||||||
? { ...i, connectionState: 'connecting' as const }
|
|
||||||
: i
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
toast({
|
|
||||||
title: "Sucesso",
|
|
||||||
description: `Instância ${instance.instanceName} reiniciada com sucesso`
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verifica o status após um breve delay para dar tempo de atualizar
|
|
||||||
setTimeout(() => checkAllInstancesStatus(), 3000);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error restarting instance ${instance.instanceName}:`, error);
|
|
||||||
toast({
|
|
||||||
title: "Erro",
|
|
||||||
description: `Falha ao reiniciar a instância ${instance.instanceName}`,
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handler for quando uma instância é desconectada
|
|
||||||
const handleLogoutInstance = async (instance: WhatsAppInstance) => {
|
|
||||||
try {
|
|
||||||
await logoutInstance(instance.instanceName);
|
|
||||||
|
|
||||||
// Atualiza o estado da instância para "closed"
|
|
||||||
setInstances(prev =>
|
|
||||||
prev.map(i =>
|
|
||||||
i.instanceId === instance.instanceId
|
|
||||||
? { ...i, connectionState: 'closed' as const }
|
|
||||||
: i
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
toast({
|
|
||||||
title: "Sucesso",
|
|
||||||
description: `Instância ${instance.instanceName} desconectada com sucesso`
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error logging out instance ${instance.instanceName}:`, error);
|
|
||||||
toast({
|
|
||||||
title: "Erro",
|
|
||||||
description: `Falha ao desconectar a instância ${instance.instanceName}`,
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handler for quando a presença é alterada
|
|
||||||
const handleSetPresence = async (instance: WhatsAppInstance, presence: 'online' | 'offline') => {
|
|
||||||
try {
|
|
||||||
await setInstancePresence(instance.instanceName, presence);
|
|
||||||
|
|
||||||
toast({
|
|
||||||
title: "Sucesso",
|
|
||||||
description: `Instância ${instance.instanceName} agora está ${presence === 'online' ? 'Online' : 'Offline'}`
|
|
||||||
});
|
|
||||||
|
|
||||||
// Não precisamos alterar o estado da instância aqui, pois isso não afeta o connectionState
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error setting presence to ${presence} for instance ${instance.instanceName}:`, error);
|
|
||||||
toast({
|
|
||||||
title: "Erro",
|
|
||||||
description: `Falha ao definir presença ${presence} para ${instance.instanceName}`,
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handler for when a new instance is created
|
// Handler for when a new instance is created
|
||||||
const handleInstanceCreated = async (newInstance: WhatsAppInstance) => {
|
const handleInstanceCreated = async (newInstance: WhatsAppInstance) => {
|
||||||
console.log("New instance created, adding to instances list:", newInstance);
|
addInstance(newInstance);
|
||||||
|
|
||||||
// Add new instance to the list - use the function form to guarantee correct state update
|
|
||||||
setInstances(prevInstances => [...prevInstances, newInstance]);
|
|
||||||
|
|
||||||
// If there's a QR code in the response, show it
|
// If there's a QR code in the response, show it
|
||||||
if (newInstance.qrcode) {
|
if (newInstance.qrcode) {
|
||||||
setActiveInstance(newInstance);
|
handleViewQrCode(newInstance);
|
||||||
setQrDialogOpen(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger a status check for all instances
|
// Trigger a status check for all instances
|
||||||
await checkAllInstancesStatus();
|
await checkAllInstancesStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handler for when QR code dialog is requested
|
|
||||||
const handleViewQrCode = async (instance: WhatsAppInstance) => {
|
|
||||||
setActiveInstance(instance);
|
|
||||||
setQrDialogOpen(true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await fetchQrCode(instance.instanceName);
|
|
||||||
console.log('QR Code API response:', data);
|
|
||||||
|
|
||||||
// If the fetchQrCode call was successful, QrCodeDialog will handle showing the QR code
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error initiating QR code fetch:", error);
|
|
||||||
toast({
|
|
||||||
title: "Erro ao obter QR Code",
|
|
||||||
description: "Falha ao iniciar obtenção de QR Code. Tente novamente.",
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
setQrDialogOpen(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handler for when an instance is deleted
|
// Handler for when an instance is deleted
|
||||||
const handleDeleteInstance = async (instanceId: string) => {
|
const handleDeleteInstanceWrapper = (instanceId: string) => {
|
||||||
console.log(`Deleting instance with ID: ${instanceId}`);
|
|
||||||
|
|
||||||
// Find the instance before deleting it
|
|
||||||
const instanceToDelete = instances.find(i => i.instanceId === instanceId);
|
const instanceToDelete = instances.find(i => i.instanceId === instanceId);
|
||||||
|
if (instanceToDelete) {
|
||||||
if (!instanceToDelete) {
|
handleDeleteInstance(instanceId, instanceToDelete.instanceName);
|
||||||
toast({
|
|
||||||
title: "Erro",
|
|
||||||
description: "Instância não encontrada",
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Call API to delete instance
|
|
||||||
await deleteInstance(instanceToDelete.instanceName);
|
|
||||||
|
|
||||||
// Remove from local state if API call was successful
|
|
||||||
setInstances(prevInstances => {
|
|
||||||
const filtered = prevInstances.filter(instance => instance.instanceId !== instanceId);
|
|
||||||
console.log("Updated instances after deletion:", filtered);
|
|
||||||
return filtered;
|
|
||||||
});
|
|
||||||
|
|
||||||
// If we're viewing QR code for this instance, close the dialog
|
|
||||||
if (activeInstance?.instanceId === instanceId) {
|
|
||||||
setQrDialogOpen(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
toast({
|
|
||||||
title: "Instância removida",
|
|
||||||
description: "A instância do WhatsApp foi removida com sucesso.",
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error deleting instance with ID ${instanceId}:`, error);
|
|
||||||
toast({
|
|
||||||
title: "Erro",
|
|
||||||
description: "Falha ao excluir a instância. Tente novamente.",
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -362,15 +84,18 @@ const WhatsApp = () => {
|
|||||||
{/* Form to create a new instance */}
|
{/* Form to create a new instance */}
|
||||||
<CreateInstanceForm onInstanceCreated={handleInstanceCreated} />
|
<CreateInstanceForm onInstanceCreated={handleInstanceCreated} />
|
||||||
|
|
||||||
|
{/* Stats component */}
|
||||||
|
<InstanceStats instances={instances} />
|
||||||
|
|
||||||
{/* List of created instances */}
|
{/* List of created instances */}
|
||||||
<InstanceList
|
<InstanceList
|
||||||
instances={instances}
|
instances={instances}
|
||||||
onViewQrCode={handleViewQrCode}
|
onViewQrCode={handleViewQrCode}
|
||||||
onDelete={handleDeleteInstance}
|
onDelete={handleDeleteInstanceWrapper}
|
||||||
onRestart={handleRestartInstance}
|
onRestart={handleRestartInstance}
|
||||||
onLogout={handleLogoutInstance}
|
onLogout={handleLogoutInstance}
|
||||||
onSetPresence={handleSetPresence}
|
onSetPresence={handleSetPresence}
|
||||||
onRefreshInstances={handleRefreshInstances}
|
onRefreshInstances={refreshInstances}
|
||||||
isRefreshing={isRefreshing}
|
isRefreshing={isRefreshing}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user