Files
whatsappNucleo/app/components/messages/content/MessageDocument.vue
josedario87 80d0042c7e
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s
Feature: Agregar botón para crear webhook de debug automáticamente
- Agregar botón "Crear Webhook de Debug" en WebhookReceiverSection
- Detectar si ya existe un webhook apuntando al receptor de debug
- Permitir eliminar el webhook de debug
- Incluir todos los eventos disponibles al crear el webhook
- También incluye mejoras previas de manejo de media y mensajes
2025-12-02 21:21:33 -06:00

214 lines
5.4 KiB
Vue

<template>
<div
class="flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-colors min-w-[200px] max-w-[280px]"
:class="fromMe ? 'bg-white/10 hover:bg-white/20' : 'bg-[var(--wa-bg-light)] hover:bg-[var(--wa-border)]'"
@click="downloadFile"
>
<!-- File icon -->
<div
class="w-10 h-10 rounded-lg flex items-center justify-center flex-shrink-0"
:class="iconBgClass"
>
<UIcon :name="fileIcon" class="w-5 h-5 text-white" />
</div>
<!-- File info -->
<div class="flex-1 min-w-0">
<p
class="text-sm font-medium truncate"
:class="fromMe ? 'text-white' : 'text-[var(--wa-text)]'"
>
{{ fileName }}
</p>
<p
class="text-xs mt-0.5"
:class="fromMe ? 'text-white/70' : 'text-[var(--wa-text-muted)]'"
>
{{ fileInfo }}
</p>
</div>
<!-- Download indicator -->
<div class="flex-shrink-0">
<UIcon
v-if="loading"
name="i-lucide-loader-2"
class="w-5 h-5 animate-spin"
:class="fromMe ? 'text-white/70' : 'text-[var(--wa-text-muted)]'"
/>
<UIcon
v-else
name="i-lucide-download"
class="w-5 h-5"
:class="fromMe ? 'text-white/70' : 'text-[var(--wa-text-muted)]'"
/>
</div>
</div>
</template>
<script setup lang="ts">
import type { MediaInfo } from '~/types/message'
import { formatFileSize } from '~/types/message'
interface Props {
media: MediaInfo
instanceId: string
messageId: string
fromMe?: boolean
}
const props = withDefaults(defineProps<Props>(), {
fromMe: false
})
const loading = ref(false)
const fileName = computed(() => {
return props.media.filename || 'Documento'
})
const fileInfo = computed(() => {
const parts: string[] = []
// Extensión
const ext = getFileExtension(props.media.filename || '', props.media.mimetype)
if (ext) parts.push(ext.toUpperCase())
// Tamaño
if (props.media.filesize) {
parts.push(formatFileSize(props.media.filesize))
}
return parts.join(' • ') || 'Documento'
})
const fileIcon = computed(() => {
const mimetype = props.media.mimetype || ''
const filename = props.media.filename || ''
// PDF
if (mimetype.includes('pdf') || filename.endsWith('.pdf')) {
return 'i-lucide-file-text'
}
// Hojas de cálculo
if (mimetype.includes('spreadsheet') || mimetype.includes('excel') ||
filename.match(/\.(xlsx?|csv|ods)$/i)) {
return 'i-lucide-file-spreadsheet'
}
// Documentos de texto
if (mimetype.includes('word') || mimetype.includes('document') ||
filename.match(/\.(docx?|odt|rtf)$/i)) {
return 'i-lucide-file-text'
}
// Presentaciones
if (mimetype.includes('presentation') || mimetype.includes('powerpoint') ||
filename.match(/\.(pptx?|odp)$/i)) {
return 'i-lucide-file-presentation'
}
// Código
if (mimetype.includes('javascript') || mimetype.includes('json') ||
mimetype.includes('html') || mimetype.includes('css') ||
filename.match(/\.(js|ts|json|html|css|py|java|c|cpp|go|rs)$/i)) {
return 'i-lucide-file-code'
}
// Comprimidos
if (mimetype.includes('zip') || mimetype.includes('rar') ||
mimetype.includes('tar') || mimetype.includes('gzip') ||
filename.match(/\.(zip|rar|7z|tar|gz)$/i)) {
return 'i-lucide-file-archive'
}
// APK
if (filename.endsWith('.apk')) {
return 'i-lucide-smartphone'
}
return 'i-lucide-file'
})
const iconBgClass = computed(() => {
const mimetype = props.media.mimetype || ''
const filename = props.media.filename || ''
// PDF - rojo
if (mimetype.includes('pdf') || filename.endsWith('.pdf')) {
return 'bg-red-500'
}
// Excel - verde
if (mimetype.includes('spreadsheet') || mimetype.includes('excel') ||
filename.match(/\.(xlsx?|csv)$/i)) {
return 'bg-green-600'
}
// Word - azul
if (mimetype.includes('word') || filename.match(/\.(docx?)$/i)) {
return 'bg-blue-600'
}
// PowerPoint - naranja
if (mimetype.includes('presentation') || filename.match(/\.(pptx?)$/i)) {
return 'bg-orange-500'
}
// Comprimidos - amarillo
if (mimetype.includes('zip') || mimetype.includes('rar') ||
filename.match(/\.(zip|rar|7z|tar|gz)$/i)) {
return 'bg-yellow-600'
}
// Código - morado
if (mimetype.includes('javascript') || mimetype.includes('json') ||
filename.match(/\.(js|ts|json|py|java)$/i)) {
return 'bg-purple-600'
}
return 'bg-gray-500'
})
function getFileExtension(filename: string, mimetype?: string): string {
// Intentar extraer de filename
const match = filename.match(/\.([a-zA-Z0-9]+)$/)
if (match) return match[1]
// Intentar extraer de mimetype
if (mimetype) {
const parts = mimetype.split('/')
if (parts.length > 1) {
const subtype = parts[1]
// Limpiar formatos como "vnd.openxmlformats-officedocument..."
if (subtype.includes('spreadsheet')) return 'xlsx'
if (subtype.includes('document')) return 'docx'
if (subtype.includes('presentation')) return 'pptx'
return subtype
}
}
return ''
}
const downloadFile = async () => {
loading.value = true
try {
const url = props.media.url || `/api/media/${props.instanceId}/${props.messageId}`
// Crear link de descarga
const a = document.createElement('a')
a.href = url
a.download = props.media.filename || 'documento'
a.target = '_blank'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
} finally {
loading.value = false
}
}
</script>