All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m43s
171 lines
4.7 KiB
Vue
171 lines
4.7 KiB
Vue
<template>
|
|
<div class="relative">
|
|
<div
|
|
class="flex items-center gap-3 p-3 cursor-pointer transition-colors hover:bg-[var(--wa-bg-light)]"
|
|
:class="{ 'bg-[var(--wa-bg-light)]': active }"
|
|
@click="$emit('click')"
|
|
>
|
|
<UAvatar
|
|
:alt="chat.name"
|
|
size="md"
|
|
:src="chat.profilePicture"
|
|
/>
|
|
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center justify-between">
|
|
<p class="font-medium text-[var(--wa-text)] truncate">{{ chat.name }}</p>
|
|
<div class="flex items-center gap-1">
|
|
<span class="text-xs text-[var(--wa-text-muted)]">{{ formatTime(chat.lastMessageAt) }}</span>
|
|
<!-- Debug button -->
|
|
<button
|
|
@click.stop="showDebug = !showDebug"
|
|
class="text-xs text-[var(--wa-text-muted)] hover:text-[var(--wa-blue)] opacity-50 hover:opacity-100"
|
|
title="Debug info"
|
|
>
|
|
<UIcon name="i-lucide-bug" class="w-3 h-3" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center gap-1 text-sm text-[var(--wa-text-muted)] truncate">
|
|
<UIcon v-if="messageTypeIcon" :name="messageTypeIcon" class="w-4 h-4 flex-shrink-0" />
|
|
<span class="truncate">{{ lastMessagePreview }}</span>
|
|
</div>
|
|
<span
|
|
v-if="chat.unreadCount > 0"
|
|
class="bg-[var(--wa-green-light)] text-white text-xs rounded-full px-2 py-0.5 flex-shrink-0"
|
|
>
|
|
{{ chat.unreadCount }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Debug panel -->
|
|
<div
|
|
v-if="showDebug"
|
|
class="mx-2 mb-2 p-2 rounded bg-gray-900 border border-gray-700 text-xs font-mono overflow-x-auto"
|
|
>
|
|
<div class="flex items-center justify-between mb-1">
|
|
<span class="text-gray-400">Chat:</span>
|
|
<button
|
|
@click.stop="copyToClipboard(JSON.stringify(chat, null, 2))"
|
|
class="px-2 py-1 rounded bg-gray-700 hover:bg-gray-600 text-gray-300"
|
|
title="Copiar al portapapeles"
|
|
>
|
|
<UIcon name="i-lucide-copy" class="w-3 h-3" />
|
|
</button>
|
|
</div>
|
|
<pre class="text-green-400 whitespace-pre-wrap">{{ JSON.stringify(chat, null, 2) }}</pre>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
interface Chat {
|
|
id: string
|
|
name: string
|
|
jid: string
|
|
profilePicture?: string
|
|
lastMessage: string
|
|
lastMessageAt: Date
|
|
lastMessageType?: string
|
|
unreadCount: number
|
|
isGroup?: boolean
|
|
}
|
|
|
|
interface Props {
|
|
chat: Chat
|
|
active?: boolean
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
defineEmits<{
|
|
click: []
|
|
}>()
|
|
|
|
const showDebug = ref(false)
|
|
|
|
// Message type to icon mapping
|
|
const messageTypeIcons: Record<string, string> = {
|
|
image: 'i-lucide-image',
|
|
video: 'i-lucide-video',
|
|
audio: 'i-lucide-music',
|
|
document: 'i-lucide-file',
|
|
sticker: 'i-lucide-sticker',
|
|
contact: 'i-lucide-contact',
|
|
location: 'i-lucide-map-pin'
|
|
}
|
|
|
|
// Message type to placeholder text
|
|
const messageTypePlaceholders: Record<string, string> = {
|
|
image: 'Foto',
|
|
video: 'Video',
|
|
audio: 'Audio',
|
|
document: 'Documento',
|
|
sticker: 'Sticker',
|
|
contact: 'Contacto',
|
|
location: 'Ubicación'
|
|
}
|
|
|
|
const messageTypeIcon = computed(() => {
|
|
const type = props.chat.lastMessageType
|
|
if (!type || type === 'text') return null
|
|
return messageTypeIcons[type] || null
|
|
})
|
|
|
|
const lastMessagePreview = computed(() => {
|
|
const type = props.chat.lastMessageType
|
|
|
|
// If there's text content, show it
|
|
if (props.chat.lastMessage) {
|
|
return props.chat.lastMessage
|
|
}
|
|
|
|
// Otherwise show placeholder based on type
|
|
if (type && messageTypePlaceholders[type]) {
|
|
return messageTypePlaceholders[type]
|
|
}
|
|
|
|
return ''
|
|
})
|
|
|
|
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
|
|
})
|
|
}
|
|
}
|
|
|
|
const formatTime = (date: Date) => {
|
|
const d = new Date(date)
|
|
const now = new Date()
|
|
const diff = now.getTime() - d.getTime()
|
|
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
|
|
|
if (days === 0) {
|
|
return d.toLocaleTimeString('es-AR', { hour: '2-digit', minute: '2-digit' })
|
|
} else if (days === 1) {
|
|
return 'Ayer'
|
|
} else if (days < 7) {
|
|
return d.toLocaleDateString('es-AR', { weekday: 'short' })
|
|
} else {
|
|
return d.toLocaleDateString('es-AR', { day: '2-digit', month: '2-digit' })
|
|
}
|
|
}
|
|
</script>
|