Webhooks: Completar integracion backend-frontend
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m1s
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:
@@ -93,9 +93,15 @@ interface Webhook {
|
|||||||
instanceId?: string
|
instanceId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Instance {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean
|
open: boolean
|
||||||
webhook?: Webhook | null
|
webhook?: Webhook | null
|
||||||
|
instances?: Instance[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
@@ -129,8 +135,11 @@ const availableEvents = [
|
|||||||
{ value: 'instance.qr', label: 'QR disponible' }
|
{ value: 'instance.qr', label: 'QR disponible' }
|
||||||
]
|
]
|
||||||
|
|
||||||
// TODO: Cargar instancias reales
|
// Instance options for selector
|
||||||
const instanceOptions = ref<any[]>([])
|
const instanceOptions = computed(() => [
|
||||||
|
{ label: 'Todas las instancias', value: null },
|
||||||
|
...(props.instances || []).map(i => ({ label: i.name, value: i.id }))
|
||||||
|
])
|
||||||
|
|
||||||
const isValid = computed(() => {
|
const isValid = computed(() => {
|
||||||
return form.value.name.trim() && form.value.url.trim() && form.value.events.length > 0
|
return form.value.name.trim() && form.value.url.trim() && form.value.events.length > 0
|
||||||
|
|||||||
@@ -8,27 +8,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<UButton
|
<UButton
|
||||||
icon="i-lucide-plus"
|
icon="i-lucide-plus"
|
||||||
@click="showCreateModal = true"
|
@click="openCreateModal"
|
||||||
>
|
>
|
||||||
Nuevo Webhook
|
Nuevo Webhook
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Webhooks List -->
|
<!-- Loading -->
|
||||||
<div v-if="webhooks.length === 0" class="instance-card p-12 text-center">
|
<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" />
|
<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>
|
<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>
|
<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
|
<UButton
|
||||||
icon="i-lucide-plus"
|
icon="i-lucide-plus"
|
||||||
@click="showCreateModal = true"
|
@click="openCreateModal"
|
||||||
>
|
>
|
||||||
Crear Webhook
|
Crear Webhook
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Webhooks list -->
|
||||||
<div v-else class="space-y-4">
|
<div v-else class="space-y-4">
|
||||||
<WebhookCard
|
<WebhooksWebhookCard
|
||||||
v-for="webhook in webhooks"
|
v-for="webhook in webhooks"
|
||||||
:key="webhook.id"
|
:key="webhook.id"
|
||||||
:webhook="webhook"
|
:webhook="webhook"
|
||||||
@@ -39,10 +46,11 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Create Webhook Modal -->
|
<!-- Create/Edit Webhook Modal -->
|
||||||
<WebhookFormModal
|
<WebhooksWebhookFormModal
|
||||||
v-model:open="showCreateModal"
|
v-model:open="showModal"
|
||||||
:webhook="editingWebhook"
|
:webhook="editingWebhook"
|
||||||
|
:instances="instances"
|
||||||
@saved="handleSaved"
|
@saved="handleSaved"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -55,32 +63,139 @@ definePageMeta({
|
|||||||
icon: 'i-lucide-webhook'
|
icon: 'i-lucide-webhook'
|
||||||
})
|
})
|
||||||
|
|
||||||
const showCreateModal = ref(false)
|
const toast = useToast()
|
||||||
const editingWebhook = ref<any>(null)
|
|
||||||
|
|
||||||
// TODO: Conectar con API real
|
const showModal = ref(false)
|
||||||
|
const editingWebhook = ref<any>(null)
|
||||||
|
const loading = ref(true)
|
||||||
const webhooks = ref<any[]>([])
|
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) => {
|
const handleEdit = (webhook: any) => {
|
||||||
editingWebhook.value = webhook
|
editingWebhook.value = webhook
|
||||||
showCreateModal.value = true
|
showModal.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async (webhookId: string) => {
|
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) => {
|
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) => {
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSaved = (webhook: any) => {
|
toast.add({
|
||||||
showCreateModal.value = false
|
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
|
editingWebhook.value = null
|
||||||
// TODO: Refresh list
|
await fetchWebhooks()
|
||||||
|
toast.add({
|
||||||
|
title: isEdit ? 'Webhook actualizado' : 'Webhook creado',
|
||||||
|
color: 'green'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -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 { baileysManager } from '../services/baileys/manager'
|
||||||
|
import { webhookDispatcher } from '../services/webhooks/dispatcher'
|
||||||
|
|
||||||
export default defineNitroPlugin(async () => {
|
export default defineNitroPlugin(async () => {
|
||||||
console.log('[Plugin] Initializing Baileys Manager...')
|
console.log('[Plugin] Initializing Baileys Manager...')
|
||||||
@@ -12,7 +13,11 @@ export default defineNitroPlugin(async () => {
|
|||||||
try {
|
try {
|
||||||
await baileysManager.initialize()
|
await baileysManager.initialize()
|
||||||
console.log('[Plugin] Baileys Manager initialized successfully')
|
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) {
|
} catch (error) {
|
||||||
console.error('[Plugin] Failed to initialize Baileys Manager:', error)
|
console.error('[Plugin] Failed to initialize:', error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user