mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-27 22:41:51 +01:00
add bookmarks in new store
This commit is contained in:
parent
aff39d1999
commit
18ec79af07
@ -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"
|
||||||
/>
|
/>
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
45
src/stores/bookmarks/index.ts
Normal file
45
src/stores/bookmarks/index.ts
Normal 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",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user