All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m1s
- Inicializar webhookDispatcher en plugin de servidor - Conectar pagina de webhooks con API - Agregar selector de instancias en formulario - Corregir bug en toast de handleSaved
202 lines
5.1 KiB
Vue
202 lines
5.1 KiB
Vue
<template>
|
|
<div class="space-y-6">
|
|
<!-- Header -->
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-[var(--wa-text)]">Webhooks</h1>
|
|
<p class="text-[var(--wa-text-muted)]">Configura notificaciones para eventos de WhatsApp</p>
|
|
</div>
|
|
<UButton
|
|
icon="i-lucide-plus"
|
|
@click="openCreateModal"
|
|
>
|
|
Nuevo Webhook
|
|
</UButton>
|
|
</div>
|
|
|
|
<!-- Loading -->
|
|
<div v-if="loading" class="instance-card p-12 text-center">
|
|
<UIcon name="i-lucide-loader-2" class="w-8 h-8 text-[var(--wa-text-muted)] mx-auto mb-4 animate-spin" />
|
|
<p class="text-[var(--wa-text-muted)]">Cargando webhooks...</p>
|
|
</div>
|
|
|
|
<!-- Empty state -->
|
|
<div v-else-if="webhooks.length === 0" class="instance-card p-12 text-center">
|
|
<UIcon name="i-lucide-webhook" class="w-16 h-16 text-[var(--wa-text-muted)] mx-auto mb-4" />
|
|
<h3 class="text-xl font-semibold text-[var(--wa-text)] mb-2">No hay webhooks configurados</h3>
|
|
<p class="text-[var(--wa-text-muted)] mb-6">Los webhooks te permiten recibir notificaciones en tiempo real cuando ocurren eventos en WhatsApp</p>
|
|
<UButton
|
|
icon="i-lucide-plus"
|
|
@click="openCreateModal"
|
|
>
|
|
Crear Webhook
|
|
</UButton>
|
|
</div>
|
|
|
|
<!-- Webhooks list -->
|
|
<div v-else class="space-y-4">
|
|
<WebhooksWebhookCard
|
|
v-for="webhook in webhooks"
|
|
:key="webhook.id"
|
|
:webhook="webhook"
|
|
@edit="handleEdit"
|
|
@delete="handleDelete"
|
|
@test="handleTest"
|
|
@toggle="handleToggle"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Create/Edit Webhook Modal -->
|
|
<WebhooksWebhookFormModal
|
|
v-model:open="showModal"
|
|
:webhook="editingWebhook"
|
|
:instances="instances"
|
|
@saved="handleSaved"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
definePageMeta({
|
|
layout: 'dashboard',
|
|
title: 'Webhooks',
|
|
icon: 'i-lucide-webhook'
|
|
})
|
|
|
|
const toast = useToast()
|
|
|
|
const showModal = ref(false)
|
|
const editingWebhook = ref<any>(null)
|
|
const loading = ref(true)
|
|
const webhooks = ref<any[]>([])
|
|
const instances = ref<any[]>([])
|
|
|
|
// Fetch webhooks
|
|
const fetchWebhooks = async () => {
|
|
try {
|
|
webhooks.value = await $fetch('/api/webhooks')
|
|
} catch (error) {
|
|
console.error('Error fetching webhooks:', error)
|
|
toast.add({
|
|
title: 'Error',
|
|
description: 'No se pudieron cargar los webhooks',
|
|
color: 'red'
|
|
})
|
|
}
|
|
}
|
|
|
|
// Fetch instances for the form
|
|
const fetchInstances = async () => {
|
|
try {
|
|
instances.value = await $fetch('/api/instances')
|
|
} catch (error) {
|
|
console.error('Error fetching instances:', error)
|
|
}
|
|
}
|
|
|
|
// Initial load
|
|
onMounted(async () => {
|
|
loading.value = true
|
|
await Promise.all([fetchWebhooks(), fetchInstances()])
|
|
loading.value = false
|
|
})
|
|
|
|
const openCreateModal = () => {
|
|
editingWebhook.value = null
|
|
showModal.value = true
|
|
}
|
|
|
|
const handleEdit = (webhook: any) => {
|
|
editingWebhook.value = webhook
|
|
showModal.value = true
|
|
}
|
|
|
|
const handleDelete = async (webhookId: string) => {
|
|
if (!confirm('¿Estás seguro de eliminar este webhook?')) return
|
|
|
|
try {
|
|
await $fetch(`/api/webhooks/${webhookId}`, { method: 'DELETE' })
|
|
webhooks.value = webhooks.value.filter(w => w.id !== webhookId)
|
|
toast.add({
|
|
title: 'Webhook eliminado',
|
|
color: 'green'
|
|
})
|
|
} catch (error) {
|
|
console.error('Error deleting webhook:', error)
|
|
toast.add({
|
|
title: 'Error',
|
|
description: 'No se pudo eliminar el webhook',
|
|
color: 'red'
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleTest = async (webhookId: string) => {
|
|
try {
|
|
const result = await $fetch<{ success: boolean; status?: number; error?: string }>(
|
|
`/api/webhooks/${webhookId}/test`,
|
|
{ method: 'POST' }
|
|
)
|
|
|
|
if (result.success) {
|
|
toast.add({
|
|
title: 'Test exitoso',
|
|
description: `El webhook respondio con status ${result.status}`,
|
|
color: 'green'
|
|
})
|
|
} else {
|
|
toast.add({
|
|
title: 'Test fallido',
|
|
description: result.error || 'El webhook no respondio correctamente',
|
|
color: 'red'
|
|
})
|
|
}
|
|
} catch (error) {
|
|
console.error('Error testing webhook:', error)
|
|
toast.add({
|
|
title: 'Error',
|
|
description: 'No se pudo probar el webhook',
|
|
color: 'red'
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleToggle = async (webhookId: string, active: boolean) => {
|
|
try {
|
|
await $fetch(`/api/webhooks/${webhookId}`, {
|
|
method: 'PUT',
|
|
body: { isActive: active }
|
|
})
|
|
|
|
// Update local state
|
|
const webhook = webhooks.value.find(w => w.id === webhookId)
|
|
if (webhook) {
|
|
webhook.isActive = active
|
|
}
|
|
|
|
toast.add({
|
|
title: active ? 'Webhook activado' : 'Webhook desactivado',
|
|
color: 'green'
|
|
})
|
|
} catch (error) {
|
|
console.error('Error toggling webhook:', error)
|
|
toast.add({
|
|
title: 'Error',
|
|
description: 'No se pudo cambiar el estado del webhook',
|
|
color: 'red'
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSaved = async () => {
|
|
const isEdit = !!editingWebhook.value
|
|
showModal.value = false
|
|
editingWebhook.value = null
|
|
await fetchWebhooks()
|
|
toast.add({
|
|
title: isEdit ? 'Webhook actualizado' : 'Webhook creado',
|
|
color: 'green'
|
|
})
|
|
}
|
|
</script>
|