FEAT: Agora é possível enviar media utilizando a meta API #1

Merged
rafael.lopes merged 2 commits from feat/send-media into dev 2026-07-22 17:49:46 -03:00
3 changed files with 37 additions and 36 deletions
Showing only changes of commit a6a88ab0c1 - Show all commits

View File

@ -188,7 +188,7 @@ function MediaRenderer({ message, isAgent }) {
function AttachmentPreview({ file, onRemove }) { function AttachmentPreview({ file, onRemove }) {
if (!file) return null; if (!file) return null;
const mediaUrl = getMediaUrl({ data: file.data, mimetype: file.type }); const mediaUrl = file.previewUrl || '';
return ( return (
<div <div
@ -203,7 +203,7 @@ function AttachmentPreview({ file, onRemove }) {
background: '#fff', background: '#fff',
}} }}
> >
{file.type?.startsWith('image/') ? ( {file.type?.startsWith('image/') && mediaUrl ? (
<img <img
src={mediaUrl} src={mediaUrl}
alt={file.name} alt={file.name}

View File

@ -16,11 +16,12 @@ import {
listWhatsappChats, listWhatsappChats,
listWhatsappMessages, listWhatsappMessages,
releaseWhatsappChat, releaseWhatsappChat,
sendWhatsappMedia,
sendWhatsappMessage, sendWhatsappMessage,
transferWhatsappChat, transferWhatsappChat,
} from '../services/whatsappChatService'; } from '../services/whatsappChatService';
const MAX_ATTACHMENT_SIZE_BYTES = 15 * 1024 * 1024; const MAX_ATTACHMENT_SIZE_BYTES = 100 * 1024 * 1024;
function getPresenceByUserId(presenceList, userId) { function getPresenceByUserId(presenceList, userId) {
return presenceList.find((presence) => Number(presence.user_id) === Number(userId)) || null; return presenceList.find((presence) => Number(presence.user_id) === Number(userId)) || null;
@ -165,17 +166,6 @@ function dedupeMessages(messages) {
return messages.reduce((acc, message) => mergeMessageList(acc, message), []); return messages.reduce((acc, message) => mergeMessageList(acc, message), []);
} }
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
const result = String(reader.result || '');
resolve(result.includes(',') ? result.split(',')[1] : result);
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
function normalizeComparableContact(contact) { function normalizeComparableContact(contact) {
return { return {
@ -581,23 +571,23 @@ export function useChat() {
})); }));
} }
async function attachFile(file) { function attachFile(file) {
if (!file) return; if (!file) return;
if (file.size > MAX_ATTACHMENT_SIZE_BYTES) { if (file.size > MAX_ATTACHMENT_SIZE_BYTES) {
setApiError('Arquivo muito grande. Envie uma mídia de até 15 MB.'); setApiError('Arquivo muito grande. O limite máximo é 100 MB.');
return; return;
} }
const data = await fileToBase64(file);
setAttachedFile({ setAttachedFile({
name: file.name, name: file.name,
type: file.type || 'application/octet-stream', type: file.type || 'application/octet-stream',
data, previewUrl: URL.createObjectURL(file),
rawFile: file,
}); });
setApiError(null); setApiError(null);
} }
function removeAttachedFile() { function removeAttachedFile() {
if (attachedFile?.previewUrl) URL.revokeObjectURL(attachedFile.previewUrl);
setAttachedFile(null); setAttachedFile(null);
} }
@ -763,28 +753,23 @@ export function useChat() {
return; return;
} }
const media = attachedFile const fileToSend = attachedFile || null;
? {
data: attachedFile.data,
mimetype: attachedFile.type,
filename: attachedFile.name,
}
: null;
const newMessage = { const newMessage = {
id: `temp-${Date.now()}`, id: `temp-${Date.now()}`,
chatId: contactId, chatId: contactId,
sender: 'agent', sender: 'agent',
text: trimmed, text: trimmed,
timestamp: Math.floor(Date.now() / 1000), timestamp: Math.floor(Date.now() / 1000),
hasMedia: Boolean(media), hasMedia: Boolean(fileToSend),
media, mediaUrl: fileToSend?.previewUrl || null,
mediaMimeType: fileToSend?.type || null,
}; };
setMessagesByContact((current) => ({ setMessagesByContact((current) => ({
...current, ...current,
[contactId]: mergeMessageList(current[contactId] || [], newMessage), [contactId]: mergeMessageList(current[contactId] || [], newMessage),
})); }));
updateContactPreview(contactId, trimmed || '[Mídia]', media); updateContactPreview(contactId, trimmed || '[Mídia]', fileToSend ? { filename: fileToSend.name } : null);
if (contactId === activeContactId) { if (contactId === activeContactId) {
setDraft(''); setDraft('');
} }
@ -793,12 +778,20 @@ export function useChat() {
if (!contactId) return; if (!contactId) return;
try { try {
if (fileToSend) {
const form = new FormData();
form.append('file', fileToSend.rawFile, fileToSend.name);
form.append('to', contactId);
form.append('senderName', getUserDisplayName(currentUser));
if (trimmed) form.append('caption', trimmed);
await sendWhatsappMedia(form);
} else {
await sendWhatsappMessage({ await sendWhatsappMessage({
to: contactId, to: contactId,
message: trimmed, message: trimmed,
senderName: getUserDisplayName(currentUser), senderName: getUserDisplayName(currentUser),
media,
}); });
}
setApiError(null); setApiError(null);
updateContact(contactId, (contact) => ({ updateContact(contactId, (contact) => ({
@ -810,7 +803,7 @@ export function useChat() {
} catch (error) { } catch (error) {
setApiError( setApiError(
error.status === 413 error.status === 413
? 'Arquivo muito grande para envio. Tente uma midia menor.' ? 'Arquivo muito grande para envio. Tente uma mídia menor.'
: error.message, : error.message,
); );
} }

View File

@ -56,3 +56,11 @@ export function transferWhatsappChat(payload) {
fallbackMessage: 'Nao foi possivel transferir o atendimento.', fallbackMessage: 'Nao foi possivel transferir o atendimento.',
}); });
} }
export function sendWhatsappMedia(formData) {
return apiRequest('/whatsapp/send-media', {
method: 'POST',
body: formData,
fallbackMessage: 'Não foi possível enviar a mídia.',
});
}