import { useCallback, useEffect, useState } from 'react'; import { MatrixClient } from 'matrix-js-sdk'; import { useMatrixClient } from './useMatrixClient'; import { useAccountDataCallback } from './useAccountDataCallback'; 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[]; }; function readBookmarks(mx: MatrixClient): Bookmark[] { return ( (mx.getAccountData(BOOKMARKS_KEY as any)?.getContent() as BookmarksContent | undefined) ?.bookmarks ?? [] ); } export function useBookmarks(): { bookmarks: Bookmark[]; addBookmark: (b: Bookmark) => Promise; removeBookmark: (eventId: string) => Promise; isBookmarked: (eventId: string) => boolean; } { const mx = useMatrixClient(); const [bookmarks, setBookmarks] = useState(() => readBookmarks(mx)); useAccountDataCallback( mx, useCallback( (evt) => { if (evt.getType() === BOOKMARKS_KEY) { setBookmarks(evt.getContent()?.bookmarks ?? []); } }, [setBookmarks], ), ); // Re-read on mx change useEffect(() => { setBookmarks(readBookmarks(mx)); }, [mx]); const addBookmark = useCallback( async (b: Bookmark) => { const current = readBookmarks(mx); // 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); } await (mx as any).setAccountData(BOOKMARKS_KEY, { bookmarks: next }); }, [mx], ); const removeBookmark = useCallback( async (eventId: string) => { const current = readBookmarks(mx); const next = current.filter((bk) => bk.eventId !== eventId); await (mx as any).setAccountData(BOOKMARKS_KEY, { bookmarks: next }); }, [mx], ); const isBookmarked = useCallback( (eventId: string) => bookmarks.some((bk) => bk.eventId === eventId), [bookmarks], ); return { bookmarks, addBookmark, removeBookmark, isBookmarked }; }