import { useCallback } from 'react'; import { useMatrixClient } from './useMatrixClient'; import { createAccountDataListStore } from './createAccountDataListStore'; export type Bookmark = { roomId: string; eventId: string; savedAt: number; previewText: string; roomName: string; }; const BOOKMARKS_KEY = 'io.lotus.bookmarks'; const MAX_BOOKMARKS = 500; type BookmarksContent = { bookmarks: Bookmark[]; }; // Shared, concurrency-safe store. See createAccountDataListStore for why the // snapshot + write queue must be module-scoped (writes are serialized to avoid // lost updates, since setAccountData replaces the whole content with no merge). const bookmarksStore = createAccountDataListStore({ eventType: BOOKMARKS_KEY, read: (content) => content?.bookmarks ?? [], write: (bookmarks) => ({ bookmarks }), }); export function useBookmarks(): { bookmarks: Bookmark[]; addBookmark: (b: Bookmark) => Promise; removeBookmark: (eventId: string) => Promise; isBookmarked: (eventId: string) => boolean; } { const mx = useMatrixClient(); const bookmarks = bookmarksStore.useValue(mx); const addBookmark = useCallback( (b: Bookmark) => bookmarksStore.enqueueWrite(mx, (current) => { // Avoid duplicates const filtered = current.filter((bk) => bk.eventId !== b.eventId); let next = [b, ...filtered]; if (next.length > MAX_BOOKMARKS) { next = next.slice(0, MAX_BOOKMARKS); } return next; }), [mx], ); const removeBookmark = useCallback( (eventId: string) => bookmarksStore.enqueueWrite(mx, (current) => current.filter((bk) => bk.eventId !== eventId)), [mx], ); const isBookmarked = useCallback( (eventId: string) => bookmarks.some((bk) => bk.eventId === eventId), [bookmarks], ); return { bookmarks, addBookmark, removeBookmark, isBookmarked }; }