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

- 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:
2025-12-02 21:21:33 -06:00
parent 71593b25e9
commit 80d0042c7e
21 changed files with 3722 additions and 112 deletions

View File

@@ -161,17 +161,26 @@
</div>
<!-- Messages -->
<div class="flex-1 overflow-y-auto p-4 space-y-2">
<div ref="messagesContainer" class="flex-1 overflow-y-auto p-4 space-y-2">
<MessagesMessageBubble
v-for="message in messages"
v-for="message in reversedMessages"
:key="message.id"
:message="message"
:instance-id="selectedInstance?.value || ''"
:is-group="selectedChat?.isGroup || false"
@reply="handleReply"
@react="handleReact"
/>
</div>
<!-- Input -->
<div class="p-4 border-t border-[var(--wa-border)]">
<MessagesMessageInput @send="handleSendMessage" />
<MessagesMessageInput
:replying-to="replyingTo"
@send="handleSendMessage"
@send-voice="handleSendVoice"
@cancel-reply="replyingTo = null"
/>
</div>
</template>
</div>
@@ -257,6 +266,27 @@ const filteredChats = computed(() => {
)
})
// Reverse messages for display (API returns DESC, we want ASC for chronological order)
const reversedMessages = computed(() => {
return [...messages.value].reverse()
})
const messagesContainer = ref<HTMLElement | null>(null)
// Scroll to bottom when new messages arrive
const scrollToBottom = () => {
nextTick(() => {
if (messagesContainer.value) {
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
}
})
}
// Watch for message changes and scroll to bottom
watch(messages, () => {
scrollToBottom()
}, { deep: true })
// Copy to clipboard function
const copyToClipboard = async (text: string) => {
try {
@@ -266,22 +296,97 @@ const copyToClipboard = async (text: string) => {
}
}
const handleSendMessage = async (content: string) => {
// Reply state (will be used for quote functionality)
const replyingTo = ref<any>(null)
const handleSendMessage = async (content: string, files: File[], caption: string, quotedId?: string) => {
if (!selectedInstance.value?.value || !selectedChat.value) return
try {
await $fetch(`/api/messages/${selectedInstance.value.value}/${selectedChat.value.id}/send`, {
method: 'POST',
body: { content }
})
const instanceId = selectedInstance.value.value
const chatId = selectedChat.value.id
// If we have files, send as media
if (files.length > 0) {
const formData = new FormData()
// Add files
for (const file of files) {
formData.append('files', file)
}
// Add caption if provided
if (caption) {
formData.append('caption', caption)
}
// Add quoted message ID if replying
if (quotedId || replyingTo.value?.messageId) {
formData.append('quotedMessageId', quotedId || replyingTo.value.messageId)
}
await $fetch(`/api/messages/${instanceId}/${chatId}/send-media`, {
method: 'POST',
body: formData
})
} else if (content) {
// Send text message
await $fetch(`/api/messages/${instanceId}/${chatId}/send`, {
method: 'POST',
body: {
content,
quotedMessageId: quotedId || replyingTo.value?.messageId
}
})
}
// Clear reply state
replyingTo.value = null
// Reload messages
messages.value = await $fetch(`/api/messages/${selectedInstance.value.value}/${selectedChat.value.id}`)
messages.value = await $fetch(`/api/messages/${instanceId}/${chatId}`)
} catch (e) {
console.error('Error sending message:', e)
}
}
// Handle voice message
const handleSendVoice = async (audioFile: File) => {
if (!selectedInstance.value?.value || !selectedChat.value) return
try {
const instanceId = selectedInstance.value.value
const chatId = selectedChat.value.id
const formData = new FormData()
formData.append('files', audioFile)
formData.append('isPtt', 'true') // Mark as push-to-talk (voice note)
await $fetch(`/api/messages/${instanceId}/${chatId}/send-media`, {
method: 'POST',
body: formData
})
// Reload messages
messages.value = await $fetch(`/api/messages/${instanceId}/${chatId}`)
} catch (e) {
console.error('Error sending voice message:', e)
}
}
// Handle reply action
const handleReply = (message: any) => {
replyingTo.value = message
// TODO: Focus input and show reply preview
console.log('Reply to:', message)
}
// Handle react action
const handleReact = (message: any) => {
// TODO: Show emoji picker
console.log('React to:', message)
}
// Reload chats for current instance
const reloadChats = async () => {
if (!selectedInstance.value?.value) return