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 { 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 (
<VideoPlayerButton
onClick={() => 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"
/>

View File

@ -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<HTMLDivElement>();
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 (
<div>
@ -44,14 +40,13 @@ export function BookmarksPart() {
<EditButton editing={editing} onEdit={setEditing} />
</SectionHeading>
<MediaGrid ref={gridRef}>
{bookmarksSorted.map((v) => (
<div key={v.id}>Bookmark</div>
// <WatchedMediaCard
// key={v.id}
// media={v}
// closable={editing}
// onClose={() => setItemBookmark(v, false)}
// />
{items.map((v) => (
<WatchedMediaCard
key={v.id}
media={v}
closable={editing}
onClose={() => removeBookmark(v.id)}
/>
))}
</MediaGrid>
</div>

View File

@ -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<HTMLDivElement>();
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;

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",
}
)
);