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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user