UI: Agregar iconos a expandir/colapsar y notificacion al copiar
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s

This commit is contained in:
2025-12-02 21:31:59 -06:00
parent 8f44826e64
commit cc87bde154
3 changed files with 130 additions and 6 deletions

View File

@@ -109,8 +109,12 @@
<div class="relative">
<button
@click="toggleExpand(event.id)"
class="text-xs text-[var(--wa-text-muted)] hover:text-[var(--wa-text)] mb-1"
class="flex items-center gap-1 text-xs text-[var(--wa-text-muted)] hover:text-[var(--wa-text)] mb-1"
>
<UIcon
:name="expandedEvents.has(event.id) ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
class="w-3 h-3"
/>
{{ expandedEvents.has(event.id) ? 'Colapsar' : 'Expandir' }} datos
</button>
<pre
@@ -253,11 +257,25 @@ const formatTime = (dateStr: string) => {
})
}
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
})
}
}

View File

@@ -164,7 +164,30 @@
</div>
<!-- Messages -->
<div ref="messagesContainer" 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"
@scroll="handleScroll"
>
<!-- Load more indicator -->
<div
v-if="loadingMore"
class="flex justify-center py-2"
>
<UIcon name="i-lucide-loader-2" class="w-5 h-5 animate-spin text-[var(--wa-text-muted)]" />
</div>
<div
v-else-if="hasMoreMessages"
class="flex justify-center py-2"
>
<button
class="text-xs text-[var(--wa-text-muted)] hover:text-[var(--wa-text)]"
@click="loadMoreMessages"
>
Cargar mensajes anteriores
</button>
</div>
<MessagesMessageBubble
v-for="message in reversedMessages"
:key="message.id"
@@ -220,6 +243,8 @@ const chats = ref<any[]>([])
const messages = ref<any[]>([])
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
}
}
})
})
</script>

View File

@@ -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<ChatRow>(
`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'
}))
})