REFACTOR: Preparação para novos tipos de chat

This commit is contained in:
Rafael Alves Lopes 2026-06-01 17:45:13 -03:00
parent 8b85971371
commit 9ba7d0fb84
2 changed files with 128 additions and 96 deletions

View File

@ -1,6 +1,5 @@
import { useEffect, useMemo, useRef, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
import { useWhatsappSocket } from '../../../shared/hooks/useWhatsappSocket'; import { useWhatsappSocket } from '../../../shared/hooks/useWhatsappSocket';
import { API_BASE_URL } from '../../../shared/services/apiConfig';
import { getAccessOptions, getAccessUsers } from '../../management/services/adminAccessService'; import { getAccessOptions, getAccessUsers } from '../../management/services/adminAccessService';
import { getCurrentUser, getCurrentUserProfile } from '../../auth/services/sessionService'; import { getCurrentUser, getCurrentUserProfile } from '../../auth/services/sessionService';
import { transferAreas as fallbackTransferAreas } from '../services/chatMocks'; import { transferAreas as fallbackTransferAreas } from '../services/chatMocks';
@ -10,6 +9,16 @@ import {
pauseAgent, pauseAgent,
resumeAgent, resumeAgent,
} from '../services/agentPresenceService'; } from '../services/agentPresenceService';
import {
assignWhatsappChat,
closeWhatsappChat,
getWhatsappMessageMedia,
listWhatsappChats,
listWhatsappMessages,
releaseWhatsappChat,
sendWhatsappMessage,
transferWhatsappChat,
} from '../services/whatsappChatService';
const MAX_ATTACHMENT_SIZE_BYTES = 15 * 1024 * 1024; const MAX_ATTACHMENT_SIZE_BYTES = 15 * 1024 * 1024;
@ -412,9 +421,7 @@ export function useChat() {
setIsLoadingChats(true); setIsLoadingChats(true);
} }
try { try {
const response = await fetch(`${API_BASE_URL}/whatsapp/chats`); const data = await listWhatsappChats();
if (!response.ok) throw new Error('Falha ao carregar chats do WhatsApp.');
const data = await response.json();
if (!Array.isArray(data)) return; if (!Array.isArray(data)) return;
const nextContacts = data.map(normalizeChat).filter(canSeeContact); const nextContacts = data.map(normalizeChat).filter(canSeeContact);
@ -454,9 +461,7 @@ export function useChat() {
if (!activeContactId.includes('@')) return; if (!activeContactId.includes('@')) return;
setIsLoadingMessages(true); setIsLoadingMessages(true);
try { try {
const response = await fetch(`${API_BASE_URL}/whatsapp/messages/${encodeURIComponent(activeContactId)}`); const data = await listWhatsappMessages(activeContactId);
if (!response.ok) throw new Error('Falha ao carregar mensagens do WhatsApp.');
const data = await response.json();
if (!isMounted || !Array.isArray(data)) return; if (!isMounted || !Array.isArray(data)) return;
const normalizedMessages = dedupeMessages( const normalizedMessages = dedupeMessages(
data data
@ -601,11 +606,7 @@ export function useChat() {
})); }));
try { try {
const response = await fetch( const media = await getWhatsappMessageMedia(contactId, messageId);
`${API_BASE_URL}/whatsapp/media/${encodeURIComponent(contactId)}/${encodeURIComponent(messageId)}`,
);
if (!response.ok) throw new Error('Falha ao carregar mídia.');
const media = await response.json();
setMessagesByContact((current) => ({ setMessagesByContact((current) => ({
...current, ...current,
[contactId]: (current[contactId] || []).map((message) => [contactId]: (current[contactId] || []).map((message) =>
@ -630,18 +631,11 @@ export function useChat() {
const targetAssignment = targetContact?.assignment || null; const targetAssignment = targetContact?.assignment || null;
const areaId = targetContact?.areaId || targetAssignment?.area_id || areaOptions.find((area) => currentUserAreas.includes(area.nome))?.id; const areaId = targetContact?.areaId || targetAssignment?.area_id || areaOptions.find((area) => currentUserAreas.includes(area.nome))?.id;
try { try {
const response = await fetch(`${API_BASE_URL}/whatsapp/assign`, { const assignment = await assignWhatsappChat({
method: 'POST', chatId: contactId,
headers: { 'Content-Type': 'application/json' }, userId: String(currentUserId),
body: JSON.stringify({ areaId,
chatId: contactId,
userId: String(currentUserId),
areaId,
}),
}); });
if (!response.ok) throw new Error('Não foi possível assumir o atendimento.');
const assignment = await response.json();
updateContact(contactId, (contact) => ({ updateContact(contactId, (contact) => ({
...contact, ...contact,
assignment, assignment,
@ -658,18 +652,19 @@ export function useChat() {
async function releaseChat() { async function releaseChat() {
if (!activeContactId?.includes('@')) return; if (!activeContactId?.includes('@')) return;
const response = await fetch(`${API_BASE_URL}/whatsapp/release/${encodeURIComponent(activeContactId)}`, {
method: 'DELETE',
});
if (!response.ok) throw new Error('Não foi possível sair do atendimento.'); try {
const assignment = await response.json(); const assignment = await releaseWhatsappChat(activeContactId);
updateContact(activeContactId, (contact) => ({ updateContact(activeContactId, (contact) => ({
...contact, ...contact,
assignment, assignment,
area: assignment?.area_nome || contact.area, area: assignment?.area_nome || contact.area,
areaId: assignment?.area_id || contact.areaId, areaId: assignment?.area_id || contact.areaId,
})); }));
setApiError(null);
} catch (error) {
setApiError(error.message);
}
} }
async function closeChat() { async function closeChat() {
@ -679,17 +674,11 @@ export function useChat() {
if (!confirmed) return; if (!confirmed) return;
try { try {
const response = await fetch(`${API_BASE_URL}/whatsapp/close`, { await closeWhatsappChat({
method: 'POST', chatId: activeContactId,
headers: { 'Content-Type': 'application/json' }, userId: currentUserId,
body: JSON.stringify({
chatId: activeContactId,
userId: currentUserId,
}),
}); });
if (!response.ok) throw new Error('Não foi possível encerrar o atendimento.');
setContacts((current) => current.filter((contact) => contact.id !== activeContactId)); setContacts((current) => current.filter((contact) => contact.id !== activeContactId));
setMessagesByContact((current) => { setMessagesByContact((current) => {
const next = { ...current }; const next = { ...current };
@ -798,25 +787,13 @@ export function useChat() {
if (!contactId.includes('@')) return; if (!contactId.includes('@')) return;
try { try {
const response = await fetch(`${API_BASE_URL}/whatsapp/send`, { await sendWhatsappMessage({
method: 'POST', to: contactId,
headers: { 'Content-Type': 'application/json' }, message: trimmed,
body: JSON.stringify({ senderName: getUserDisplayName(currentUser),
to: contactId, media,
message: trimmed,
senderName: getUserDisplayName(currentUser),
media,
}),
}); });
if (!response.ok) {
const message =
response.status === 413
? 'Arquivo muito grande para envio. Tente uma mídia menor.'
: 'Não foi possível enviar a mensagem.';
throw new Error(message);
}
setApiError(null); setApiError(null);
updateContact(contactId, (contact) => ({ updateContact(contactId, (contact) => ({
...contact, ...contact,
@ -825,7 +802,11 @@ export function useChat() {
: contact.assignment, : contact.assignment,
})); }));
} catch (error) { } catch (error) {
setApiError(error.message); setApiError(
error.status === 413
? 'Arquivo muito grande para envio. Tente uma midia menor.'
: error.message,
);
} }
} }
@ -834,7 +815,7 @@ export function useChat() {
const areaId = selectedTransferArea?.id; const areaId = selectedTransferArea?.id;
if (!areaId) { if (!areaId) {
setApiError('Selecione uma especialidade válida para transferência.'); setApiError('Selecione uma especialidade valida para transferencia.');
return; return;
} }
@ -844,47 +825,40 @@ export function useChat() {
} }
const targetUserId = isSameUserArea && transferAttendant ? Number(transferAttendant) : null; const targetUserId = isSameUserArea && transferAttendant ? Number(transferAttendant) : null;
const response = await fetch(`${API_BASE_URL}/whatsapp/transfer`, {
method: 'POST', try {
headers: { 'Content-Type': 'application/json' }, const assignment = await transferWhatsappChat({
body: JSON.stringify({
chatId: activeContactId, chatId: activeContactId,
areaId, areaId,
userId: targetUserId, userId: targetUserId,
note, note,
}), });
}); const transferMessage = targetUserId
? `Transferencia solicitada para ${transferArea}. Obs: ${note || 'Sem observacao.'}`
: `Transferencia enviada para a fila de ${transferArea}. Obs: ${note || 'Sem observacao.'}`;
if (!response.ok) { setMessagesByContact((current) => ({
setApiError('Não foi possível transferir o atendimento.'); ...current,
return; [activeContactId]: [
...(current[activeContactId] || []),
{ id: Date.now() + 2, sender: 'system', text: transferMessage },
],
}));
updateContact(activeContactId, (contact) => ({
...contact,
area: assignment.area_nome || transferArea,
areaId: assignment.area_id || areaId,
assignment,
}));
setSelectedArea(transferArea);
setIsTransferOpen(false);
setTransferNote('');
setApiError(null);
} catch (error) {
setApiError(error.message);
} }
const assignment = await response.json();
const transferMessage = targetUserId
? `Transferência solicitada para ${transferArea}. Obs: ${note || 'Sem observação.'}`
: `Transferência enviada para a fila de ${transferArea}. Obs: ${note || 'Sem observação.'}`;
setMessagesByContact((current) => ({
...current,
[activeContactId]: [
...(current[activeContactId] || []),
{ id: Date.now() + 2, sender: 'system', text: transferMessage },
],
}));
updateContact(activeContactId, (contact) => ({
...contact,
area: assignment.area_nome || transferArea,
areaId: assignment.area_id || areaId,
assignment,
}));
setSelectedArea(transferArea);
setIsTransferOpen(false);
setTransferNote('');
setApiError(null);
} }
return { return {
currentUserId, currentUserId,
contacts, contacts,

View File

@ -0,0 +1,58 @@
import { apiRequest } from '../../../shared/services/apiClient';
export function listWhatsappChats() {
return apiRequest('/whatsapp/chats', {
fallbackMessage: 'Falha ao carregar chats do WhatsApp.',
});
}
export function listWhatsappMessages(chatId) {
return apiRequest(`/whatsapp/messages/${encodeURIComponent(chatId)}`, {
fallbackMessage: 'Falha ao carregar mensagens do WhatsApp.',
});
}
export function getWhatsappMessageMedia(chatId, messageId) {
return apiRequest(`/whatsapp/media/${encodeURIComponent(chatId)}/${encodeURIComponent(messageId)}`, {
fallbackMessage: 'Falha ao carregar midia.',
});
}
export function assignWhatsappChat(payload) {
return apiRequest('/whatsapp/assign', {
method: 'POST',
body: JSON.stringify(payload),
fallbackMessage: 'Nao foi possivel assumir o atendimento.',
});
}
export function releaseWhatsappChat(chatId) {
return apiRequest(`/whatsapp/release/${encodeURIComponent(chatId)}`, {
method: 'DELETE',
fallbackMessage: 'Nao foi possivel sair do atendimento.',
});
}
export function closeWhatsappChat(payload) {
return apiRequest('/whatsapp/close', {
method: 'POST',
body: JSON.stringify(payload),
fallbackMessage: 'Nao foi possivel encerrar o atendimento.',
});
}
export function sendWhatsappMessage(payload) {
return apiRequest('/whatsapp/send', {
method: 'POST',
body: JSON.stringify(payload),
fallbackMessage: 'Nao foi possivel enviar a mensagem.',
});
}
export function transferWhatsappChat(payload) {
return apiRequest('/whatsapp/transfer', {
method: 'POST',
body: JSON.stringify(payload),
fallbackMessage: 'Nao foi possivel transferir o atendimento.',
});
}