From fc598838c41e8156ff193d2a60d3d27042f1a4dc Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sat, 21 Oct 2023 21:54:25 +0200 Subject: [PATCH] Disable empty genre list during ssr --- front/packages/ui/src/fetch-infinite.tsx | 14 ++-- front/packages/ui/src/fetch-infinite.web.tsx | 29 +++----- front/packages/ui/src/fetch.tsx | 18 +++++ front/packages/ui/src/home/genre.tsx | 74 ++++++++++++-------- front/translations/en.json | 3 +- front/translations/fr.json | 3 +- 6 files changed, 85 insertions(+), 56 deletions(-) diff --git a/front/packages/ui/src/fetch-infinite.tsx b/front/packages/ui/src/fetch-infinite.tsx index b6a3d0bc..5c118bb0 100644 --- a/front/packages/ui/src/fetch-infinite.tsx +++ b/front/packages/ui/src/fetch-infinite.tsx @@ -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 = ({ query, @@ -33,7 +33,7 @@ export const InfiniteFetch = ({ empty, divider = false, Header, - headerProps, + headerProps: hprops, getItemType, ...props }: { @@ -48,7 +48,7 @@ export const InfiniteFetch = ({ empty?: string | JSX.Element; incremental?: boolean; divider?: boolean | ComponentType; - Header?: ComponentType | ReactElement; + Header?: ComponentType | ReactElement; headerProps?: Props; getItemType?: (item: Data, index: number) => string | number; }): JSX.Element | null => { @@ -65,9 +65,13 @@ export const InfiniteFetch = ({ if (incremental && items) oldItems.current = items; if (error) return ; + // @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 ; + if (typeof empty !== "string") return addHeader(Header, empty, headerProps); + return addHeader(Header, , headerProps); } if (incremental) items ??= oldItems.current; diff --git a/front/packages/ui/src/fetch-infinite.web.tsx b/front/packages/ui/src/fetch-infinite.web.tsx index 87da70b5..ea13d51f 100644 --- a/front/packages/ui/src/fetch-infinite.web.tsx +++ b/front/packages/ui/src/fetch-infinite.web.tsx @@ -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 = ({ children, @@ -139,7 +139,7 @@ export const InfiniteFetch = ({ empty, divider: Divider = false, Header, - headerProps, + headerProps: hprops, getItemType, ...props }: { @@ -165,10 +165,14 @@ export const InfiniteFetch = ({ }); 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, , headerProps); if (empty && items && items.length === 0) { - if (typeof empty !== "string") return empty; - return ; + if (typeof empty !== "string") return addHeader(Header, empty, headerProps); + return addHeader(Header, , headerProps); } return ( @@ -196,20 +200,3 @@ export const InfiniteFetch = ({ ); }; - -const addHeader = ( - Header: ComponentType<{ children: JSX.Element } & Props> | ReactElement | undefined, - children: ReactElement, - headerProps?: Props, -) => { - if (!Header) return children; - return !isValidElement(Header) ? ( - // @ts-ignore -
{children}
- ) : ( - <> - {Header} - {children} - - ); -}; diff --git a/front/packages/ui/src/fetch.tsx b/front/packages/ui/src/fetch.tsx index 42be9276..9cd15bb4 100644 --- a/front/packages/ui/src/fetch.tsx +++ b/front/packages/ui/src/fetch.tsx @@ -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 }) => { ); }; + +export const addHeader = ( + Header: ComponentType<{ children: JSX.Element } & Props> | ReactElement | undefined, + children: ReactElement, + headerProps?: Props, +) => { + if (!Header) return children; + return !isValidElement(Header) ? ( + // @ts-ignore +
{children}
+ ) : ( + <> + {Header} + {children} + + ); +}; diff --git a/front/packages/ui/src/home/genre.tsx b/front/packages/ui/src/home/genre.tsx index 8a9b4c83..cd9b6289 100644 --- a/front/packages/ui/src/home/genre.tsx +++ b/front/packages/ui/src/home/genre.tsx @@ -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(null); +const Header = forwardRef< + View, + { empty: boolean; displayEmpty: boolean; genre: Genre; children: ReactElement } +>(function Header({ empty, displayEmpty, genre, children }, ref) { const { css } = useYoshiki(); return ( - - -

{genre}

- - ref.current?.scrollTo({ x: 0, animated: true })} - /> - ref.current?.scrollTo({ x: 0, animated: true })} - /> + + {!(empty && !displayEmpty) && ( + +

{genre}

+ + ref.current?.scrollTo({ x: 0, animated: true })} + /> + ref.current?.scrollTo({ x: 0, animated: true })} + /> +
-
- - {(x, i) => ( + )} + {children} +
+ ); +}); + +export const GenreGrid = ({ genre }: { genre: Genre }) => { + const displayEmpty = useRef(false); + const { t } = useTranslation(); + + return ( + + {(x, i) => { + // only display empty list if a loading as been displayed (not durring ssr) + if (x.isLoading) displayEmpty.current = true; + return ( { } poster={x.poster} /> - )} - -
+ ); + }} + ); }; diff --git a/front/translations/en.json b/front/translations/en.json index e0b62987..d740730d 100644 --- a/front/translations/en.json +++ b/front/translations/en.json @@ -1,7 +1,8 @@ { "home": { "recommanded": "Recommanded", - "info": "See more" + "info": "See more", + "none": "No episodes" }, "show": { "play": "Play", diff --git a/front/translations/fr.json b/front/translations/fr.json index 231330e4..58ed722d 100644 --- a/front/translations/fr.json +++ b/front/translations/fr.json @@ -1,7 +1,8 @@ { "home": { "recommanded": "Recommandé", - "info": "Voir plus" + "info": "Voir plus", + "none": "Aucun episode" }, "show": { "play": "Lecture",