Refactor: Split WhatsApp service into modules

Split `whatsAppService.ts` into smaller files for API calls, local storage, and types to improve maintainability.
This commit is contained in:
gpt-engineer-app[bot] 2025-05-19 23:05:13 +00:00
parent 90b3030ebb
commit 2eba5aa7b1
8 changed files with 316 additions and 298 deletions

View File

@ -147,6 +147,42 @@ export type Database = {
}
Relationships: []
}
rodrigo_audio_messages: {
Row: {
audio_url: string | null
created_at: string
duration: number | null
id: string
instance_id: string
message_id: string | null
metadata: Json | null
sender_id: string
sender_name: string | null
}
Insert: {
audio_url?: string | null
created_at?: string
duration?: number | null
id?: string
instance_id: string
message_id?: string | null
metadata?: Json | null
sender_id: string
sender_name?: string | null
}
Update: {
audio_url?: string | null
created_at?: string
duration?: number | null
id?: string
instance_id?: string
message_id?: string | null
metadata?: Json | null
sender_id?: string
sender_name?: string | null
}
Relationships: []
}
transacoes: {
Row: {
categoria: string | null
@ -154,6 +190,7 @@ export type Database = {
detalhes: string | null
estabelecimento: string | null
id: number
login: string | null
quando: string | null
tipo: string | null
user: string | null
@ -165,6 +202,7 @@ export type Database = {
detalhes?: string | null
estabelecimento?: string | null
id?: number
login?: string | null
quando?: string | null
tipo?: string | null
user?: string | null
@ -176,6 +214,7 @@ export type Database = {
detalhes?: string | null
estabelecimento?: string | null
id?: number
login?: string | null
quando?: string | null
tipo?: string | null
user?: string | null

View File

@ -0,0 +1,35 @@
import { SERVER_URL, API_KEY } from './config';
/**
* Makes an API request to the WhatsApp server
*/
export const makeRequest = async <T>(
endpoint: string,
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
body?: object
): Promise<T> => {
const url = `https://${SERVER_URL}${endpoint}`;
console.log(`Making ${method} request to: ${url}`);
const options: RequestInit = {
method,
headers: {
'Content-Type': 'application/json',
'apikey': API_KEY
},
body: body ? JSON.stringify(body) : undefined
};
const response = await fetch(url, options);
if (!response.ok) {
const errorData = await response.json();
console.error(`API error (${response.status}):`, errorData);
throw new Error(errorData.message || `API request failed with status ${response.status}`);
}
const data = await response.json();
return data as T;
};

View File

@ -0,0 +1,7 @@
// WhatsApp API configuration
export const SERVER_URL = "evolutionapi2.innova1001.com.br";
export const API_KEY = "beeb77fbd7f48f91db2cd539a573c130";
// Local storage key
export const STORAGE_KEY = 'whatsappInstances';

View File

@ -0,0 +1,5 @@
// Re-export all functions from the service modules
export * from './instanceManagement';
export * from './instanceActions';
export * from './localStorage';

View File

@ -0,0 +1,70 @@
import { makeRequest } from './apiHelpers';
/**
* Restarts a WhatsApp instance
*/
export const restartInstance = async (instanceName: string): Promise<any> => {
try {
console.log(`Restarting instance: ${instanceName}`);
const data = await makeRequest(`/instance/restart/${encodeURIComponent(instanceName)}`, 'PUT');
console.log(`Restart response for ${instanceName}:`, data);
return data;
} catch (error) {
console.error(`Error restarting instance ${instanceName}:`, error);
throw error;
}
};
/**
* Logs out (disconnects) a WhatsApp instance
*/
export const logoutInstance = async (instanceName: string): Promise<any> => {
try {
console.log(`Logging out instance: ${instanceName}`);
const data = await makeRequest(`/instance/logout/${encodeURIComponent(instanceName)}`, 'DELETE');
console.log(`Logout response for ${instanceName}:`, data);
return data;
} catch (error) {
console.error(`Error logging out instance ${instanceName}:`, error);
throw error;
}
};
/**
* Deletes a WhatsApp instance
*/
export const deleteInstance = async (instanceName: string): Promise<any> => {
try {
console.log(`Deleting instance: ${instanceName}`);
const data = await makeRequest(`/instance/${encodeURIComponent(instanceName)}`, 'DELETE');
console.log(`Delete response for ${instanceName}:`, data);
return data;
} catch (error) {
console.error(`Error deleting instance ${instanceName}:`, error);
throw error;
}
};
/**
* Sets the online/offline presence status for an instance
*/
export const setInstancePresence = async (instanceName: string, presence: 'online' | 'offline'): Promise<any> => {
try {
console.log(`Setting presence to ${presence} for: ${instanceName}`);
const data = await makeRequest(`/instance/setPresence/${encodeURIComponent(instanceName)}`, 'POST', { presence });
console.log(`Set presence response for ${instanceName}:`, data);
return data;
} catch (error) {
console.error(`Error setting presence to ${presence} for instance ${instanceName}:`, error);
throw error;
}
};

View File

@ -0,0 +1,73 @@
import { makeRequest } from './apiHelpers';
/**
* Creates a new WhatsApp instance
*/
export const createWhatsAppInstance = async (
instanceName: string,
phoneNumber: string
): Promise<any> => {
console.log(`Creating new WhatsApp instance: ${instanceName}, ${phoneNumber}`);
const data = await makeRequest('/instance/create', 'POST', {
instanceName: instanceName,
number: phoneNumber,
qrcode: true,
integration: "WHATSAPP-BAILEYS"
});
console.log('Create instance API response:', data);
return data;
};
/**
* Fetches QR code for an instance
*/
export const fetchQrCode = async (instanceName: string): Promise<any> => {
console.log(`Fetching QR code for instance: ${instanceName}`);
const data = await makeRequest(`/instance/connect/${encodeURIComponent(instanceName)}`, 'GET');
console.log('QR code fetch response:', data);
return data;
};
/**
* Fetches connection state for an instance
*/
export const fetchConnectionState = async (instanceName: string): Promise<'open' | 'closed' | 'connecting'> => {
try {
console.log(`Fetching connection state for: ${instanceName}`);
const data = await makeRequest(`/instance/connectionState/${encodeURIComponent(instanceName)}`, 'GET');
console.log(`Connection state for ${instanceName}:`, data);
return data.instance?.state || 'closed';
} catch (error) {
console.error(`Error fetching connection state for ${instanceName}:`, error);
if (error instanceof Error && error.message.includes("does not exist")) {
throw error; // Rethrow specific "does not exist" errors
}
return 'closed';
}
};
/**
* Fetches all WhatsApp instances
*/
export const fetchAllInstances = async (): Promise<any> => {
try {
console.log('Fetching all instances');
const data = await makeRequest('/fetch-instances', 'GET');
console.log('All instances response:', data);
return data;
} catch (error) {
console.error("Error fetching all instances:", error);
throw error;
}
};

View File

@ -0,0 +1,80 @@
import { WhatsAppInstance } from '@/types/whatsAppTypes';
import { STORAGE_KEY } from './config';
/**
* Saves WhatsApp instances to localStorage
*/
export const saveInstancesToLocalStorage = (
instances: WhatsAppInstance[],
currentUserId: string
): void => {
try {
console.log(`Saving ${instances.length} instances for user ${currentUserId}`);
// Get existing instances from localStorage
const savedInstancesStr = localStorage.getItem(STORAGE_KEY);
let allInstances: WhatsAppInstance[] = [];
if (savedInstancesStr) {
try {
// Parse saved instances
const savedInstances = JSON.parse(savedInstancesStr);
// If it's an array, filter out current user's old instances
if (Array.isArray(savedInstances)) {
allInstances = savedInstances.filter(
(instance: WhatsAppInstance) => instance.userId !== currentUserId
);
}
} catch (parseError) {
console.error('Error parsing stored instances, resetting:', parseError);
}
}
// Add current user's instances to the array
const updatedInstances = [...allInstances, ...instances];
// Save back to localStorage
localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedInstances));
console.log('All WhatsApp instances saved to localStorage:', updatedInstances);
} catch (error) {
console.error('Error saving instances to localStorage:', error);
}
};
/**
* Loads WhatsApp instances from localStorage for a specific user
*/
export const loadInstancesFromLocalStorage = (
userId: string
): WhatsAppInstance[] => {
try {
console.log(`Loading instances for user: ${userId}`);
const savedInstancesStr = localStorage.getItem(STORAGE_KEY);
console.log('Raw saved instances from localStorage:', savedInstancesStr);
if (savedInstancesStr && userId) {
try {
// Parse saved instances
const allInstances = JSON.parse(savedInstancesStr);
// If it's an array, filter by user ID
if (Array.isArray(allInstances)) {
// Filter instances to only show those belonging to the current user
const userInstances = allInstances.filter(
(instance: WhatsAppInstance) => instance.userId === userId
);
console.log(`Found ${userInstances.length} instances for user ${userId}:`, userInstances);
return userInstances;
}
} catch (parseError) {
console.error('Error parsing stored instances:', parseError);
}
}
console.log(`No instances found for user ${userId}`);
return [];
} catch (error) {
console.error("Error loading instances from localStorage:", error);
return [];
}
};

View File

@ -1,301 +1,10 @@
import { WhatsAppInstance } from '@/types/whatsAppTypes';
// This file is kept for backwards compatibility
// It re-exports all WhatsApp service functions from their new modular structure
const SERVER_URL = "evolutionapi2.innova1001.com.br";
const API_KEY = "beeb77fbd7f48f91db2cd539a573c130";
export * from './whatsApp/instanceManagement';
export * from './whatsApp/instanceActions';
export * from './whatsApp/localStorage';
// Local storage key
const STORAGE_KEY = 'whatsappInstances';
export const createWhatsAppInstance = async (
instanceName: string,
phoneNumber: string
): Promise<any> => {
console.log(`Creating new WhatsApp instance: ${instanceName}, ${phoneNumber}`);
const response = await fetch(`https://${SERVER_URL}/instance/create`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': API_KEY
},
body: JSON.stringify({
instanceName: instanceName,
number: phoneNumber,
qrcode: true,
integration: "WHATSAPP-BAILEYS"
})
});
if (!response.ok) {
const errorData = await response.json();
console.error('Error creating instance:', errorData);
throw new Error(errorData.message || 'Erro ao criar instância');
}
const data = await response.json();
console.log('Create instance API response:', data);
return data;
};
export const fetchQrCode = async (instanceName: string): Promise<any> => {
console.log(`Fetching QR code for instance: ${instanceName}`);
const response = await fetch(`https://${SERVER_URL}/instance/connect/${encodeURIComponent(instanceName)}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'apikey': API_KEY
}
});
if (!response.ok) {
const errorData = await response.json();
console.error('Error fetching QR code:', errorData);
throw new Error(errorData.message || 'Erro ao obter QR Code');
}
const data = await response.json();
console.log('QR code fetch response:', data);
return data;
};
export const fetchConnectionState = async (instanceName: string): Promise<'open' | 'closed' | 'connecting'> => {
try {
console.log(`Fetching connection state for: ${instanceName}`);
const response = await fetch(`https://${SERVER_URL}/instance/connectionState/${encodeURIComponent(instanceName)}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'apikey': API_KEY
}
});
if (!response.ok) {
const errorData = await response.json();
console.error(`Connection state error for ${instanceName}:`, errorData);
// If instance doesn't exist, throw a specific error
if (response.status === 404) {
throw new Error(`The "${instanceName}" instance does not exist`);
}
return 'closed';
}
const data = await response.json();
console.log(`Connection state for ${instanceName}:`, data);
return data.instance?.state || 'closed';
} catch (error) {
console.error(`Error fetching connection state for ${instanceName}:`, error);
if (error instanceof Error && error.message.includes("does not exist")) {
throw error; // Rethrow specific "does not exist" errors
}
return 'closed';
}
};
// Nova função para listar todas as instâncias
export const fetchAllInstances = async (): Promise<any> => {
try {
console.log('Fetching all instances');
const response = await fetch(`https://${SERVER_URL}/fetch-instances`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'apikey': API_KEY
}
});
if (!response.ok) {
const errorData = await response.json();
console.error('Error fetching instances:', errorData);
throw new Error(errorData.message || 'Erro ao buscar instâncias');
}
const data = await response.json();
console.log('All instances response:', data);
return data;
} catch (error) {
console.error("Error fetching all instances:", error);
throw error;
}
};
// Função para reiniciar uma instância
export const restartInstance = async (instanceName: string): Promise<any> => {
try {
console.log(`Restarting instance: ${instanceName}`);
const response = await fetch(`https://${SERVER_URL}/instance/restart/${encodeURIComponent(instanceName)}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'apikey': API_KEY
}
});
if (!response.ok) {
const errorData = await response.json();
console.error(`Error restarting instance ${instanceName}:`, errorData);
throw new Error(errorData.message || 'Erro ao reiniciar instância');
}
const data = await response.json();
console.log(`Restart response for ${instanceName}:`, data);
return data;
} catch (error) {
console.error(`Error restarting instance ${instanceName}:`, error);
throw error;
}
};
// Função para desconectar (logout) uma instância
export const logoutInstance = async (instanceName: string): Promise<any> => {
try {
console.log(`Logging out instance: ${instanceName}`);
const response = await fetch(`https://${SERVER_URL}/instance/logout/${encodeURIComponent(instanceName)}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'apikey': API_KEY
}
});
if (!response.ok) {
const errorData = await response.json();
console.error(`Error logging out instance ${instanceName}:`, errorData);
throw new Error(errorData.message || 'Erro ao desconectar instância');
}
const data = await response.json();
console.log(`Logout response for ${instanceName}:`, data);
return data;
} catch (error) {
console.error(`Error logging out instance ${instanceName}:`, error);
throw error;
}
};
// Função para excluir uma instância
export const deleteInstance = async (instanceName: string): Promise<any> => {
try {
console.log(`Deleting instance: ${instanceName}`);
const response = await fetch(`https://${SERVER_URL}/instance/${encodeURIComponent(instanceName)}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'apikey': API_KEY
}
});
if (!response.ok) {
const errorData = await response.json();
console.error(`Error deleting instance ${instanceName}:`, errorData);
throw new Error(errorData.message || 'Erro ao excluir instância');
}
const data = await response.json();
console.log(`Delete response for ${instanceName}:`, data);
return data;
} catch (error) {
console.error(`Error deleting instance ${instanceName}:`, error);
throw error;
}
};
// Função para definir presença online/offline
export const setInstancePresence = async (instanceName: string, presence: 'online' | 'offline'): Promise<any> => {
try {
console.log(`Setting presence to ${presence} for: ${instanceName}`);
const response = await fetch(`https://${SERVER_URL}/instance/setPresence/${encodeURIComponent(instanceName)}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': API_KEY
},
body: JSON.stringify({ presence })
});
if (!response.ok) {
const errorData = await response.json();
console.error(`Error setting presence for ${instanceName}:`, errorData);
throw new Error(errorData.message || `Erro ao definir presença para ${presence}`);
}
const data = await response.json();
console.log(`Set presence response for ${instanceName}:`, data);
return data;
} catch (error) {
console.error(`Error setting presence to ${presence} for instance ${instanceName}:`, error);
throw error;
}
};
export const saveInstancesToLocalStorage = (
instances: WhatsAppInstance[],
currentUserId: string
): void => {
try {
console.log(`Saving ${instances.length} instances for user ${currentUserId}`);
// Get existing instances from localStorage
const savedInstancesStr = localStorage.getItem(STORAGE_KEY);
let allInstances: WhatsAppInstance[] = [];
if (savedInstancesStr) {
try {
// Parse saved instances
const savedInstances = JSON.parse(savedInstancesStr);
// If it's an array, filter out current user's old instances
if (Array.isArray(savedInstances)) {
allInstances = savedInstances.filter(
(instance: WhatsAppInstance) => instance.userId !== currentUserId
);
}
} catch (parseError) {
console.error('Error parsing stored instances, resetting:', parseError);
}
}
// Add current user's instances to the array
const updatedInstances = [...allInstances, ...instances];
// Save back to localStorage
localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedInstances));
console.log('All WhatsApp instances saved to localStorage:', updatedInstances);
} catch (error) {
console.error('Error saving instances to localStorage:', error);
}
};
export const loadInstancesFromLocalStorage = (
userId: string
): WhatsAppInstance[] => {
try {
console.log(`Loading instances for user: ${userId}`);
const savedInstancesStr = localStorage.getItem(STORAGE_KEY);
console.log('Raw saved instances from localStorage:', savedInstancesStr);
if (savedInstancesStr && userId) {
try {
// Parse saved instances
const allInstances = JSON.parse(savedInstancesStr);
// If it's an array, filter by user ID
if (Array.isArray(allInstances)) {
// Filter instances to only show those belonging to the current user
const userInstances = allInstances.filter(
(instance: WhatsAppInstance) => instance.userId === userId
);
console.log(`Found ${userInstances.length} instances for user ${userId}:`, userInstances);
return userInstances;
}
} catch (parseError) {
console.error('Error parsing stored instances:', parseError);
}
}
console.log(`No instances found for user ${userId}`);
return [];
} catch (error) {
console.error("Error loading instances from localStorage:", error);
return [];
}
};
// Export config values if needed by other parts of the app
export { SERVER_URL, API_KEY, STORAGE_KEY } from './whatsApp/config';