add bookmarks in new store

This commit is contained in:
mrjvs 2023-10-17 16:14:46 +02:00
parent aff39d1999
commit 18ec79af07
4 changed files with 95 additions and 32 deletions

View File

@ -1,12 +1,28 @@
import { useCallback } from "react";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { useBookmarkStore } from "@/stores/bookmarks";
import { usePlayerStore } from "@/stores/player/store";
import { VideoPlayerButton } from "./Button"; import { VideoPlayerButton } from "./Button";
export function BookmarkButton() { 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 ( return (
<VideoPlayerButton <VideoPlayerButton
onClick={() => window.open("https://youtu.be/TENzstSjsus", "_blank")} onClick={() => toggleBookmark()}
icon={Icons.BOOKMARK_OUTLINE} icon={isBookmarked ? Icons.BOOKMARK : Icons.BOOKMARK_OUTLINE}
iconSizeClass="text-base" iconSizeClass="text-base"
className="p-3" className="p-3"
/> />

View File

@ -7,33 +7,29 @@ import { Icons } from "@/components/Icon";
import { SectionHeading } from "@/components/layout/SectionHeading"; import { SectionHeading } from "@/components/layout/SectionHeading";
import { MediaGrid } from "@/components/media/MediaGrid"; import { MediaGrid } from "@/components/media/MediaGrid";
import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; import { WatchedMediaCard } from "@/components/media/WatchedMediaCard";
import { useBookmarkContext } from "@/state/bookmark"; import { useBookmarkStore } from "@/stores/bookmarks";
import { useWatchedContext } from "@/state/watched"; import { MediaItem } from "@/utils/mediaTypes";
export function BookmarksPart() { export function BookmarksPart() {
const { t } = useTranslation(); const { t } = useTranslation();
const { getFilteredBookmarks, setItemBookmark } = useBookmarkContext(); const bookmarks = useBookmarkStore((s) => s.bookmarks);
const bookmarks = getFilteredBookmarks(); const removeBookmark = useBookmarkStore((s) => s.removeBookmark);
const [editing, setEditing] = useState(false); const [editing, setEditing] = useState(false);
const [gridRef] = useAutoAnimate<HTMLDivElement>(); const [gridRef] = useAutoAnimate<HTMLDivElement>();
const { watched } = useWatchedContext();
const bookmarksSorted = useMemo(() => { // TODO sort on last watched
return bookmarks const items = useMemo(() => {
.map((v) => { const output: MediaItem[] = [];
return { Object.entries(bookmarks).forEach((entry) => {
...v, output.push({
watched: watched.items id: entry[0],
.sort((a, b) => b.watchedAt - a.watchedAt) ...entry[1],
.find((watchedItem) => watchedItem.item.meta.id === v.id), });
}; });
}) return output;
.sort( }, [bookmarks]);
(a, b) => (b.watched?.watchedAt || 0) - (a.watched?.watchedAt || 0)
);
}, [watched.items, bookmarks]);
if (bookmarks.length === 0) return null; if (items.length === 0) return null;
return ( return (
<div> <div>
@ -44,14 +40,13 @@ export function BookmarksPart() {
<EditButton editing={editing} onEdit={setEditing} /> <EditButton editing={editing} onEdit={setEditing} />
</SectionHeading> </SectionHeading>
<MediaGrid ref={gridRef}> <MediaGrid ref={gridRef}>
{bookmarksSorted.map((v) => ( {items.map((v) => (
<div key={v.id}>Bookmark</div> <WatchedMediaCard
// <WatchedMediaCard key={v.id}
// key={v.id} media={v}
// media={v} closable={editing}
// closable={editing} onClose={() => removeBookmark(v.id)}
// onClose={() => setItemBookmark(v, false)} />
// />
))} ))}
</MediaGrid> </MediaGrid>
</div> </div>

View File

@ -7,27 +7,34 @@ import { Icons } from "@/components/Icon";
import { SectionHeading } from "@/components/layout/SectionHeading"; import { SectionHeading } from "@/components/layout/SectionHeading";
import { MediaGrid } from "@/components/media/MediaGrid"; import { MediaGrid } from "@/components/media/MediaGrid";
import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; import { WatchedMediaCard } from "@/components/media/WatchedMediaCard";
import { useBookmarkStore } from "@/stores/bookmarks";
import { useProgressStore } from "@/stores/progress"; import { useProgressStore } from "@/stores/progress";
import { MediaItem } from "@/utils/mediaTypes"; import { MediaItem } from "@/utils/mediaTypes";
export function WatchingPart() { export function WatchingPart() {
const { t } = useTranslation(); const { t } = useTranslation();
const bookmarks = useBookmarkStore((s) => s.bookmarks);
const progressItems = useProgressStore((s) => s.items); const progressItems = useProgressStore((s) => s.items);
const removeItem = useProgressStore((s) => s.removeItem); const removeItem = useProgressStore((s) => s.removeItem);
const [editing, setEditing] = useState(false); const [editing, setEditing] = useState(false);
const [gridRef] = useAutoAnimate<HTMLDivElement>(); const [gridRef] = useAutoAnimate<HTMLDivElement>();
const sortedProgressItems = useMemo(() => { const sortedProgressItems = useMemo(() => {
const output: MediaItem[] = []; let output: MediaItem[] = [];
Object.entries(progressItems).forEach((entry) => { Object.entries(progressItems).forEach((entry) => {
output.push({ output.push({
id: entry[0], id: entry[0],
...entry[1], ...entry[1],
}); });
}); });
output = output.filter((v) => {
const isBookMarked = !!bookmarks[v.id];
return !isBookMarked;
});
// TODO sort on last modified date // TODO sort on last modified date
return output; return output;
}, [progressItems]); }, [progressItems, bookmarks]);
if (sortedProgressItems.length === 0) return null; if (sortedProgressItems.length === 0) return null;

View File

@ -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<string, BookmarkMediaItem>;
addBookmark(meta: PlayerMeta): void;
removeBookmark(id: string): void;
}
// TODO add migration from previous bookmark store
export const useBookmarkStore = create(
persist(
immer<ProgressStore>((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",
}
)
);