Feat: Validacion de tamaño de archivos y notificaciones de error
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m9s

- Agregar validacion de tamaño en frontend antes de enviar
- Mostrar toast con error cuando archivo excede limite
- Mostrar toast con mensaje de error del servidor cuando falla envio
- Limites: imagen 16MB, video 64MB, audio 16MB, documento 100MB
This commit is contained in:
2025-12-04 10:14:35 -06:00
parent f4cf23f1ee
commit 9667738604
2 changed files with 64 additions and 3 deletions

View File

@@ -184,6 +184,16 @@ const caption = ref('')
const isDragging = ref(false)
const stickerModes = ref<boolean[]>([])
// File size limits (in bytes) - should match server
const MAX_SIZES: Record<string, number> = {
image: 16 * 1024 * 1024, // 16 MB
video: 64 * 1024 * 1024, // 64 MB
audio: 16 * 1024 * 1024, // 16 MB
document: 100 * 1024 * 1024, // 100 MB
}
const toast = useToast()
// Audio recorder
const {
isRecording,
@@ -242,12 +252,48 @@ const handleFileSelect = (event: Event, type: string) => {
}
}
const getFileMediaType = (file: File): string => {
if (file.type.startsWith('image/')) return 'image'
if (file.type.startsWith('video/')) return 'video'
if (file.type.startsWith('audio/')) return 'audio'
return 'document'
}
const formatFileSize = (bytes: number): string => {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`
}
const addFiles = (files: File[]) => {
// Limit to 10 files
const remaining = 10 - selectedFiles.value.length
const toAdd = files.slice(0, remaining)
// Use spread operator to trigger reactivity
selectedFiles.value = [...selectedFiles.value, ...toAdd]
// Validate file sizes
const validFiles: File[] = []
for (const file of toAdd) {
const mediaType = getFileMediaType(file)
const maxSize = MAX_SIZES[mediaType]
if (file.size > maxSize) {
toast.add({
title: 'Archivo muy grande',
description: `${file.name} (${formatFileSize(file.size)}) excede el límite de ${formatFileSize(maxSize)} para ${mediaType}`,
color: 'error',
duration: 5000
})
} else {
validFiles.push(file)
}
}
if (validFiles.length > 0) {
// Use spread operator to trigger reactivity
selectedFiles.value = [...selectedFiles.value, ...validFiles]
}
}
const handleDrop = (event: DragEvent) => {

View File

@@ -548,8 +548,23 @@ const handleSendMessage = async (content: string, files: File[], caption: string
// Reload messages
messages.value = await $fetch(`/api/messages/${instanceId}/${chatId}`)
} catch (e) {
} catch (e: any) {
console.error('Error sending message:', e)
// Extract error message from response
let errorMessage = 'Error al enviar el mensaje'
if (e?.data?.message) {
errorMessage = e.data.message
} else if (e?.message) {
errorMessage = e.message
}
toast.add({
title: 'Error de envío',
description: errorMessage,
color: 'error',
duration: 5000
})
}
}