Disable empty genre list during ssr

This commit is contained in:
Zoe Roux 2023-10-21 21:54:25 +02:00
parent 11712b5b13
commit fc598838c4
6 changed files with 85 additions and 56 deletions

View File

@ -22,7 +22,7 @@ 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 { EmptyView, ErrorView, Layout, WithLoading } from "./fetch";
import { EmptyView, ErrorView, Layout, WithLoading, addHeader } from "./fetch";
export const InfiniteFetch = <Data, Props, _>({
query,
@ -33,7 +33,7 @@ export const InfiniteFetch = <Data, Props, _>({
empty,
divider = false,
Header,
headerProps,
headerProps: hprops,
getItemType,
...props
}: {
@ -48,7 +48,7 @@ export const InfiniteFetch = <Data, Props, _>({
empty?: string | JSX.Element;
incremental?: boolean;
divider?: boolean | ComponentType;
Header?: ComponentType<Props & { children: JSX.Element }> | ReactElement;
Header?: ComponentType<Props & { children: JSX.Element; empty: boolean }> | ReactElement;
headerProps?: Props;
getItemType?: (item: Data, index: number) => string | number;
}): JSX.Element | null => {
@ -65,9 +65,13 @@ export const InfiniteFetch = <Data, Props, _>({
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 empty;
return <EmptyView message={empty} />;
if (typeof empty !== "string") return addHeader(Header, empty, headerProps);
return addHeader(Header, <EmptyView message={empty} />, headerProps);
}
if (incremental) items ??= oldItems.current;

View File

@ -30,7 +30,7 @@ import {
useRef,
} from "react";
import { Stylable, useYoshiki, ysMap } from "yoshiki";
import { EmptyView, ErrorView, Layout, WithLoading } from "./fetch";
import { EmptyView, ErrorView, Layout, WithLoading, addHeader } from "./fetch";
const InfiniteScroll = <Props,>({
children,
@ -139,7 +139,7 @@ export const InfiniteFetch = <Data, _, HeaderProps>({
empty,
divider: Divider = false,
Header,
headerProps,
headerProps: hprops,
getItemType,
...props
}: {
@ -165,10 +165,14 @@ export const InfiniteFetch = <Data, _, HeaderProps>({
});
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 empty;
return <EmptyView message={empty} />;
if (typeof empty !== "string") return addHeader(Header, empty, headerProps);
return addHeader(Header, <EmptyView message={empty} />, headerProps);
}
return (
@ -196,20 +200,3 @@ export const InfiniteFetch = <Data, _, HeaderProps>({
</InfiniteScroll>
);
};
const addHeader = <Props,>(
Header: ComponentType<{ children: JSX.Element } & Props> | ReactElement | undefined,
children: ReactElement,
headerProps?: Props,
) => {
if (!Header) return children;
return !isValidElement(Header) ? (
// @ts-ignore
<Header {...(headerProps ?? {})}>{children}</Header>
) : (
<>
{Header}
{children}
</>
);
};

View File

@ -20,6 +20,7 @@
import { Page, QueryIdentifier, useFetch, KyooErrors } from "@kyoo/models";
import { Breakpoint, P } from "@kyoo/primitives";
import { ComponentType, ReactElement, isValidElement } from "react";
import { View } from "react-native";
import { useYoshiki } from "yoshiki/native";
@ -130,3 +131,20 @@ export const EmptyView = ({ message }: { message: string }) => {
</View>
);
};
export const addHeader = <Props,>(
Header: ComponentType<{ children: JSX.Element } & Props> | ReactElement | undefined,
children: ReactElement,
headerProps?: Props,
) => {
if (!Header) return children;
return !isValidElement(Header) ? (
// @ts-ignore
<Header {...(headerProps ?? {})}>{children}</Header>
) : (
<>
{Header}
{children}
</>
);
};

View File

@ -23,45 +23,63 @@ import {
ItemKind,
LibraryItem,
LibraryItemP,
Page,
Paged,
QueryIdentifier,
getDisplayDate,
} from "@kyoo/models";
import { H3, IconButton, ts } from "@kyoo/primitives";
import { useRef } from "react";
import { ScrollView, View } from "react-native";
import { ReactElement, forwardRef, useRef } from "react";
import { View } from "react-native";
import { useYoshiki } from "yoshiki/native";
import { Fetch } from "../fetch";
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 { useTranslation } from "react-i18next";
export const GenreGrid = ({ genre }: { genre: Genre }) => {
const ref = useRef<ScrollView>(null);
const Header = forwardRef<
View,
{ empty: boolean; displayEmpty: boolean; genre: Genre; children: ReactElement }
>(function Header({ empty, displayEmpty, genre, children }, ref) {
const { css } = useYoshiki();
return (
<View>
<View ref={ref}>
{!(empty && !displayEmpty) && (
<View {...css({ marginX: ts(1), flexDirection: "row", justifyContent: "space-between" })}>
<H3>{genre}</H3>
<View {...css({ flexDirection: "row" })}>
<IconButton
icon={ChevronLeft}
onPress={() => ref.current?.scrollTo({ x: 0, animated: true })}
// onPress={() => ref.current?.scrollTo({ x: 0, animated: true })}
/>
<IconButton
icon={ChevronRight}
onPress={() => ref.current?.scrollTo({ x: 0, animated: true })}
// onPress={() => ref.current?.scrollTo({ x: 0, animated: true })}
/>
</View>
</View>
)}
{children}
</View>
);
});
export const GenreGrid = ({ genre }: { genre: 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) => (
{(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}
@ -72,9 +90,9 @@ export const GenreGrid = ({ genre }: { genre: Genre }) => {
}
poster={x.poster}
/>
)}
);
}}
</InfiniteFetch>
</View>
);
};

View File

@ -1,7 +1,8 @@
{
"home": {
"recommanded": "Recommanded",
"info": "See more"
"info": "See more",
"none": "No episodes"
},
"show": {
"play": "Play",

View File

@ -1,7 +1,8 @@
{
"home": {
"recommanded": "Recommandé",
"info": "Voir plus"
"info": "Voir plus",
"none": "Aucun episode"
},
"show": {
"play": "Lecture",