Webhooks: Completar integracion backend-frontend
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
This commit is contained in:
2025-12-02 20:33:48 -06:00
parent a750bd9163
commit 738584514d
3 changed files with 151 additions and 22 deletions

View File

@@ -93,9 +93,15 @@ interface Webhook {
instanceId?: string
}
interface Instance {
id: string
name: string
}
interface Props {
open: boolean
webhook?: Webhook | null
instances?: Instance[]
}
const props = defineProps<Props>()
@@ -129,8 +135,11 @@ const availableEvents = [
{ value: 'instance.qr', label: 'QR disponible' }
]
// TODO: Cargar instancias reales
const instanceOptions = ref<any[]>([])
// Instance options for selector
const instanceOptions = computed(() => [
{ label: 'Todas las instancias', value: null },
...(props.instances || []).map(i => ({ label: i.name, value: i.id }))
])
const isValid = computed(() => {
return form.value.name.trim() && form.value.url.trim() && form.value.events.length > 0

View File

@@ -8,27 +8,34 @@
</div>
<UButton
icon="i-lucide-plus"
@click="showCreateModal = true"
@click="openCreateModal"
>
Nuevo Webhook
</UButton>
</div>
<!-- Webhooks List -->
<div v-if="webhooks.length === 0" class="instance-card p-12 text-center">
<!-- 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="showCreateModal = true"
@click="openCreateModal"
>
Crear Webhook
</UButton>
</div>
<!-- Webhooks list -->
<div v-else class="space-y-4">
<WebhookCard
<WebhooksWebhookCard
v-for="webhook in webhooks"
:key="webhook.id"
:webhook="webhook"
@@ -39,10 +46,11 @@
/>
</div>
<!-- Create Webhook Modal -->
<WebhookFormModal
v-model:open="showCreateModal"
<!-- Create/Edit Webhook Modal -->
<WebhooksWebhookFormModal
v-model:open="showModal"
:webhook="editingWebhook"
:instances="instances"
@saved="handleSaved"
/>
</div>
@@ -55,32 +63,139 @@ definePageMeta({
icon: 'i-lucide-webhook'
})
const showCreateModal = ref(false)
const editingWebhook = ref<any>(null)
const toast = useToast()
// TODO: Conectar con API real
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
showCreateModal.value = true
showModal.value = true
}
const handleDelete = async (webhookId: string) => {
console.log('Deleting webhook', webhookId)
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) => {
console.log('Testing webhook', webhookId)
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) => {
console.log('Toggle webhook', webhookId, active)
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 = (webhook: any) => {
showCreateModal.value = false
const handleSaved = async () => {
const isEdit = !!editingWebhook.value
showModal.value = false
editingWebhook.value = null
// TODO: Refresh list
await fetchWebhooks()
toast.add({
title: isEdit ? 'Webhook actualizado' : 'Webhook creado',
color: 'green'
})
}
</script>

View File

@@ -1,7 +1,8 @@
/**
* Nitro plugin to initialize Baileys manager on server start
* Nitro plugin to initialize Baileys manager and Webhook dispatcher on server start
*/
import { baileysManager } from '../services/baileys/manager'
import { webhookDispatcher } from '../services/webhooks/dispatcher'
export default defineNitroPlugin(async () => {
console.log('[Plugin] Initializing Baileys Manager...')
@@ -12,7 +13,11 @@ export default defineNitroPlugin(async () => {
try {
await baileysManager.initialize()
console.log('[Plugin] Baileys Manager initialized successfully')
// Initialize webhook dispatcher after baileys manager
await webhookDispatcher.initialize()
console.log('[Plugin] Webhook Dispatcher initialized successfully')
} catch (error) {
console.error('[Plugin] Failed to initialize Baileys Manager:', error)
console.error('[Plugin] Failed to initialize:', error)
}
})