diff --git a/src/hooks/useWhatsAppInstances.ts b/src/hooks/useWhatsAppInstances.ts index 4fc64b4..40ef46f 100644 --- a/src/hooks/useWhatsAppInstances.ts +++ b/src/hooks/useWhatsAppInstances.ts @@ -1,249 +1,3 @@ -import { useState, useEffect, useCallback } 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([]); - const [currentUserId, setCurrentUserId] = useState(''); - 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 && instances.length > 0) { - console.log('Saving instances to localStorage:', instances); - saveInstancesToLocalStorage(instances, currentUserId); - } - }, [instances, currentUserId]); - - // Function to check connection status for all instances - const checkAllInstancesStatus = useCallback(async () => { - if (instances.length === 0) return; - - console.log(`Checking connection status for ${instances.length} instances`); - - try { - const updatedInstances = await Promise.all( - instances.map(async (instance) => { - try { - console.log(`Checking status for ${instance.instanceName}`); - const state = await fetchConnectionState(instance.instanceName); - console.log(`Status for ${instance.instanceName}: ${state}`); - - // Only update connectionState if it's different - if (instance.connectionState !== state) { - // Ensure the state is one of the valid values or treat as 'closed' - let validState: 'open' | 'closed' | 'connecting'; - if (state === 'open' || state === 'connecting') { - validState = state; - } else { - validState = 'closed'; - } - - return { - ...instance, - connectionState: validState, - status: state === 'open' ? 'connected' : - state === 'connecting' ? 'connecting' : 'disconnected' - }; - } - return instance; - } catch (error) { - console.error(`Error checking status for ${instance.instanceName}:`, error); - - // If the instance doesn't exist on the server, mark it as closed - if (error instanceof Error && error.message.includes("does not exist")) { - return { - ...instance, - connectionState: 'closed' as const, - status: 'disconnected' - }; - } - - // Keep the current state in case of other errors - return instance; - } - }) - ); - - // Only update state if there are actual changes - const hasChanges = JSON.stringify(updatedInstances) !== JSON.stringify(instances); - if (hasChanges) { - console.log('Updated instances after status check:', updatedInstances); - setInstances(updatedInstances); - } else { - console.log('No changes in instance status'); - } - } catch (error) { - console.error("Error checking instances status:", error); - } - }, [instances]); - - // 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 { - console.log("Fetching instances from server..."); - const response = await fetchAllInstances(); - console.log("Fetched instances from server:", response); - - if (response.instances && Array.isArray(response.instances)) { - // Mapeia as instâncias do servidor para o formato correto com userId - const serverInstances: WhatsAppInstance[] = response.instances - .map(serverInstance => { - // Ensure we convert server state to valid connectionState - let connectionState: 'open' | 'closed' | 'connecting'; - const state = serverInstance.state || 'closed'; - - if (state === 'open' || state === 'connecting') { - connectionState = state; - } else { - connectionState = 'closed'; - } - - return { - instanceName: serverInstance.instanceName, - instanceId: serverInstance.instanceName, // Using instanceName as the ID for consistency - phoneNumber: serverInstance.number || 'Desconhecido', - userId: currentUserId, - connectionState: connectionState, - status: connectionState === 'open' ? 'connected' : - connectionState === 'connecting' ? 'connecting' : 'disconnected' - }; - }); - - console.log("Mapped server instances:", serverInstances); - - // Identifica instâncias novas que não existem localmente - const localInstanceIds = new Set(instances.map(i => i.instanceId)); - const newServerInstances = serverInstances.filter(i => !localInstanceIds.has(i.instanceId)); - - // Atualiza instâncias existentes com dados do servidor - const updatedExistingInstances = instances.map(localInstance => { - const serverMatch = serverInstances.find(si => si.instanceId === localInstance.instanceId); - if (serverMatch) { - return { - ...localInstance, - connectionState: serverMatch.connectionState, - status: serverMatch.status - }; - } - return localInstance; - }); - - // Combina tudo - const allInstances = [...updatedExistingInstances, ...newServerInstances]; - - console.log("Combined instances after refresh:", allInstances); - setInstances(allInstances); - - 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 - await checkAllInstancesStatus(); - } - }; - - // Add a new instance - const addInstance = (newInstance: WhatsAppInstance) => { - console.log("New instance created, adding to instances list:", newInstance); - - // Verifica se já existe uma instância com o mesmo ID - const existingIndex = instances.findIndex(inst => inst.instanceId === newInstance.instanceId); - - if (existingIndex >= 0) { - // Atualiza a instância existente - console.log(`Instance with ID ${newInstance.instanceId} already exists, updating it`); - setInstances(prevInstances => - prevInstances.map((instance, index) => - index === existingIndex ? newInstance : instance - ) - ); - } else { - // Adiciona nova instância - setInstances(prevInstances => [...prevInstances, newInstance]); - } - }; - - // Remove an instance - const removeInstance = (instanceId: string) => { - console.log(`Removing instance with ID: ${instanceId}`); - 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) => { - console.log(`Updating instance: ${updatedInstance.instanceName}`, updatedInstance); - setInstances(prevInstances => { - const newInstances = prevInstances.map(instance => - instance.instanceId === updatedInstance.instanceId - ? updatedInstance - : instance - ); - - console.log("Updated instances:", newInstances); - return newInstances; - }); - }; - - return { - instances, - isRefreshing, - currentUserId, - addInstance, - removeInstance, - updateInstance, - refreshInstances, - checkAllInstancesStatus - }; -}; +// Re-export from the refactored location +export { useWhatsAppInstances } from './whatsapp/useWhatsAppInstances'; diff --git a/src/hooks/whatsapp/instanceStatusUtils.ts b/src/hooks/whatsapp/instanceStatusUtils.ts new file mode 100644 index 0000000..8f6c231 --- /dev/null +++ b/src/hooks/whatsapp/instanceStatusUtils.ts @@ -0,0 +1,76 @@ +import { WhatsAppInstance } from '@/types/whatsAppTypes'; +import { fetchConnectionState } from '@/services/whatsAppService'; + +/** + * Checks the connection status for a single WhatsApp instance + */ +export const checkInstanceStatus = async (instance: WhatsAppInstance): Promise => { + try { + console.log(`Checking status for ${instance.instanceName}`); + const state = await fetchConnectionState(instance.instanceName); + console.log(`Status for ${instance.instanceName}: ${state}`); + + // Only update connectionState if it's different + if (instance.connectionState !== state) { + // Ensure the state is one of the valid values or treat as 'closed' + let validState: 'open' | 'closed' | 'connecting'; + if (state === 'open' || state === 'connecting') { + validState = state; + } else { + validState = 'closed'; + } + + return { + ...instance, + connectionState: validState, + status: state === 'open' ? 'connected' : + state === 'connecting' ? 'connecting' : 'disconnected' + }; + } + return instance; + } catch (error) { + console.error(`Error checking status for ${instance.instanceName}:`, error); + + // If the instance doesn't exist on the server, mark it as closed + if (error instanceof Error && error.message.includes("does not exist")) { + return { + ...instance, + connectionState: 'closed' as const, + status: 'disconnected' + }; + } + + // Keep the current state in case of other errors + return instance; + } +}; + +/** + * Maps server instances to the local WhatsAppInstance format + */ +export const mapServerInstancesToLocal = ( + serverInstances: any[], + currentUserId: string +): WhatsAppInstance[] => { + return serverInstances.map(serverInstance => { + // Ensure we convert server state to valid connectionState + let connectionState: 'open' | 'closed' | 'connecting'; + const state = serverInstance.state || 'closed'; + + if (state === 'open' || state === 'connecting') { + connectionState = state; + } else { + connectionState = 'closed'; + } + + return { + instanceName: serverInstance.instanceName, + instanceId: serverInstance.instanceName, // Using instanceName as the ID for consistency + phoneNumber: serverInstance.number || 'Desconhecido', + userId: currentUserId, + connectionState: connectionState, + status: connectionState === 'open' ? 'connected' : + connectionState === 'connecting' ? 'connecting' : 'disconnected' + }; + }); +}; diff --git a/src/hooks/whatsapp/instanceStorageUtils.ts b/src/hooks/whatsapp/instanceStorageUtils.ts new file mode 100644 index 0000000..496c5e9 --- /dev/null +++ b/src/hooks/whatsapp/instanceStorageUtils.ts @@ -0,0 +1,31 @@ + +import { WhatsAppInstance } from '@/types/whatsAppTypes'; + +/** + * Load WhatsApp instances from localStorage for a specific user + */ +export const loadInstancesFromLocalStorage = (userId: string): WhatsAppInstance[] => { + try { + const storedData = localStorage.getItem(`whatsAppInstances_${userId}`); + if (storedData) { + const parsedData = JSON.parse(storedData); + console.log(`Loaded ${parsedData.length} instances from localStorage for user ${userId}`); + return parsedData; + } + } catch (error) { + console.error('Error loading WhatsApp instances from localStorage:', error); + } + return []; +}; + +/** + * Save WhatsApp instances to localStorage for a specific user + */ +export const saveInstancesToLocalStorage = (instances: WhatsAppInstance[], userId: string): void => { + try { + console.log(`Saving ${instances.length} instances to localStorage for user ${userId}`); + localStorage.setItem(`whatsAppInstances_${userId}`, JSON.stringify(instances)); + } catch (error) { + console.error('Error saving WhatsApp instances to localStorage:', error); + } +}; diff --git a/src/hooks/whatsapp/types.ts b/src/hooks/whatsapp/types.ts new file mode 100644 index 0000000..ef3654d --- /dev/null +++ b/src/hooks/whatsapp/types.ts @@ -0,0 +1,18 @@ + +import { WhatsAppInstance } from '@/types/whatsAppTypes'; + +export interface WhatsAppInstancesState { + instances: WhatsAppInstance[]; + currentUserId: string; + isRefreshing: boolean; +} + +export interface WhatsAppInstancesActions { + addInstance: (newInstance: WhatsAppInstance) => void; + removeInstance: (instanceId: string) => void; + updateInstance: (updatedInstance: WhatsAppInstance) => void; + refreshInstances: () => Promise; + checkAllInstancesStatus: () => Promise; +} + +export type WhatsAppInstancesHookReturn = WhatsAppInstancesState & WhatsAppInstancesActions; diff --git a/src/hooks/whatsapp/useWhatsAppInstances.ts b/src/hooks/whatsapp/useWhatsAppInstances.ts new file mode 100644 index 0000000..650fdca --- /dev/null +++ b/src/hooks/whatsapp/useWhatsAppInstances.ts @@ -0,0 +1,196 @@ + +import { useState, useEffect, useCallback } from 'react'; +import { useToast } from '@/hooks/use-toast'; +import { WhatsAppInstance } from '@/types/whatsAppTypes'; +import { fetchAllInstances } from '@/services/whatsAppService'; +import { + loadInstancesFromLocalStorage, + saveInstancesToLocalStorage +} from './instanceStorageUtils'; +import { + checkInstanceStatus, + mapServerInstancesToLocal +} from './instanceStatusUtils'; +import { WhatsAppInstancesHookReturn } from './types'; + +/** + * Hook for managing WhatsApp instances + */ +export const useWhatsAppInstances = (): WhatsAppInstancesHookReturn => { + const { toast } = useToast(); + const [instances, setInstances] = useState([]); + const [currentUserId, setCurrentUserId] = useState(''); + 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); + } + }, []); + + // Save instances to localStorage whenever they change + useEffect(() => { + if (currentUserId && instances.length > 0) { + console.log('Saving instances to localStorage:', instances); + saveInstancesToLocalStorage(instances, currentUserId); + } + }, [instances, currentUserId]); + + // Check connection status for all instances + const checkAllInstancesStatus = useCallback(async () => { + if (instances.length === 0) return; + + console.log(`Checking connection status for ${instances.length} instances`); + + try { + const updatedInstances = await Promise.all( + instances.map(async (instance) => checkInstanceStatus(instance)) + ); + + // Only update state if there are actual changes + const hasChanges = JSON.stringify(updatedInstances) !== JSON.stringify(instances); + if (hasChanges) { + console.log('Updated instances after status check:', updatedInstances); + setInstances(updatedInstances); + } else { + console.log('No changes in instance status'); + } + } catch (error) { + console.error("Error checking instances status:", error); + } + }, [instances]); + + // Refresh instances from the server + 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 { + console.log("Fetching instances from server..."); + const response = await fetchAllInstances(); + console.log("Fetched instances from server:", response); + + if (response.instances && Array.isArray(response.instances)) { + // Map server instances to local format + const serverInstances = mapServerInstancesToLocal(response.instances, currentUserId); + + console.log("Mapped server instances:", serverInstances); + + // Find new instances that don't exist locally + const localInstanceIds = new Set(instances.map(i => i.instanceId)); + const newServerInstances = serverInstances.filter(i => !localInstanceIds.has(i.instanceId)); + + // Update existing instances with server data + const updatedExistingInstances = instances.map(localInstance => { + const serverMatch = serverInstances.find(si => si.instanceId === localInstance.instanceId); + if (serverMatch) { + return { + ...localInstance, + connectionState: serverMatch.connectionState, + status: serverMatch.status + }; + } + return localInstance; + }); + + // Combine everything + const allInstances = [...updatedExistingInstances, ...newServerInstances]; + + console.log("Combined instances after refresh:", allInstances); + setInstances(allInstances); + + 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); + // Check status after updating the list + await checkAllInstancesStatus(); + } + }; + + // Add a new instance + const addInstance = (newInstance: WhatsAppInstance) => { + console.log("New instance created, adding to instances list:", newInstance); + + // Check if instance with same ID already exists + const existingIndex = instances.findIndex(inst => inst.instanceId === newInstance.instanceId); + + if (existingIndex >= 0) { + // Update existing instance + console.log(`Instance with ID ${newInstance.instanceId} already exists, updating it`); + setInstances(prevInstances => + prevInstances.map((instance, index) => + index === existingIndex ? newInstance : instance + ) + ); + } else { + // Add new instance + setInstances(prevInstances => [...prevInstances, newInstance]); + } + }; + + // Remove an instance + const removeInstance = (instanceId: string) => { + console.log(`Removing instance with ID: ${instanceId}`); + 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) => { + console.log(`Updating instance: ${updatedInstance.instanceName}`, updatedInstance); + setInstances(prevInstances => { + const newInstances = prevInstances.map(instance => + instance.instanceId === updatedInstance.instanceId + ? updatedInstance + : instance + ); + + console.log("Updated instances:", newInstances); + return newInstances; + }); + }; + + return { + instances, + isRefreshing, + currentUserId, + addInstance, + removeInstance, + updateInstance, + refreshInstances, + checkAllInstancesStatus + }; +};