diff --git a/web/src/stores/conversation.ts b/web/src/stores/conversation.ts index eeaf73f..1192ce6 100644 --- a/web/src/stores/conversation.ts +++ b/web/src/stores/conversation.ts @@ -2,6 +2,13 @@ import { create } from "zustand"; import { api } from "../lib/api.ts"; import { type Reaction } from "./message.ts"; +function parseDate(iso: string): number { + if (!iso) return 0; + const normalized = iso.includes("T") ? iso : iso.replace(" ", "T"); + const t = new Date(normalized).getTime(); + return isNaN(t) ? 0 : t; +} + export interface ConversationMember { id: string; username: string; @@ -89,17 +96,26 @@ export const useConversationStore = create((set, get) => ({ `/conversations/${conversationId}/messages${params}`, ); const list = Array.isArray(messages) ? messages : []; - set((state) => ({ - messagesByConversation: { - ...state.messagesByConversation, - [conversationId]: list, - }, - hasMoreByConversation: { - ...state.hasMoreByConversation, - [conversationId]: list.length >= 50, - }, - isLoading: false, - })); + set((state) => { + const existing = state.messagesByConversation[conversationId] || []; + const map = new Map(); + existing.forEach((m) => map.set(m.id, m)); + list.forEach((m) => map.set(m.id, m)); + const merged = Array.from(map.values()).sort( + (a, b) => parseDate(a.created_at) - parseDate(b.created_at) + ); + return { + messagesByConversation: { + ...state.messagesByConversation, + [conversationId]: merged, + }, + hasMoreByConversation: { + ...state.hasMoreByConversation, + [conversationId]: list.length >= 50, + }, + isLoading: false, + }; + }); } catch (error) { set({ isLoading: false, error: error instanceof Error ? error.message : "Failed" }); } @@ -118,17 +134,24 @@ export const useConversationStore = create((set, get) => ({ `/conversations/${conversationId}/messages?before=${encodeURIComponent(oldestId)}`, ); const list = Array.isArray(older) ? older : []; - set((state) => ({ - messagesByConversation: { - ...state.messagesByConversation, - [conversationId]: [...list, ...existing], - }, - hasMoreByConversation: { - ...state.hasMoreByConversation, - [conversationId]: list.length >= 50, - }, - isLoadingOlder: false, - })); + set((state) => { + const map = new Map(); + [...list, ...existing].forEach((m) => map.set(m.id, m)); + const merged = Array.from(map.values()).sort( + (a, b) => parseDate(a.created_at) - parseDate(b.created_at) + ); + return { + messagesByConversation: { + ...state.messagesByConversation, + [conversationId]: merged, + }, + hasMoreByConversation: { + ...state.hasMoreByConversation, + [conversationId]: list.length >= 50, + }, + isLoadingOlder: false, + }; + }); } catch { set({ isLoadingOlder: false }); } @@ -156,7 +179,7 @@ export const useConversationStore = create((set, get) => ({ messagesByConversation: { ...state.messagesByConversation, [message.conversation_id]: [...existing, message] - .sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()), + .sort((a, b) => parseDate(a.created_at) - parseDate(b.created_at)), }, }; });