From 908904f9b904ebdc8b94a385057ad4764213aa9f Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 23:59:46 +0000 Subject: [PATCH] Refactor: Split useWhatsAppInstances hook Split the `useWhatsAppInstances.ts` hook into smaller, more manageable files to improve code organization and readability. --- src/hooks/useWhatsAppInstances.ts | 262 ++----------------- src/hooks/whatsApp/useInstanceOperations.ts | 59 +++++ src/hooks/whatsApp/useInstanceRefresh.ts | 104 ++++++++ src/hooks/whatsApp/useInstanceState.ts | 45 ++++ src/hooks/whatsApp/useInstanceStatusCheck.ts | 78 ++++++ 5 files changed, 315 insertions(+), 233 deletions(-) create mode 100644 src/hooks/whatsApp/useInstanceOperations.ts create mode 100644 src/hooks/whatsApp/useInstanceRefresh.ts create mode 100644 src/hooks/whatsApp/useInstanceState.ts create mode 100644 src/hooks/whatsApp/useInstanceStatusCheck.ts diff --git a/src/hooks/useWhatsAppInstances.ts b/src/hooks/useWhatsAppInstances.ts index b8033d0..cb68383 100644 --- a/src/hooks/useWhatsAppInstances.ts +++ b/src/hooks/useWhatsAppInstances.ts @@ -1,242 +1,38 @@ -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'; +import { useInstanceState } from './whatsApp/useInstanceState'; +import { useInstanceOperations } from './whatsApp/useInstanceOperations'; +import { useInstanceStatusCheck } from './whatsApp/useInstanceStatusCheck'; +import { useInstanceRefresh } from './whatsApp/useInstanceRefresh'; export const useWhatsAppInstances = () => { - const { toast } = useToast(); - const [instances, setInstances] = useState([]); - const [currentUserId, setCurrentUserId] = useState(''); - const [isRefreshing, setIsRefreshing] = useState(false); - const [isCheckingStatus, setIsCheckingStatus] = useState(false); + const { + instances, + setInstances, + currentUserId, + isRefreshing, + setIsRefreshing, + isCheckingStatus, + setIsCheckingStatus + } = useInstanceState(); - // 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 + const { addInstance, removeInstance, updateInstance } = useInstanceOperations( + instances, + setInstances + ); - // 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 || isCheckingStatus) return; - - console.log(`Checking connection status for ${instances.length} instances`); - setIsCheckingStatus(true); - - 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); - } finally { - setIsCheckingStatus(false); - } - }, [instances, isCheckingStatus]); + const { checkAllInstancesStatus } = useInstanceStatusCheck( + instances, + setInstances, + isCheckingStatus, + setIsCheckingStatus + ); - // 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); - } - }; - - // 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; - }); - }; + const { refreshInstances } = useInstanceRefresh( + instances, + setInstances, + currentUserId, + setIsRefreshing + ); return { instances, diff --git a/src/hooks/whatsApp/useInstanceOperations.ts b/src/hooks/whatsApp/useInstanceOperations.ts new file mode 100644 index 0000000..4303a77 --- /dev/null +++ b/src/hooks/whatsApp/useInstanceOperations.ts @@ -0,0 +1,59 @@ + +import { WhatsAppInstance } from '@/types/whatsAppTypes'; + +export const useInstanceOperations = ( + instances: WhatsAppInstance[], + setInstances: React.Dispatch> +) => { + // 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 { + addInstance, + removeInstance, + updateInstance + }; +}; diff --git a/src/hooks/whatsApp/useInstanceRefresh.ts b/src/hooks/whatsApp/useInstanceRefresh.ts new file mode 100644 index 0000000..6554006 --- /dev/null +++ b/src/hooks/whatsApp/useInstanceRefresh.ts @@ -0,0 +1,104 @@ + +import { useToast } from '@/hooks/use-toast'; +import { WhatsAppInstance } from '@/types/whatsAppTypes'; +import { fetchAllInstances } from '@/services/whatsApp/instanceManagement'; + +export const useInstanceRefresh = ( + instances: WhatsAppInstance[], + setInstances: React.Dispatch>, + currentUserId: string, + setIsRefreshing: React.Dispatch> +) => { + const { toast } = useToast(); + + // 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); + } + }; + + return { refreshInstances }; +}; diff --git a/src/hooks/whatsApp/useInstanceState.ts b/src/hooks/whatsApp/useInstanceState.ts new file mode 100644 index 0000000..c8d85bd --- /dev/null +++ b/src/hooks/whatsApp/useInstanceState.ts @@ -0,0 +1,45 @@ + +import { useState, useEffect } from 'react'; +import { WhatsAppInstance } from '@/types/whatsAppTypes'; +import { + saveInstancesToLocalStorage, + loadInstancesFromLocalStorage +} from '@/services/whatsApp/localStorage'; + +export const useInstanceState = () => { + const [instances, setInstances] = useState([]); + const [currentUserId, setCurrentUserId] = useState(''); + const [isRefreshing, setIsRefreshing] = useState(false); + const [isCheckingStatus, setIsCheckingStatus] = 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]); + + return { + instances, + setInstances, + currentUserId, + isRefreshing, + setIsRefreshing, + isCheckingStatus, + setIsCheckingStatus + }; +}; diff --git a/src/hooks/whatsApp/useInstanceStatusCheck.ts b/src/hooks/whatsApp/useInstanceStatusCheck.ts new file mode 100644 index 0000000..91e8a12 --- /dev/null +++ b/src/hooks/whatsApp/useInstanceStatusCheck.ts @@ -0,0 +1,78 @@ +import { useCallback } from 'react'; +import { WhatsAppInstance } from '@/types/whatsAppTypes'; +import { fetchConnectionState } from '@/services/whatsApp/instanceManagement'; + +export const useInstanceStatusCheck = ( + instances: WhatsAppInstance[], + setInstances: React.Dispatch>, + isCheckingStatus: boolean, + setIsCheckingStatus: React.Dispatch> +) => { + // Function to check connection status for all instances + const checkAllInstancesStatus = useCallback(async () => { + if (instances.length === 0 || isCheckingStatus) return; + + console.log(`Checking connection status for ${instances.length} instances`); + setIsCheckingStatus(true); + + 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); + } finally { + setIsCheckingStatus(false); + } + }, [instances, isCheckingStatus, setInstances, setIsCheckingStatus]); + + return { checkAllInstancesStatus }; +};