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:
150
app/components/messages/content/MessageVideo.vue
Normal file
150
app/components/messages/content/MessageVideo.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<div class="relative group">
|
||||
<!-- Video player -->
|
||||
<video
|
||||
v-if="!error"
|
||||
ref="videoRef"
|
||||
:src="videoUrl"
|
||||
:poster="posterUrl"
|
||||
class="rounded-lg max-w-full"
|
||||
:class="{ 'max-h-80': !fullscreen }"
|
||||
:controls="isPlaying"
|
||||
preload="metadata"
|
||||
@loadedmetadata="onLoadedMetadata"
|
||||
@play="isPlaying = true"
|
||||
@pause="isPlaying = false"
|
||||
@ended="isPlaying = false"
|
||||
@error="onError"
|
||||
/>
|
||||
|
||||
<!-- Placeholder con play button cuando no está reproduciendo -->
|
||||
<div
|
||||
v-if="!isPlaying && !error"
|
||||
class="absolute inset-0 flex items-center justify-center cursor-pointer bg-black/20 rounded-lg"
|
||||
@click="playVideo"
|
||||
>
|
||||
<!-- Play button -->
|
||||
<div class="w-14 h-14 rounded-full bg-black/50 flex items-center justify-center backdrop-blur-sm">
|
||||
<UIcon name="i-lucide-play" class="w-8 h-8 text-white ml-1" />
|
||||
</div>
|
||||
|
||||
<!-- Duration badge -->
|
||||
<div
|
||||
v-if="duration"
|
||||
class="absolute bottom-2 left-2 px-1.5 py-0.5 rounded bg-black/60 text-white text-xs"
|
||||
>
|
||||
{{ formattedDuration }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error state -->
|
||||
<div
|
||||
v-if="error"
|
||||
class="flex flex-col items-center justify-center p-8 bg-[var(--wa-bg-light)] rounded-lg"
|
||||
>
|
||||
<UIcon name="i-lucide-video-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 el video</p>
|
||||
<UButton
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
class="mt-2"
|
||||
@click="retryLoad"
|
||||
>
|
||||
Reintentar
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<!-- Loading overlay -->
|
||||
<div
|
||||
v-if="loading"
|
||||
class="absolute inset-0 flex items-center justify-center bg-[var(--wa-bg-light)] rounded-lg"
|
||||
>
|
||||
<UIcon name="i-lucide-loader-2" class="w-8 h-8 text-[var(--wa-text-muted)] animate-spin" />
|
||||
</div>
|
||||
|
||||
<!-- Fullscreen button -->
|
||||
<button
|
||||
v-if="!error && isPlaying"
|
||||
class="absolute top-2 right-2 p-1.5 rounded-full bg-black/50 text-white opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
@click="toggleFullscreen"
|
||||
>
|
||||
<UIcon :name="fullscreen ? 'i-lucide-minimize' : 'i-lucide-maximize'" class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { MediaInfo } from '~/types/message'
|
||||
import { formatDuration } from '~/types/message'
|
||||
|
||||
interface Props {
|
||||
media: MediaInfo
|
||||
instanceId: string
|
||||
messageId: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const videoRef = ref<HTMLVideoElement | null>(null)
|
||||
const isPlaying = ref(false)
|
||||
const loading = ref(true)
|
||||
const error = ref(false)
|
||||
const fullscreen = ref(false)
|
||||
const duration = ref(props.media.duration || 0)
|
||||
|
||||
const videoUrl = computed(() => {
|
||||
if (props.media.url) return props.media.url
|
||||
return `/api/media/${props.instanceId}/${props.messageId}`
|
||||
})
|
||||
|
||||
const posterUrl = computed(() => {
|
||||
if (props.media.thumbnail) {
|
||||
return `data:image/jpeg;base64,${props.media.thumbnail}`
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
|
||||
const formattedDuration = computed(() => formatDuration(duration.value))
|
||||
|
||||
const playVideo = () => {
|
||||
if (videoRef.value) {
|
||||
videoRef.value.play()
|
||||
}
|
||||
}
|
||||
|
||||
const onLoadedMetadata = () => {
|
||||
loading.value = false
|
||||
if (videoRef.value && !props.media.duration) {
|
||||
duration.value = videoRef.value.duration
|
||||
}
|
||||
}
|
||||
|
||||
const onError = () => {
|
||||
loading.value = false
|
||||
error.value = true
|
||||
}
|
||||
|
||||
const retryLoad = () => {
|
||||
error.value = false
|
||||
loading.value = true
|
||||
}
|
||||
|
||||
const toggleFullscreen = async () => {
|
||||
if (!videoRef.value) return
|
||||
|
||||
if (!fullscreen.value) {
|
||||
await videoRef.value.requestFullscreen()
|
||||
fullscreen.value = true
|
||||
} else {
|
||||
await document.exitFullscreen()
|
||||
fullscreen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Escuchar cambios de fullscreen
|
||||
onMounted(() => {
|
||||
document.addEventListener('fullscreenchange', () => {
|
||||
fullscreen.value = !!document.fullscreenElement
|
||||
})
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user