Update video's link on comboxbox change

This commit is contained in:
Zoe Roux 2026-03-09 17:31:06 +01:00
parent 3890e39e56
commit ef1486deaf
No known key found for this signature in database
7 changed files with 61 additions and 9 deletions

View File

@ -8,6 +8,7 @@ import { nextup } from "./controllers/profiles/nextup";
import { watchlistH } from "./controllers/profiles/watchlist";
import { seasonsH } from "./controllers/seasons";
import { seed } from "./controllers/seed";
import { videoLinkH } from "./controllers/seed/video-links";
import { videosWriteH } from "./controllers/seed/videos";
import { collections } from "./controllers/shows/collections";
import { movies } from "./controllers/shows/movies";
@ -140,5 +141,5 @@ export const handlers = new Elysia({ prefix })
},
permissions: ["core.write"],
},
(app) => app.use(videosWriteH).use(seed),
(app) => app.use(videosWriteH).use(videoLinkH).use(seed),
);

View File

@ -79,7 +79,7 @@ const videoSort = Sort(
],
},
{
default: ["entry"],
default: ["entry", "path"],
tablePk: videos.pk,
},
);

View File

@ -91,6 +91,7 @@ export const ComboBox = <Data,>({
{(multiple ? !values : !value)
? label
: (multiple ? values : [value!])
.sort((a, b) => getKey(a).localeCompare(getKey(b)))
.map(getSmallLabel ?? getLabel)
.join(", ")}
</P>

View File

@ -70,6 +70,7 @@ export const ComboBox = <Data,>({
{(multiple ? !values : !value)
? label
: (multiple ? values : [value!])
.sort((a, b) => getKey(a).localeCompare(getKey(b)))
.map(getSmallLabel ?? getLabel)
.join(", ")}
</P>

View File

@ -68,8 +68,8 @@ export const InfiniteFetch = <Data, Type extends string = string>({
: placeholderCount;
const placeholders = [...Array(count === 0 ? numColumns : count)].fill(0);
if (!items) return placeholders;
return isFetching ? [...items, ...placeholders] : items;
}, [items, isFetching, placeholderCount, numColumns]);
return isFetching && !isRefetching ? [...items, ...placeholders] : items;
}, [items, isFetching, isRefetching, placeholderCount, numColumns]);
if (!data.length && Empty) return Empty;

View File

@ -322,10 +322,12 @@ export const useMutation = <T = void, QueryRet = void>({
compute,
invalidate,
optimistic,
optimisticKey,
...queryParams
}: MutationParams & {
compute?: (param: T) => MutationParams;
optimistic?: (param: T, previous?: QueryRet) => QueryRet | undefined;
optimisticKey?: QueryIdentifier<unknown>;
invalidate: string[] | null;
}) => {
const { apiUrl, authToken } = useContext(AccountContext);
@ -348,7 +350,11 @@ export const useMutation = <T = void, QueryRet = void>({
...(invalidate && optimistic
? {
onMutate: async (params) => {
const queryKey = toQueryKey({ apiUrl, path: invalidate });
const queryKey = toQueryKey({
apiUrl,
path: optimisticKey?.path ?? invalidate,
params: optimisticKey?.params,
});
await queryClient.cancelQueries({
queryKey,
});
@ -361,7 +367,11 @@ export const useMutation = <T = void, QueryRet = void>({
},
onError: (_, __, context) => {
queryClient.setQueryData(
toQueryKey({ apiUrl, path: invalidate }),
toQueryKey({
apiUrl,
path: optimisticKey?.path ?? invalidate,
params: optimisticKey?.params,
}),
context!.previous,
);
},

View File

@ -1,9 +1,14 @@
import { useTranslation } from "react-i18next";
import { View } from "react-native";
import { entryDisplayNumber } from "~/components/entries";
import { Entry, FullVideo } from "~/models";
import { Entry, FullVideo, type Page } from "~/models";
import { ComboBox, Modal, P, Skeleton } from "~/primitives";
import { InfiniteFetch, type QueryIdentifier, useFetch } from "~/query";
import {
InfiniteFetch,
type QueryIdentifier,
useFetch,
useMutation,
} from "~/query";
import { useQueryState } from "~/utils";
import { Header } from "../details/header";
@ -12,6 +17,32 @@ export const VideosModal = () => {
const { data } = useFetch(Header.query("serie", slug));
const { t } = useTranslation();
const { mutateAsync } = useMutation({
method: "PUT",
path: ["api", "videos", "link"],
compute: ({
video,
entries,
}: {
video: string;
entries: Omit<Entry, "href" | "progress" | "videos">[];
}) => ({
body: [{ id: video, for: entries.map((x) => ({ slug: x.slug })) }],
}),
invalidate: ["api", "series", slug],
optimisticKey: VideosModal.query(slug),
optimistic: (params, prev?: { pages: Page<FullVideo>[] }) => ({
...prev!,
pages: prev!.pages.map((p) => ({
...p,
items: p!.items.map((x) => {
if (x.id !== params.video) return x;
return { ...x, entries: params.entries };
}) as FullVideo[],
})),
}),
});
return (
<Modal title={data?.name ?? t("misc.loading")} scroll={false}>
<InfiniteFetch
@ -36,7 +67,12 @@ export const VideosModal = () => {
getKey={(x) => x.id}
getLabel={(x) => `${entryDisplayNumber(x)} - ${x.name}`}
getSmallLabel={entryDisplayNumber}
onValueChange={(x) => {}}
onValueChange={async (entries) => {
await mutateAsync({
video: item.id,
entries,
});
}}
/>
</View>
)}
@ -49,5 +85,8 @@ export const VideosModal = () => {
VideosModal.query = (slug: string): QueryIdentifier<FullVideo> => ({
parser: FullVideo,
path: ["api", "series", slug, "videos"],
params: {
sort: "path",
},
infinite: true,
});