107 lines
3.0 KiB
Vue

<script setup lang="ts">
import { messageHandler } from '@/composable/message'
import router from '@/router'
import { ref, onMounted, onBeforeUnmount, nextTick, watch, type Ref } from 'vue'
const msg = messageHandler()
const newMessage = ref('')
const msgTimer = ref()
const scrollContainer = ref<null | HTMLElement>(null)
watch(msg.messages, async () => {
// To automatically scroll down when new message arrives
await nextTick()
const el = scrollContainer.value
if (!el) return
el.scrollTop = el.scrollHeight
})
const onSentMessage = () => {
if (newMessage.value.trim() === '') {
return
}
msg
.sendMessage(newMessage.value)
.then(() => {
newMessage.value = ''
})
.catch((error) => {
console.error('Error sending message:', error)
})
}
const handleKeyPress = (event: KeyboardEvent) => {
if (event.key === 'Enter' && event.shiftKey === false) {
onSentMessage()
}
}
// Instantiate polling for messages
// ToDo: Try using a WebSocket instea
onMounted(() => {
document.addEventListener('keypress', handleKeyPress)
msg.requestMessages()
msgTimer.value = setInterval(() => {
msg.requestMessages(msg.lastMsg()?.timestamp)
}, 3000) // 3s
})
// Clean up polling
onBeforeUnmount(() => {
clearInterval(msgTimer.value)
document.removeEventListener('keypress', handleKeyPress)
msgTimer.value = null
})
</script>
<template>
<main>
<div class="grid grid-cols-1 grid-rows-10 boxed h-[75vh] max-w-128 min-w-100">
<h1 class="border-b-2">Chat</h1>
<div class="row-span-8 flex flex-col overflow-scroll" ref="scrollContainer">
<div v-if="msg" v-for="(message, id) in msg.messages.value" :key="message.id" class="mb-4">
<div
v-if="
!msg.previousMessage(id) ||
new Date(Number(message.timestamp) * 1000).toLocaleDateString() !==
new Date(Number(msg.previousMessage(id)?.timestamp) * 1000).toLocaleDateString()
"
class="text-center text-gray-500 my-2"
>
{{ new Date(Number(message.timestamp) * 1000).toLocaleDateString() }}
</div>
<p class="whitespace-pre-line">
<a class="italic mr-1">{{
new Date(Number(message.timestamp) * 1000).toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
hour12: false,
})
}}</a>
<a class="font-bold">{{ message.user }}</a
>: {{ message.content }}
</p>
</div>
</div>
<div class="flex flex-row mt-auto">
<textarea
v-model="newMessage"
placeholder="Type your message here..."
class="w-full h-12 min-h-12 p-2 border rounded"
/>
<button
@click="
() =>
msg.sendMessage(newMessage).then(() => {
newMessage = ''
})
"
class="!w-min"
>
Send
</button>
</div>
</div>
</main>
</template>