mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Clean up fetch story by allowing hook fetch
This commit is contained in:
parent
034f048883
commit
e8b929d4ca
@ -104,7 +104,7 @@ export const EpisodeList = <Props,>({
|
||||
}: {
|
||||
slug: string;
|
||||
season: string | number;
|
||||
Header: ComponentType<Props & { children: JSX.Element; empty: boolean }>;
|
||||
Header: ComponentType<Props & { children: JSX.Element }>;
|
||||
headerProps: Props;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -21,10 +21,10 @@
|
||||
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
||||
import { useBreakpointMap, HR } from "@kyoo/primitives";
|
||||
import { FlashList } from "@shopify/flash-list";
|
||||
import { ComponentType, isValidElement, ReactElement, useRef } from "react";
|
||||
import { ComponentProps, ComponentType, isValidElement, ReactElement, useRef } from "react";
|
||||
import { EmptyView, ErrorView, Layout, WithLoading, addHeader } from "./fetch";
|
||||
|
||||
export const InfiniteFetch = <Data, Props, _>({
|
||||
export const InfiniteFetchList = <Data, Props, _>({
|
||||
query,
|
||||
placeholderCount = 15,
|
||||
incremental = false,
|
||||
@ -33,11 +33,11 @@ export const InfiniteFetch = <Data, Props, _>({
|
||||
empty,
|
||||
divider = false,
|
||||
Header,
|
||||
headerProps: hprops,
|
||||
headerProps,
|
||||
getItemType,
|
||||
...props
|
||||
}: {
|
||||
query: QueryIdentifier<_, Data>;
|
||||
query: ReturnType<typeof useInfiniteFetch<_, Data>>;
|
||||
placeholderCount?: number;
|
||||
layout: Layout;
|
||||
horizontal?: boolean;
|
||||
@ -48,27 +48,16 @@ export const InfiniteFetch = <Data, Props, _>({
|
||||
empty?: string | JSX.Element;
|
||||
incremental?: boolean;
|
||||
divider?: boolean | ComponentType;
|
||||
Header?: ComponentType<Props & { children: JSX.Element; empty: boolean }> | ReactElement;
|
||||
Header?: ComponentType<Props & { children: JSX.Element }> | ReactElement;
|
||||
headerProps?: Props;
|
||||
getItemType?: (item: Data, index: number) => string | number;
|
||||
}): JSX.Element | null => {
|
||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||
|
||||
const { numColumns, size } = useBreakpointMap(layout);
|
||||
const oldItems = useRef<Data[] | undefined>();
|
||||
let { items, error, fetchNextPage, hasNextPage, refetch, isRefetching } = useInfiniteFetch(
|
||||
query,
|
||||
{
|
||||
useErrorBoundary: false,
|
||||
},
|
||||
);
|
||||
let { items, error, fetchNextPage, hasNextPage, refetch, isRefetching } = query;
|
||||
if (incremental && items) oldItems.current = items;
|
||||
|
||||
if (error) return <ErrorView error={error} />;
|
||||
// @ts-ignore
|
||||
const headerProps: Props & { empty: boolean } = hprops
|
||||
? { ...hprops, empty: items?.length === 0 }
|
||||
: { empty: items?.length === 0 };
|
||||
if (empty && items && items.length === 0) {
|
||||
if (typeof empty !== "string") return addHeader(Header, empty, headerProps);
|
||||
return addHeader(Header, <EmptyView message={empty} />, headerProps);
|
||||
@ -101,3 +90,17 @@ export const InfiniteFetch = <Data, Props, _>({
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const InfiniteFetch = <Data, Props, _>({
|
||||
query,
|
||||
...props
|
||||
}: {
|
||||
query: QueryIdentifier<_, Data>;
|
||||
} & Omit<ComponentProps<typeof InfiniteFetchList<Data, Props, _>>, "query">) => {
|
||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||
|
||||
const ret = useInfiniteFetch(query, {
|
||||
useErrorBoundary: false,
|
||||
});
|
||||
return <InfiniteFetchList query={ret} {...props} />;
|
||||
};
|
||||
|
@ -21,6 +21,7 @@
|
||||
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
||||
import { HR } from "@kyoo/primitives";
|
||||
import {
|
||||
ComponentProps,
|
||||
ComponentType,
|
||||
Fragment,
|
||||
isValidElement,
|
||||
@ -131,7 +132,7 @@ const InfiniteScroll = <Props,>({
|
||||
);
|
||||
};
|
||||
|
||||
export const InfiniteFetch = <Data, _, HeaderProps>({
|
||||
export const InfiniteFetchList = <Data, _, HeaderProps>({
|
||||
query,
|
||||
incremental = false,
|
||||
placeholderCount = 15,
|
||||
@ -140,11 +141,11 @@ export const InfiniteFetch = <Data, _, HeaderProps>({
|
||||
empty,
|
||||
divider: Divider = false,
|
||||
Header,
|
||||
headerProps: hprops,
|
||||
headerProps,
|
||||
getItemType,
|
||||
...props
|
||||
}: {
|
||||
query: QueryIdentifier<_, Data>;
|
||||
query: ReturnType<typeof useInfiniteFetch<_, Data>>;
|
||||
incremental?: boolean;
|
||||
placeholderCount?: number;
|
||||
layout: Layout;
|
||||
@ -158,18 +159,10 @@ export const InfiniteFetch = <Data, _, HeaderProps>({
|
||||
headerProps: HeaderProps;
|
||||
getItemType?: (item: Data, index: number) => string | number;
|
||||
}): JSX.Element | null => {
|
||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||
|
||||
const oldItems = useRef<Data[] | undefined>();
|
||||
const { items, error, fetchNextPage, hasNextPage, isFetching } = useInfiniteFetch(query, {
|
||||
useErrorBoundary: false,
|
||||
});
|
||||
const { items, error, fetchNextPage, hasNextPage, isFetching } = query;
|
||||
if (incremental && items) oldItems.current = items;
|
||||
|
||||
// @ts-ignore
|
||||
const headerProps: HeaderProps & { empty: boolean } = hprops
|
||||
? { ...hprops, empty: items?.length === 0 }
|
||||
: { empty: items?.length === 0 };
|
||||
if (error) return addHeader(Header, <ErrorView error={error} />, headerProps);
|
||||
if (empty && items && items.length === 0) {
|
||||
if (typeof empty !== "string") return addHeader(Header, empty, headerProps);
|
||||
@ -201,3 +194,17 @@ export const InfiniteFetch = <Data, _, HeaderProps>({
|
||||
</InfiniteScroll>
|
||||
);
|
||||
};
|
||||
|
||||
export const InfiniteFetch = <Data, Props, _>({
|
||||
query,
|
||||
...props
|
||||
}: {
|
||||
query: QueryIdentifier<_, Data>;
|
||||
} & Omit<ComponentProps<typeof InfiniteFetchList<Data, Props, _>>, "query">) => {
|
||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||
|
||||
const ret = useInfiniteFetch(query, {
|
||||
useErrorBoundary: false,
|
||||
});
|
||||
return <InfiniteFetchList query={ret} {...props} />;
|
||||
};
|
||||
|
@ -25,6 +25,7 @@ import {
|
||||
LibraryItemP,
|
||||
QueryIdentifier,
|
||||
getDisplayDate,
|
||||
useInfiniteFetch,
|
||||
} from "@kyoo/models";
|
||||
import { H3, IconButton, ts } from "@kyoo/primitives";
|
||||
import { ReactElement, forwardRef, useRef } from "react";
|
||||
@ -33,74 +34,69 @@ import { px, useYoshiki } from "yoshiki/native";
|
||||
import { ItemGrid } from "../browse/grid";
|
||||
import ChevronLeft from "@material-symbols/svg-400/rounded/chevron_left-fill.svg";
|
||||
import ChevronRight from "@material-symbols/svg-400/rounded/chevron_right-fill.svg";
|
||||
import { InfiniteFetch } from "../fetch-infinite";
|
||||
import { InfiniteFetch, InfiniteFetchList } from "../fetch-infinite";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const Header = forwardRef<
|
||||
View,
|
||||
{ empty: boolean; displayEmpty: boolean; genre: Genre; children: ReactElement }
|
||||
>(function Header({ empty, displayEmpty, genre, children }, ref) {
|
||||
export const Header = ({ title }: { title: string }) => {
|
||||
const { css } = useYoshiki();
|
||||
|
||||
return (
|
||||
<View ref={ref}>
|
||||
{!(empty && !displayEmpty) && (
|
||||
<View
|
||||
{...css({
|
||||
marginTop: ItemGrid.layout.gap,
|
||||
marginX: ItemGrid.layout.gap,
|
||||
pX: ts(0.5),
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
})}
|
||||
>
|
||||
<H3>{genre}</H3>
|
||||
{/* <View {...css({ flexDirection: "row" })}> */}
|
||||
{/* <IconButton */}
|
||||
{/* icon={ChevronLeft} */}
|
||||
{/* // onPress={() => ref.current?.scrollTo({ x: 0, animated: true })} */}
|
||||
{/* /> */}
|
||||
{/* <IconButton */}
|
||||
{/* icon={ChevronRight} */}
|
||||
{/* // onPress={() => ref.current?.scrollTo({ x: 0, animated: true })} */}
|
||||
{/* /> */}
|
||||
{/* </View> */}
|
||||
</View>
|
||||
)}
|
||||
{children}
|
||||
<View
|
||||
{...css({
|
||||
marginTop: ItemGrid.layout.gap,
|
||||
marginX: ItemGrid.layout.gap,
|
||||
pX: ts(0.5),
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
})}
|
||||
>
|
||||
<H3>{title}</H3>
|
||||
{/* <View {...css({ flexDirection: "row" })}> */}
|
||||
{/* <IconButton */}
|
||||
{/* icon={ChevronLeft} */}
|
||||
{/* // onPress={() => ref.current?.scrollTo({ x: 0, animated: true })} */}
|
||||
{/* /> */}
|
||||
{/* <IconButton */}
|
||||
{/* icon={ChevronRight} */}
|
||||
{/* // onPress={() => ref.current?.scrollTo({ x: 0, animated: true })} */}
|
||||
{/* /> */}
|
||||
{/* </View> */}
|
||||
</View>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const GenreGrid = ({ genre }: { genre: Genre }) => {
|
||||
const query = useInfiniteFetch(GenreGrid.query(genre));
|
||||
const displayEmpty = useRef(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<InfiniteFetch
|
||||
query={GenreGrid.query(genre)}
|
||||
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
|
||||
empty={displayEmpty.current ? t("home.none") : undefined}
|
||||
Header={Header}
|
||||
headerProps={{ genre, displayEmpty: displayEmpty.current }}
|
||||
>
|
||||
{(x, i) => {
|
||||
// only display empty list if a loading as been displayed (not durring ssr)
|
||||
if (x.isLoading) displayEmpty.current = true;
|
||||
return (
|
||||
<ItemGrid
|
||||
key={x.id ?? i}
|
||||
isLoading={x.isLoading as any}
|
||||
href={x.href}
|
||||
name={x.name}
|
||||
subtitle={
|
||||
x.kind !== ItemKind.Collection && !x.isLoading ? getDisplayDate(x) : undefined
|
||||
}
|
||||
poster={x.poster}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</InfiniteFetch>
|
||||
<>
|
||||
{(displayEmpty.current || query.items?.length !== 0) && <Header title={genre} />}
|
||||
<InfiniteFetchList
|
||||
query={query}
|
||||
layout={{ ...ItemGrid.layout, layout: "horizontal" }}
|
||||
empty={displayEmpty.current ? t("home.none") : undefined}
|
||||
headerProps={{ title: genre, displayEmpty: displayEmpty.current }}
|
||||
>
|
||||
{(x, i) => {
|
||||
// only display empty list if a loading as been displayed (not durring ssr)
|
||||
if (x.isLoading) displayEmpty.current = true;
|
||||
return (
|
||||
<ItemGrid
|
||||
key={x.id ?? i}
|
||||
isLoading={x.isLoading as any}
|
||||
href={x.href}
|
||||
name={x.name}
|
||||
subtitle={
|
||||
x.kind !== ItemKind.Collection && !x.isLoading ? getDisplayDate(x) : undefined
|
||||
}
|
||||
poster={x.poster}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</InfiniteFetchList>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -111,5 +107,7 @@ GenreGrid.query = (genre: Genre): QueryIdentifier<LibraryItem> => ({
|
||||
params: {
|
||||
genres: genre,
|
||||
sortBy: "random",
|
||||
// Limit the inital numbers of items
|
||||
limit: 10,
|
||||
},
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user