Feature: Agregar botón para crear webhook de debug automáticamente
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s
- 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
This commit is contained in:
174
app/components/messages/content/MessageImage.vue
Normal file
174
app/components/messages/content/MessageImage.vue
Normal file
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<div class="relative group">
|
||||
<!-- Image -->
|
||||
<img
|
||||
v-if="!error"
|
||||
:src="imageUrl"
|
||||
:alt="'Imagen'"
|
||||
class="rounded-lg max-w-full cursor-pointer"
|
||||
:class="[
|
||||
{ 'max-h-80': !expanded },
|
||||
{ 'animate-pulse bg-[var(--wa-bg-light)]': loading }
|
||||
]"
|
||||
@load="onLoad"
|
||||
@error="onError"
|
||||
@click="toggleExpand"
|
||||
/>
|
||||
|
||||
<!-- Error state -->
|
||||
<div
|
||||
v-if="error"
|
||||
class="flex flex-col items-center justify-center p-8 bg-[var(--wa-bg-light)] rounded-lg min-w-[200px]"
|
||||
>
|
||||
<UIcon name="i-lucide-image-off" class="w-12 h-12 text-[var(--wa-text-muted)] mb-2" />
|
||||
<p class="text-sm text-[var(--wa-text-muted)]">No se pudo cargar la imagen</p>
|
||||
<UButton
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
class="mt-2"
|
||||
@click="retryLoad"
|
||||
>
|
||||
Reintentar
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<!-- Loading placeholder with thumbnail -->
|
||||
<div
|
||||
v-if="loading && !error"
|
||||
class="relative"
|
||||
>
|
||||
<!-- Blur thumbnail as placeholder -->
|
||||
<img
|
||||
v-if="media.thumbnail"
|
||||
:src="`data:image/jpeg;base64,${media.thumbnail}`"
|
||||
class="rounded-lg max-w-full max-h-80 blur-sm"
|
||||
:style="{ width: `${media.width || 200}px`, height: `${media.height || 200}px`, objectFit: 'cover' }"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
class="rounded-lg bg-[var(--wa-bg-light)]"
|
||||
:style="{ width: `${media.width || 200}px`, height: `${media.height || 200}px` }"
|
||||
/>
|
||||
|
||||
<!-- Loading spinner overlay -->
|
||||
<div class="absolute inset-0 flex items-center justify-center">
|
||||
<UIcon name="i-lucide-loader-2" class="w-8 h-8 text-white animate-spin drop-shadow-lg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- View once indicator -->
|
||||
<div
|
||||
v-if="media.isViewOnce && !error"
|
||||
class="absolute top-2 left-2 px-2 py-1 rounded bg-black/50 text-white text-xs flex items-center gap-1"
|
||||
>
|
||||
<UIcon name="i-lucide-eye" class="w-3 h-3" />
|
||||
<span>Vista única</span>
|
||||
</div>
|
||||
|
||||
<!-- Expand/download buttons on hover -->
|
||||
<div
|
||||
v-if="!error && !loading"
|
||||
class="absolute top-2 right-2 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<button
|
||||
class="p-1.5 rounded-full bg-black/50 text-white hover:bg-black/70"
|
||||
@click.stop="downloadImage"
|
||||
title="Descargar"
|
||||
>
|
||||
<UIcon name="i-lucide-download" class="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
class="p-1.5 rounded-full bg-black/50 text-white hover:bg-black/70"
|
||||
@click.stop="openFullscreen"
|
||||
title="Ver en pantalla completa"
|
||||
>
|
||||
<UIcon name="i-lucide-maximize" class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fullscreen modal -->
|
||||
<UModal v-model="showFullscreen" :ui="{ width: 'max-w-[95vw]' }">
|
||||
<div class="relative bg-black flex items-center justify-center min-h-[50vh]">
|
||||
<img
|
||||
:src="imageUrl"
|
||||
:alt="'Imagen'"
|
||||
class="max-w-full max-h-[90vh] object-contain"
|
||||
/>
|
||||
<button
|
||||
class="absolute top-4 right-4 p-2 rounded-full bg-black/50 text-white hover:bg-black/70"
|
||||
@click="showFullscreen = false"
|
||||
>
|
||||
<UIcon name="i-lucide-x" class="w-6 h-6" />
|
||||
</button>
|
||||
<button
|
||||
class="absolute bottom-4 right-4 p-2 rounded-full bg-black/50 text-white hover:bg-black/70"
|
||||
@click="downloadImage"
|
||||
>
|
||||
<UIcon name="i-lucide-download" class="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { MediaInfo } from '~/types/message'
|
||||
|
||||
interface Props {
|
||||
media: MediaInfo
|
||||
instanceId: string
|
||||
messageId: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const loading = ref(true)
|
||||
const error = ref(false)
|
||||
const expanded = ref(false)
|
||||
const showFullscreen = ref(false)
|
||||
|
||||
const imageUrl = computed(() => {
|
||||
if (props.media.url) return props.media.url
|
||||
return `/api/media/${props.instanceId}/${props.messageId}`
|
||||
})
|
||||
|
||||
const onLoad = () => {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const onError = () => {
|
||||
loading.value = false
|
||||
error.value = true
|
||||
}
|
||||
|
||||
const retryLoad = () => {
|
||||
error.value = false
|
||||
loading.value = true
|
||||
}
|
||||
|
||||
const toggleExpand = () => {
|
||||
expanded.value = !expanded.value
|
||||
}
|
||||
|
||||
const openFullscreen = () => {
|
||||
showFullscreen.value = true
|
||||
}
|
||||
|
||||
const downloadImage = async () => {
|
||||
try {
|
||||
const response = await fetch(imageUrl.value)
|
||||
const blob = await response.blob()
|
||||
const url = URL.createObjectURL(blob)
|
||||
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `imagen-${props.messageId}.jpg`
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
} catch (e) {
|
||||
console.error('Error downloading image:', e)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user