From c80b2cbf10500c2015d9be28a6a74b971268374a Mon Sep 17 00:00:00 2001 From: Shibo Lyu Date: Wed, 4 Sep 2024 12:59:31 +0800 Subject: [PATCH] refactor: render messages in sections --- src/lib/chat.ts | 48 +++++++++++++++++-- src/lib/components/ServiceMessage.svelte | 2 +- src/lib/formatters.ts | 38 ++++++++++++--- .../chats/[server]/[chatId]/+page.svelte | 4 +- .../chats/[server]/[chatId]/ChatHeader.svelte | 2 +- .../[server]/[chatId]/ChatHistory.svelte | 37 ++++++++++++-- .../[server]/[chatId]/ChatMessage.svelte | 29 ++++++----- .../chats/[server]/[chatId]/ChatPage.svelte | 5 +- 8 files changed, 129 insertions(+), 36 deletions(-) diff --git a/src/lib/chat.ts b/src/lib/chat.ts index 9067806..4994e95 100644 --- a/src/lib/chat.ts +++ b/src/lib/chat.ts @@ -1,7 +1,16 @@ -import { readable, type Readable } from 'svelte/store'; +import { derived, readable, type Readable } from 'svelte/store'; import type { BlahChatServerConnection } from './blah/connection/chatServer'; import type { BlahRichText } from './richText'; -import { messageFromBlah, type Chat, type Message } from './types'; +import { messageFromBlah, type Chat, type Message, type User } from './types'; + +const MAX_MESSAGES_PER_SECTION = 10; +const SHOW_TIME_AFTER_SILENCE = 30 * 60 * 1000; + +export type MessageSection = { + sender?: User; + messages: Message[]; + date?: Date; +}; export function useChat( server: BlahChatServerConnection, @@ -9,6 +18,7 @@ export function useChat( ): { info: Readable; messages: Readable; + sectionedMessages: Readable; sendMessage: (brt: BlahRichText) => Promise; } { const info = readable( @@ -37,9 +47,41 @@ export function useChat( return unsubscribe; }); + const sectionedMessages = derived([messages], ([messages]) => { + const sections: MessageSection[] = []; + + let lastMessage: Message | undefined = messages[0]; + let currentSection: MessageSection = { + messages: [], + sender: lastMessage?.sender, + date: lastMessage?.date + }; + + for (const message of messages) { + const reachesMaxMessages = currentSection.messages.length >= MAX_MESSAGES_PER_SECTION; + const senderChanged = message.sender.id !== lastMessage.sender.id; + const silentForTooLong = + message.date.getTime() - lastMessage.date.getTime() > SHOW_TIME_AFTER_SILENCE; + if (reachesMaxMessages || senderChanged || silentForTooLong) { + if (currentSection.messages.length > 0) { + sections.push(currentSection); + } + currentSection = { messages: [], sender: message.sender }; + if (silentForTooLong) currentSection.date = message.date; + } + currentSection.messages.push(message); + lastMessage = message; + } + + sections.push(currentSection); + + console.log(sections); + return sections; + }); + const sendMessage = async (brt: BlahRichText) => { await server.sendMessage(chatId, brt); }; - return { info, messages, sendMessage }; + return { info, messages, sectionedMessages, sendMessage }; } diff --git a/src/lib/components/ServiceMessage.svelte b/src/lib/components/ServiceMessage.svelte index ee8c9b0..317cbca 100644 --- a/src/lib/components/ServiceMessage.svelte +++ b/src/lib/components/ServiceMessage.svelte @@ -7,7 +7,7 @@
diff --git a/src/lib/formatters.ts b/src/lib/formatters.ts index 7192080..6aa381a 100644 --- a/src/lib/formatters.ts +++ b/src/lib/formatters.ts @@ -7,19 +7,29 @@ export function formatUnreadCount(count: number) { return unreadCountFormatter.format(count); } -const sameDayFormatter = new Intl.DateTimeFormat('default', { - hour: '2-digit', - minute: '2-digit' -}); +const timeOptions: Intl.DateTimeFormatOptions = { hour: '2-digit', minute: '2-digit' }; + +const sameDayFormatter = new Intl.DateTimeFormat('default', timeOptions); const sameYearFormatter = new Intl.DateTimeFormat('default', { month: 'short', day: 'numeric' }); +const sameYearWithTimeFormatter = new Intl.DateTimeFormat('default', { + month: 'short', + day: 'numeric', + ...timeOptions +}); const otherYearFormatter = new Intl.DateTimeFormat('default', { year: 'numeric', month: 'short', day: 'numeric' }); +const otherYearWithTimeFormatter = new Intl.DateTimeFormat('default', { + year: 'numeric', + month: 'short', + day: 'numeric', + ...timeOptions +}); const fullDateTimeFormatter = new Intl.DateTimeFormat('default', { year: 'numeric', month: 'short', @@ -29,9 +39,7 @@ const fullDateTimeFormatter = new Intl.DateTimeFormat('default', { second: '2-digit' }); -export const formatMessageDate = (date: Date, full: boolean = false) => { - if (full) return fullDateTimeFormatter.format(date); - +export const formatMessageDate = (date: Date) => { const now = new Date(); if (date.getFullYear() === now.getFullYear()) { if (date.getMonth() === now.getMonth() && date.getDate() === now.getDate()) { @@ -43,3 +51,19 @@ export const formatMessageDate = (date: Date, full: boolean = false) => { return otherYearFormatter.format(date); } }; +export const formatFullMessageDate = (date: Date) => { + return fullDateTimeFormatter.format(date); +}; + +export const formatMessageSectionDate = (date: Date) => { + const now = new Date(); + if (date.getFullYear() === now.getFullYear()) { + if (date.getMonth() === now.getMonth() && date.getDate() === now.getDate()) { + return sameDayFormatter.format(date); + } else { + return sameYearWithTimeFormatter.format(date); + } + } else { + return otherYearWithTimeFormatter.format(date); + } +}; diff --git a/src/routes/(app)/chats/[server]/[chatId]/+page.svelte b/src/routes/(app)/chats/[server]/[chatId]/+page.svelte index 3a5396d..683c235 100644 --- a/src/routes/(app)/chats/[server]/[chatId]/+page.svelte +++ b/src/routes/(app)/chats/[server]/[chatId]/+page.svelte @@ -27,8 +27,8 @@
{#if server} - {@const { info, messages, sendMessage } = useChat(server, roomId)} - sendMessage(e.detail)} /> + {@const { info, sectionedMessages, sendMessage } = useChat(server, roomId)} + sendMessage(e.detail)} /> {:else} To view this chat, you need to connect to chat server diff --git a/src/routes/(app)/chats/[server]/[chatId]/ChatHeader.svelte b/src/routes/(app)/chats/[server]/[chatId]/ChatHeader.svelte index 98cd57b..cf1d3b0 100644 --- a/src/routes/(app)/chats/[server]/[chatId]/ChatHeader.svelte +++ b/src/routes/(app)/chats/[server]/[chatId]/ChatHeader.svelte @@ -31,7 +31,7 @@

{info.name}

- +