diff --git a/front/packages/models/src/utils.ts b/front/packages/models/src/utils.ts index 51678098..6b35fd2e 100644 --- a/front/packages/models/src/utils.ts +++ b/front/packages/models/src/utils.ts @@ -26,25 +26,6 @@ import type { Movie, Show } from "./resources"; export const zdate = z.coerce.date; -export const getDisplayDate = (data: Show | Movie) => { - const { - startAir, - endAir, - airDate, - }: { startAir?: Date | null; endAir?: Date | null; airDate?: Date | null } = data; - - if (startAir) { - if (!endAir || startAir.getFullYear() === endAir.getFullYear()) { - return startAir.getFullYear().toString(); - } - return startAir.getFullYear() + (endAir ? ` - ${endAir.getFullYear()}` : ""); - } - if (airDate) { - return airDate.getFullYear().toString(); - } - return null; -}; - export const useLocalSetting = (setting: string, def: string) => { if (Platform.OS === "web" && typeof window === "undefined") return [def, null!] as const; // eslint-disable-next-line react-hooks/rules-of-hooks diff --git a/front/packages/ui/src/components/context-menus.tsx b/front/packages/ui/src/components/context-menus.tsx deleted file mode 100644 index ea2904b6..00000000 --- a/front/packages/ui/src/components/context-menus.tsx +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Kyoo - A portable and vast media library solution. - * Copyright (c) Kyoo. - * - * See AUTHORS.md and LICENSE file in the project root for full license information. - * - * Kyoo is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * Kyoo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Kyoo. If not, see . - */ - -import { WatchStatusV, queryFn, useAccount } from "@kyoo/models"; -import { HR, IconButton, Menu, tooltip, usePopup } from "@kyoo/primitives"; -import Refresh from "@material-symbols/svg-400/rounded/autorenew.svg"; -import Download from "@material-symbols/svg-400/rounded/download.svg"; -import Info from "@material-symbols/svg-400/rounded/info.svg"; -import MoreVert from "@material-symbols/svg-400/rounded/more_vert.svg"; -import MovieInfo from "@material-symbols/svg-400/rounded/movie_info.svg"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { ComponentProps } from "react"; -import { useTranslation } from "react-i18next"; -import { Platform } from "react-native"; -import { useYoshiki } from "yoshiki/native"; -import { useDownloader } from "../downloads"; -import { MediaInfoPopup } from "./media-info"; -import { watchListIcon } from "./watchlist-info"; - -export const EpisodesContext = ({ - type = "episode", - slug, - showSlug, - status, - force, - ...props -}: { - type?: "show" | "movie" | "episode"; - showSlug?: string | null; - slug: string; - status: WatchStatusV | null; - force?: boolean; -} & Partial>>) => { - const account = useAccount(); - const downloader = useDownloader(); - const { css } = useYoshiki(); - const { t } = useTranslation(); - const [setPopup, close] = usePopup(); - - const queryClient = useQueryClient(); - const mutation = useMutation({ - mutationFn: (newStatus: WatchStatusV | null) => - queryFn({ - path: [type, slug, "watchStatus", newStatus && `?status=${newStatus}`], - method: newStatus ? "POST" : "DELETE", - }), - onSettled: async () => await queryClient.invalidateQueries({ queryKey: [type, slug] }), - }); - - const metadataRefreshMutation = useMutation({ - mutationFn: () => - queryFn({ - path: [type, slug, "refresh"], - method: "POST", - }), - }); - - return ( - <> - - {showSlug && ( - - )} - - {Object.values(WatchStatusV).map((x) => ( - }`)} - onSelect={() => mutation.mutate(x)} - selected={x === status} - /> - ))} - {status !== null && ( - mutation.mutate(null)} - /> - )} - - {type !== "show" && ( - <> - downloader(type, slug)} - /> - - setPopup() - } - /> - - )} - {account?.isAdmin === true && ( - <> -
- metadataRefreshMutation.mutate()} - /> - - )} -
- - ); -}; - -export const ItemContext = ({ - type, - slug, - status, - force, - ...props -}: { - type: "movie" | "show"; - slug: string; - status: WatchStatusV | null; - force?: boolean; -} & Partial>>) => { - return ( - - ); -}; diff --git a/front/packages/ui/src/components/watchlist-info.tsx b/front/src/components/watchlist-info.tsx similarity index 63% rename from front/packages/ui/src/components/watchlist-info.tsx rename to front/src/components/watchlist-info.tsx index fd3a64b2..c46d27f8 100644 --- a/front/packages/ui/src/components/watchlist-info.tsx +++ b/front/src/components/watchlist-info.tsx @@ -1,32 +1,13 @@ -/* - * Kyoo - A portable and vast media library solution. - * Copyright (c) Kyoo. - * - * See AUTHORS.md and LICENSE file in the project root for full license information. - * - * Kyoo is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * Kyoo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Kyoo. If not, see . - */ - -import { WatchStatusV, queryFn, useAccount } from "@kyoo/models"; -import { IconButton, Menu, tooltip } from "@kyoo/primitives"; import Bookmark from "@material-symbols/svg-400/rounded/bookmark-fill.svg"; import BookmarkAdd from "@material-symbols/svg-400/rounded/bookmark_add.svg"; import BookmarkAdded from "@material-symbols/svg-400/rounded/bookmark_added-fill.svg"; import BookmarkRemove from "@material-symbols/svg-400/rounded/bookmark_remove.svg"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; import type { ComponentProps } from "react"; import { useTranslation } from "react-i18next"; +import { WatchStatusV } from "~/models"; +import { IconButton, Menu, tooltip } from "~/primitives"; +import { useAccount } from "~/providers/account-context"; +import { useMutation } from "~/query"; export const watchListIcon = (status: WatchStatusV | null) => { switch (status) { @@ -55,14 +36,13 @@ export const WatchListInfo = ({ const account = useAccount(); const { t } = useTranslation(); - const queryClient = useQueryClient(); const mutation = useMutation({ - mutationFn: (newStatus: WatchStatusV | null) => - queryFn({ - path: [type, slug, "watchStatus", newStatus && `?status=${newStatus}`], - method: newStatus ? "POST" : "DELETE", - }), - onSettled: async () => await queryClient.invalidateQueries({ queryKey: [type, slug] }), + path: [type, slug, "watchStatus"], + compute: (newStatus: WatchStatusV | null) => ({ + method: newStatus ? "POST" : "DELETE", + params: newStatus ? { status: newStatus } : undefined, + }), + invalidate: [type, slug], }); if (mutation.isPending) status = mutation.variables; @@ -112,5 +92,11 @@ export const WatchListInfo = ({ mutation.mutate(null)} /> ); + default: + return exhaustiveCheck(status); } }; + +function exhaustiveCheck(v: never): never { + return v; +} diff --git a/front/src/ui/browse/index.tsx b/front/src/ui/browse/index.tsx index ab31056b..3add7ee1 100644 --- a/front/src/ui/browse/index.tsx +++ b/front/src/ui/browse/index.tsx @@ -1,17 +1,11 @@ import { type ComponentProps, useState } from "react"; -import { - type LibraryItem, - LibraryItemP, - type QueryIdentifier, - type QueryPage, - getDisplayDate, -} from "~/models"; +import { ItemGrid } from "~/components"; +import { type LibraryItem, LibraryItemP, getDisplayDate } from "~/models"; +import { InfiniteFetch, type QueryIdentifier, type QueryPage } from "~/query"; import { useQueryState } from "~/utils"; import { DefaultLayout } from "../../../packages/ui/src/layout"; -import { InfiniteFetch } from "../../query/fetch-infinite"; -import { ItemGrid } from "~/components"; -import { BrowseSettings } from "./header"; import { ItemList } from "../../components/item-list"; +import { BrowseSettings } from "./header"; import { Layout, type MediaType, diff --git a/front/src/utils.ts b/front/src/utils.ts index e3ce4a22..086a4d23 100644 --- a/front/src/utils.ts +++ b/front/src/utils.ts @@ -16,3 +16,23 @@ export const useQueryState = (key: string, initial: S) => { }; return [state, update] as const; }; + +export const getDisplayDate = (data: Show | Movie) => { + const { + startAir, + endAir, + airDate, + }: { startAir?: Date | null; endAir?: Date | null; airDate?: Date | null } = data; + + if (startAir) { + if (!endAir || startAir.getFullYear() === endAir.getFullYear()) { + return startAir.getFullYear().toString(); + } + return startAir.getFullYear() + (endAir ? ` - ${endAir.getFullYear()}` : ""); + } + if (airDate) { + return airDate.getFullYear().toString(); + } + return null; +}; + diff --git a/front/tsconfig.json b/front/tsconfig.json index a49aed56..8a1c6ae7 100644 --- a/front/tsconfig.json +++ b/front/tsconfig.json @@ -19,7 +19,6 @@ "types": [ "node", "react", - "vite/client" ], "lib": [ "dom",