diff --git a/src/components/player/internals/BookmarkButton.tsx b/src/components/player/internals/BookmarkButton.tsx index 5a618b6a..abf3af1d 100644 --- a/src/components/player/internals/BookmarkButton.tsx +++ b/src/components/player/internals/BookmarkButton.tsx @@ -1,12 +1,28 @@ +import { useCallback } from "react"; + import { Icons } from "@/components/Icon"; +import { useBookmarkStore } from "@/stores/bookmarks"; +import { usePlayerStore } from "@/stores/player/store"; import { VideoPlayerButton } from "./Button"; export function BookmarkButton() { + const addBookmark = useBookmarkStore((s) => s.addBookmark); + const removeBookmark = useBookmarkStore((s) => s.removeBookmark); + const bookmarks = useBookmarkStore((s) => s.bookmarks); + const meta = usePlayerStore((s) => s.meta); + const isBookmarked = !!bookmarks[meta?.tmdbId ?? ""]; + + const toggleBookmark = useCallback(() => { + if (!meta) return; + if (isBookmarked) removeBookmark(meta.tmdbId); + else addBookmark(meta); + }, [isBookmarked, meta, addBookmark, removeBookmark]); + return ( window.open("https://youtu.be/TENzstSjsus", "_blank")} - icon={Icons.BOOKMARK_OUTLINE} + onClick={() => toggleBookmark()} + icon={isBookmarked ? Icons.BOOKMARK : Icons.BOOKMARK_OUTLINE} iconSizeClass="text-base" className="p-3" /> diff --git a/src/pages/parts/home/BookmarksPart.tsx b/src/pages/parts/home/BookmarksPart.tsx index a27150ff..1a7f5671 100644 --- a/src/pages/parts/home/BookmarksPart.tsx +++ b/src/pages/parts/home/BookmarksPart.tsx @@ -7,33 +7,29 @@ import { Icons } from "@/components/Icon"; import { SectionHeading } from "@/components/layout/SectionHeading"; import { MediaGrid } from "@/components/media/MediaGrid"; import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; -import { useBookmarkContext } from "@/state/bookmark"; -import { useWatchedContext } from "@/state/watched"; +import { useBookmarkStore } from "@/stores/bookmarks"; +import { MediaItem } from "@/utils/mediaTypes"; export function BookmarksPart() { const { t } = useTranslation(); - const { getFilteredBookmarks, setItemBookmark } = useBookmarkContext(); - const bookmarks = getFilteredBookmarks(); + const bookmarks = useBookmarkStore((s) => s.bookmarks); + const removeBookmark = useBookmarkStore((s) => s.removeBookmark); const [editing, setEditing] = useState(false); const [gridRef] = useAutoAnimate(); - const { watched } = useWatchedContext(); - const bookmarksSorted = useMemo(() => { - return bookmarks - .map((v) => { - return { - ...v, - watched: watched.items - .sort((a, b) => b.watchedAt - a.watchedAt) - .find((watchedItem) => watchedItem.item.meta.id === v.id), - }; - }) - .sort( - (a, b) => (b.watched?.watchedAt || 0) - (a.watched?.watchedAt || 0) - ); - }, [watched.items, bookmarks]); + // TODO sort on last watched + const items = useMemo(() => { + const output: MediaItem[] = []; + Object.entries(bookmarks).forEach((entry) => { + output.push({ + id: entry[0], + ...entry[1], + }); + }); + return output; + }, [bookmarks]); - if (bookmarks.length === 0) return null; + if (items.length === 0) return null; return (
@@ -44,14 +40,13 @@ export function BookmarksPart() { - {bookmarksSorted.map((v) => ( -
Bookmark
- // setItemBookmark(v, false)} - // /> + {items.map((v) => ( + removeBookmark(v.id)} + /> ))}
diff --git a/src/pages/parts/home/WatchingPart.tsx b/src/pages/parts/home/WatchingPart.tsx index 9c86b39a..99ccf6a4 100644 --- a/src/pages/parts/home/WatchingPart.tsx +++ b/src/pages/parts/home/WatchingPart.tsx @@ -7,27 +7,34 @@ import { Icons } from "@/components/Icon"; import { SectionHeading } from "@/components/layout/SectionHeading"; import { MediaGrid } from "@/components/media/MediaGrid"; import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; +import { useBookmarkStore } from "@/stores/bookmarks"; import { useProgressStore } from "@/stores/progress"; import { MediaItem } from "@/utils/mediaTypes"; export function WatchingPart() { const { t } = useTranslation(); + const bookmarks = useBookmarkStore((s) => s.bookmarks); const progressItems = useProgressStore((s) => s.items); const removeItem = useProgressStore((s) => s.removeItem); const [editing, setEditing] = useState(false); const [gridRef] = useAutoAnimate(); const sortedProgressItems = useMemo(() => { - const output: MediaItem[] = []; + let output: MediaItem[] = []; Object.entries(progressItems).forEach((entry) => { output.push({ id: entry[0], ...entry[1], }); }); + + output = output.filter((v) => { + const isBookMarked = !!bookmarks[v.id]; + return !isBookMarked; + }); // TODO sort on last modified date return output; - }, [progressItems]); + }, [progressItems, bookmarks]); if (sortedProgressItems.length === 0) return null; diff --git a/src/stores/bookmarks/index.ts b/src/stores/bookmarks/index.ts new file mode 100644 index 00000000..bd3ac204 --- /dev/null +++ b/src/stores/bookmarks/index.ts @@ -0,0 +1,45 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; +import { immer } from "zustand/middleware/immer"; + +import { PlayerMeta } from "@/stores/player/slices/source"; + +export interface BookmarkMediaItem { + title: string; + year: number; + poster?: string; + type: "show" | "movie"; +} + +export interface ProgressStore { + bookmarks: Record; + addBookmark(meta: PlayerMeta): void; + removeBookmark(id: string): void; +} + +// TODO add migration from previous bookmark store +export const useBookmarkStore = create( + persist( + immer((set) => ({ + bookmarks: {}, + removeBookmark(id) { + set((s) => { + delete s.bookmarks[id]; + }); + }, + addBookmark(meta) { + set((s) => { + s.bookmarks[meta.tmdbId] = { + type: meta.type, + title: meta.title, + year: meta.releaseYear, + poster: meta.poster, + }; + }); + }, + })), + { + name: "__MW::bookmarks", + } + ) +);