From be0003a85dc4e91799e85019aeb1110bd524a026 Mon Sep 17 00:00:00 2001 From: sct Date: Thu, 17 Sep 2020 03:10:00 +0000 Subject: [PATCH] feat(frontend): discover tv/movies full page Also adds ListView component for infinite scrolling pages --- server/models/Search.ts | 3 +- src/components/Common/ListView/index.tsx | 94 ++++++++++++++++++++++ src/components/Discover/DiscoverMovies.tsx | 66 +++++++++++++++ src/components/Discover/DiscoverTv.tsx | 63 +++++++++++++++ src/components/MovieDetails/index.tsx | 2 +- src/components/Search/index.tsx | 80 +++--------------- src/components/Slider/index.tsx | 4 +- src/components/TitleCard/Placeholder.tsx | 7 +- src/pages/discover/movies.tsx | 9 +++ src/pages/discover/tv.tsx | 9 +++ 10 files changed, 260 insertions(+), 77 deletions(-) create mode 100644 src/components/Common/ListView/index.tsx create mode 100644 src/components/Discover/DiscoverMovies.tsx create mode 100644 src/components/Discover/DiscoverTv.tsx create mode 100644 src/pages/discover/movies.tsx create mode 100644 src/pages/discover/tv.tsx diff --git a/server/models/Search.ts b/server/models/Search.ts index 9550f8663..ec93995b9 100644 --- a/server/models/Search.ts +++ b/server/models/Search.ts @@ -80,7 +80,8 @@ export const mapTvResult = ( id: tvResult.id, firstAirDate: tvResult.first_air_Date, genreIds: tvResult.genre_ids, - mediaType: tvResult.media_type, + // Some results from tmdb dont return the mediaType so we force it here! + mediaType: tvResult.media_type || 'tv', name: tvResult.name, originCountry: tvResult.origin_country, originalLanguage: tvResult.original_language, diff --git a/src/components/Common/ListView/index.tsx b/src/components/Common/ListView/index.tsx new file mode 100644 index 000000000..0ab8328a0 --- /dev/null +++ b/src/components/Common/ListView/index.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import { + TvResult, + MovieResult, + PersonResult, +} from '../../../../server/models/Search'; +import TitleCard from '../../TitleCard'; +import useVerticalScroll from '../../../hooks/useVerticalScroll'; + +interface ListViewProps { + items?: (TvResult | MovieResult | PersonResult)[]; + isEmpty?: boolean; + isLoading?: boolean; + onScrollBottom: () => void; +} + +const ListView: React.FC = ({ + items, + isEmpty, + isLoading, + onScrollBottom, +}) => { + useVerticalScroll(onScrollBottom, !isLoading); + return ( + <> + {isEmpty && ( +
+ No Results +
+ )} + + + ); +}; + +export default ListView; diff --git a/src/components/Discover/DiscoverMovies.tsx b/src/components/Discover/DiscoverMovies.tsx new file mode 100644 index 000000000..fe5b365e9 --- /dev/null +++ b/src/components/Discover/DiscoverMovies.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { useSWRInfinite } from 'swr'; +import { MovieResult } from '../../../server/models/Search'; +import ListView from '../Common/ListView'; + +interface SearchResult { + page: number; + totalResults: number; + totalPages: number; + results: MovieResult[]; +} + +const DiscoverMovies: React.FC = () => { + const { data, error, size, setSize } = useSWRInfinite( + (pageIndex: number, previousPageData: SearchResult | null) => { + if (previousPageData && pageIndex + 1 > previousPageData.totalPages) { + return null; + } + + return `/api/v1/discover/movies?page=${pageIndex + 1}`; + }, + { + initialSize: 3, + } + ); + + const isLoadingInitialData = !data && !error; + const isLoadingMore = + isLoadingInitialData || + (size > 0 && data && typeof data[size - 1] === 'undefined'); + + const fetchMore = () => { + setSize(size + 1); + }; + + if (error) { + return
{error}
; + } + + const titles = data?.reduce( + (a, v) => [...a, ...v.results], + [] as MovieResult[] + ); + + return ( + <> +
+
+

+ Discover Movies +

+
+
+ 0) + } + onScrollBottom={fetchMore} + /> + + ); +}; + +export default DiscoverMovies; diff --git a/src/components/Discover/DiscoverTv.tsx b/src/components/Discover/DiscoverTv.tsx new file mode 100644 index 000000000..ee76e5ecc --- /dev/null +++ b/src/components/Discover/DiscoverTv.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { useSWRInfinite } from 'swr'; +import { TvResult } from '../../../server/models/Search'; +import ListView from '../Common/ListView'; + +interface SearchResult { + page: number; + totalResults: number; + totalPages: number; + results: TvResult[]; +} + +const DiscoverTv: React.FC = () => { + const { data, error, size, setSize } = useSWRInfinite( + (pageIndex: number, previousPageData: SearchResult | null) => { + if (previousPageData && pageIndex + 1 > previousPageData.totalPages) { + return null; + } + + return `/api/v1/discover/tv?page=${pageIndex + 1}`; + }, + { + initialSize: 3, + } + ); + + const isLoadingInitialData = !data && !error; + const isLoadingMore = + isLoadingInitialData || + (size > 0 && data && typeof data[size - 1] === 'undefined'); + + const fetchMore = () => { + setSize(size + 1); + }; + + if (error) { + return
{error}
; + } + + const titles = data?.reduce((a, v) => [...a, ...v.results], [] as TvResult[]); + + return ( + <> +
+
+

+ Discover Series +

+
+
+ 0) + } + onScrollBottom={fetchMore} + /> + + ); +}; + +export default DiscoverTv; diff --git a/src/components/MovieDetails/index.tsx b/src/components/MovieDetails/index.tsx index edd4f4604..53e1d906f 100644 --- a/src/components/MovieDetails/index.tsx +++ b/src/components/MovieDetails/index.tsx @@ -67,7 +67,7 @@ const MovieDetails: React.FC = ({ movie }) => { } return (
{ isLoadingInitialData || (size > 0 && data && typeof data[size - 1] === 'undefined'); - useVerticalScroll(() => { + const fetchMore = () => { setSize(size + 1); - }, !isLoadingMore && !isLoadingInitialData); + }; if (error) { return
{error}
; @@ -76,71 +75,14 @@ const Search: React.FC = () => {
- {!isLoadingInitialData && titles?.length === 0 && ( -
- No Results -
- )} -
    - {titles?.map((title) => { - let titleCard: React.ReactNode; - - switch (title.mediaType) { - case 'movie': - titleCard = ( - - ); - break; - case 'tv': - titleCard = ( - - ); - break; - case 'person': - titleCard =
    {title.name}
    ; - break; - } - - return ( -
  • - {titleCard} -
  • - ); - })} - {(isLoadingInitialData || - (isLoadingMore && (titles?.length ?? 0) > 0)) && - [...Array(10)].map((_item, i) => ( -
  • - -
  • - ))} -
+ 0) + } + onScrollBottom={fetchMore} + /> ); }; diff --git a/src/components/Slider/index.tsx b/src/components/Slider/index.tsx index 3cd5dba99..27fbfc3f9 100644 --- a/src/components/Slider/index.tsx +++ b/src/components/Slider/index.tsx @@ -19,7 +19,7 @@ const Slider: React.FC = ({ {items?.map((item, index) => (
{item}
@@ -28,7 +28,7 @@ const Slider: React.FC = ({ [...Array(10)].map((_item, i) => (
diff --git a/src/components/TitleCard/Placeholder.tsx b/src/components/TitleCard/Placeholder.tsx index 5210739e8..99ce58f43 100644 --- a/src/components/TitleCard/Placeholder.tsx +++ b/src/components/TitleCard/Placeholder.tsx @@ -2,10 +2,9 @@ import React from 'react'; const Placeholder: React.FC = () => { return ( -
+
+
+
); }; diff --git a/src/pages/discover/movies.tsx b/src/pages/discover/movies.tsx new file mode 100644 index 000000000..ca5e75f46 --- /dev/null +++ b/src/pages/discover/movies.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { NextPage } from 'next'; +import DiscoverMovies from '../../components/Discover/DiscoverMovies'; + +const DiscoverMoviesPage: NextPage = () => { + return ; +}; + +export default DiscoverMoviesPage; diff --git a/src/pages/discover/tv.tsx b/src/pages/discover/tv.tsx new file mode 100644 index 000000000..03c1d6f80 --- /dev/null +++ b/src/pages/discover/tv.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { NextPage } from 'next'; +import DiscoverTv from '../../components/Discover/DiscoverTv'; + +const DiscoverMoviesPage: NextPage = () => { + return ; +}; + +export default DiscoverMoviesPage;