From cc87bde154fec2bf2d6d2e90d37687b0a5876315 Mon Sep 17 00:00:00 2001 From: josedario87 Date: Tue, 2 Dec 2025 21:31:59 -0600 Subject: [PATCH] UI: Agregar iconos a expandir/colapsar y notificacion al copiar --- .../debug/WebhookReceiverSection.vue | 20 +++- app/pages/messages/index.vue | 108 +++++++++++++++++- server/api/messages/[instanceId]/chats.get.ts | 8 +- 3 files changed, 130 insertions(+), 6 deletions(-) diff --git a/app/components/debug/WebhookReceiverSection.vue b/app/components/debug/WebhookReceiverSection.vue index 4ae6f4b..527d184 100644 --- a/app/components/debug/WebhookReceiverSection.vue +++ b/app/components/debug/WebhookReceiverSection.vue @@ -109,8 +109,12 @@
 {
   })
 }
 
+const toast = useToast()
+
 const copyToClipboard = async (text: string) => {
   try {
     await navigator.clipboard.writeText(text)
+    toast.add({
+      title: 'Copiado al portapapeles',
+      icon: 'i-lucide-check',
+      color: 'success',
+      timeout: 2000
+    })
   } catch (err) {
     console.error('Failed to copy:', err)
+    toast.add({
+      title: 'Error al copiar',
+      icon: 'i-lucide-x',
+      color: 'error',
+      timeout: 2000
+    })
   }
 }
 
diff --git a/app/pages/messages/index.vue b/app/pages/messages/index.vue
index 26e922c..44c13e3 100644
--- a/app/pages/messages/index.vue
+++ b/app/pages/messages/index.vue
@@ -164,7 +164,30 @@
           
-
+
+ +
+
+
+ +
+ ([]) const messages = ref([]) const loadingChats = ref(false) const loadingMessages = ref(false) +const loadingMore = ref(false) +const hasMoreMessages = ref(true) const showDebugPanel = ref(false) const showChatsDebug = ref(false) const showSelectedChatDebug = ref(false) @@ -264,8 +289,15 @@ watch(selectedChat, async (chat) => { } loadingMessages.value = true + hasMoreMessages.value = true // Reset for new chat try { - messages.value = await $fetch(`/api/messages/${selectedInstance.value.value}/${chat.id}`) + const result = await $fetch(`/api/messages/${selectedInstance.value.value}/${chat.id}?limit=50`) + messages.value = result as any[] + + // If we got less than 50, there are no more messages + if ((result as any[]).length < 50) { + hasMoreMessages.value = false + } // Subscribe to presence updates for this chat (if not a group) if (!chat.isGroup && chat.jid) { @@ -279,6 +311,55 @@ watch(selectedChat, async (chat) => { } }) +// Load more messages (infinite scroll) +const loadMoreMessages = async () => { + if (!selectedInstance.value?.value || !selectedChat.value || loadingMore.value || !hasMoreMessages.value) return + + const oldestMessage = messages.value[messages.value.length - 1] // Messages are in DESC order + if (!oldestMessage) return + + loadingMore.value = true + const previousScrollHeight = messagesContainer.value?.scrollHeight || 0 + + try { + const instanceId = selectedInstance.value.value + const chatId = selectedChat.value.id + const before = oldestMessage.timestamp + + const olderMessages = await $fetch(`/api/messages/${instanceId}/${chatId}?limit=50&before=${before}`) + + if ((olderMessages as any[]).length < 50) { + hasMoreMessages.value = false + } + + if ((olderMessages as any[]).length > 0) { + messages.value = [...messages.value, ...(olderMessages as any[])] + + // Maintain scroll position after loading + nextTick(() => { + if (messagesContainer.value) { + const newScrollHeight = messagesContainer.value.scrollHeight + messagesContainer.value.scrollTop = newScrollHeight - previousScrollHeight + } + }) + } + } catch (e) { + console.error('Error loading more messages:', e) + } finally { + loadingMore.value = false + } +} + +// Handle scroll for infinite scroll +const handleScroll = () => { + if (!messagesContainer.value) return + + // Load more when scrolled near the top (< 100px) + if (messagesContainer.value.scrollTop < 100 && hasMoreMessages.value && !loadingMore.value) { + loadMoreMessages() + } +} + // Computed presence text for current chat const currentChatPresence = computed(() => { if (!selectedChat.value?.jid) return null @@ -484,5 +565,28 @@ onMounted(() => { console.log('[Messages] Message sent:', data) // Already handled by the send function }) + + // Listen for reaction updates + on('message.reaction', (data) => { + console.log('[Messages] Reaction received:', data) + + // If it's for the current instance and chat, reload messages + if (data.instanceId === selectedInstance.value?.value && selectedChat.value) { + reloadMessages() + } + }) + + // Listen for message status updates + on('message.status', (data) => { + console.log('[Messages] Message status update:', data) + + // Update message status in local state + if (data.instanceId === selectedInstance.value?.value) { + const messageIndex = messages.value.findIndex(m => m.messageId === data.messageId) + if (messageIndex !== -1) { + messages.value[messageIndex].status = data.status + } + } + }) }) diff --git a/server/api/messages/[instanceId]/chats.get.ts b/server/api/messages/[instanceId]/chats.get.ts index 87d4b9a..c7eed2d 100644 --- a/server/api/messages/[instanceId]/chats.get.ts +++ b/server/api/messages/[instanceId]/chats.get.ts @@ -29,10 +29,11 @@ export default defineEventHandler(async (event) => { throw createError({ statusCode: 404, message: 'Instance not found' }) } - // Get chats with last message + // Get chats with last message and type const result = await query( `SELECT c.id, c.jid, c.name, c.is_group, c.unread_count, c.last_message_at, - (SELECT content FROM messages m WHERE m.chat_id = c.id ORDER BY timestamp DESC LIMIT 1) as last_message + c.last_message_type, + (SELECT COALESCE(content, caption) FROM messages m WHERE m.chat_id = c.id ORDER BY timestamp DESC LIMIT 1) as last_message FROM chats c WHERE c.instance_id = $1 ORDER BY c.last_message_at DESC NULLS LAST`, @@ -46,6 +47,7 @@ export default defineEventHandler(async (event) => { isGroup: row.is_group, unreadCount: row.unread_count, lastMessageAt: row.last_message_at, - lastMessage: row.last_message || '' + lastMessage: row.last_message || '', + lastMessageType: row.last_message_type || 'text' })) })