From 94eaaf96b4302a832c52ccb72009b3593452c779 Mon Sep 17 00:00:00 2001 From: sct Date: Tue, 17 Nov 2020 09:18:45 +0000 Subject: [PATCH] feat: upcoming/trending list views and larger title cards --- src/components/Common/Header/index.tsx | 21 ++ src/components/Common/ListView/index.tsx | 14 +- src/components/Discover/DiscoverMovies.tsx | 13 +- src/components/Discover/DiscoverTv.tsx | 15 +- src/components/Discover/Trending.tsx | 81 +++++ src/components/Discover/Upcoming.tsx | 77 +++++ src/components/Discover/index.tsx | 26 +- src/components/PersonCard/index.tsx | 8 +- src/components/TitleCard/Placeholder.tsx | 12 +- src/components/TitleCard/index.tsx | 6 +- src/components/UserEdit/index.tsx | 320 +++++++++--------- src/components/UserList/index.tsx | 9 +- src/i18n/locale/en.json | 30 +- src/i18n/locale/ja.json | 24 ++ .../discover/{movies.tsx => movies/index.tsx} | 2 +- src/pages/discover/movies/upcoming.tsx | 9 + src/pages/discover/trending.tsx | 9 + 17 files changed, 457 insertions(+), 219 deletions(-) create mode 100644 src/components/Common/Header/index.tsx create mode 100644 src/components/Discover/Trending.tsx create mode 100644 src/components/Discover/Upcoming.tsx rename src/pages/discover/{movies.tsx => movies/index.tsx} (70%) create mode 100644 src/pages/discover/movies/upcoming.tsx create mode 100644 src/pages/discover/trending.tsx diff --git a/src/components/Common/Header/index.tsx b/src/components/Common/Header/index.tsx new file mode 100644 index 00000000..fc33bec5 --- /dev/null +++ b/src/components/Common/Header/index.tsx @@ -0,0 +1,21 @@ +import React from 'react'; + +interface HeaderProps { + extraMargin?: number; +} + +const Header: React.FC = ({ children, extraMargin = 0 }) => { + return ( +
+
+

+ + {children} + +

+
+
+ ); +}; + +export default Header; diff --git a/src/components/Common/ListView/index.tsx b/src/components/Common/ListView/index.tsx index 8f757f4f..f2fe94b7 100644 --- a/src/components/Common/ListView/index.tsx +++ b/src/components/Common/ListView/index.tsx @@ -31,7 +31,7 @@ const ListView: React.FC = ({ No Results )} -
    +
      {items?.map((title) => { let titleCard: React.ReactNode; @@ -47,6 +47,7 @@ const ListView: React.FC = ({ userScore={title.voteAverage} year={title.releaseDate} mediaType={title.mediaType} + canExpand /> ); break; @@ -61,12 +62,17 @@ const ListView: React.FC = ({ userScore={title.voteAverage} year={title.firstAirDate} mediaType={title.mediaType} + canExpand /> ); break; case 'person': titleCard = ( - + ); break; } @@ -82,12 +88,12 @@ const ListView: React.FC = ({ })} {isLoading && !isReachingEnd && - [...Array(10)].map((_item, i) => ( + [...Array(20)].map((_item, i) => (
    • - +
    • ))}
    diff --git a/src/components/Discover/DiscoverMovies.tsx b/src/components/Discover/DiscoverMovies.tsx index 6a2660dc..fc8a5096 100644 --- a/src/components/Discover/DiscoverMovies.tsx +++ b/src/components/Discover/DiscoverMovies.tsx @@ -4,9 +4,10 @@ import type { MovieResult } from '../../../server/models/Search'; import ListView from '../Common/ListView'; import { LanguageContext } from '../../context/LanguageContext'; import { defineMessages, FormattedMessage } from 'react-intl'; +import Header from '../Common/Header'; const messages = defineMessages({ - discovermovies: 'Discover Movies', + discovermovies: 'Popular Movies', }); interface SearchResult { @@ -55,13 +56,9 @@ const DiscoverMovies: React.FC = () => { return ( <> -
    -
    -

    - -

    -
    -
    +
    + +
    { return ( <> -
    -
    -

    - -

    -
    -
    +
    + +
    { + const { locale } = useContext(LanguageContext); + const { data, error, size, setSize } = useSWRInfinite( + (pageIndex: number, previousPageData: SearchResult | null) => { + if (previousPageData && pageIndex + 1 > previousPageData.totalPages) { + return null; + } + + return `/api/v1/discover/trending?page=${ + pageIndex + 1 + }&language=${locale}`; + }, + { + 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 | TvResult | PersonResult)[] + ); + + const isEmpty = !isLoadingInitialData && titles?.length === 0; + const isReachingEnd = + isEmpty || (data && data[data.length - 1]?.results.length < 20); + + return ( + <> +
    + +
    + 0) + } + isReachingEnd={isReachingEnd} + onScrollBottom={fetchMore} + /> + + ); +}; + +export default Trending; diff --git a/src/components/Discover/Upcoming.tsx b/src/components/Discover/Upcoming.tsx new file mode 100644 index 00000000..1687d0bc --- /dev/null +++ b/src/components/Discover/Upcoming.tsx @@ -0,0 +1,77 @@ +import React, { useContext } from 'react'; +import { useSWRInfinite } from 'swr'; +import type { MovieResult } from '../../../server/models/Search'; +import ListView from '../Common/ListView'; +import { LanguageContext } from '../../context/LanguageContext'; +import { defineMessages, FormattedMessage } from 'react-intl'; +import Header from '../Common/Header'; + +const messages = defineMessages({ + upcomingmovies: 'Upcoming Movies', +}); + +interface SearchResult { + page: number; + totalResults: number; + totalPages: number; + results: MovieResult[]; +} + +const UpcomingMovies: React.FC = () => { + const { locale } = useContext(LanguageContext); + const { data, error, size, setSize } = useSWRInfinite( + (pageIndex: number, previousPageData: SearchResult | null) => { + if (previousPageData && pageIndex + 1 > previousPageData.totalPages) { + return null; + } + + return `/api/v1/discover/movies/upcoming?page=${ + pageIndex + 1 + }&language=${locale}`; + }, + { + 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[] + ); + + const isEmpty = !isLoadingInitialData && titles?.length === 0; + const isReachingEnd = + isEmpty || (data && data[data.length - 1]?.results.length < 20); + + return ( + <> +
    + +
    + 0) + } + isReachingEnd={isReachingEnd} + onScrollBottom={fetchMore} + /> + + ); +}; + +export default UpcomingMovies; diff --git a/src/components/Discover/index.tsx b/src/components/Discover/index.tsx index 41d63a41..0ffa024b 100644 --- a/src/components/Discover/index.tsx +++ b/src/components/Discover/index.tsx @@ -77,27 +77,11 @@ const Discover: React.FC = () => { <>
    - - - - - - - - - - +
    + + + +
    = ({ name, subName, profilePath, + canExpand = false, }) => { return ( -
    +
    {profilePath && ( diff --git a/src/components/TitleCard/Placeholder.tsx b/src/components/TitleCard/Placeholder.tsx index 99ce58f4..524262d1 100644 --- a/src/components/TitleCard/Placeholder.tsx +++ b/src/components/TitleCard/Placeholder.tsx @@ -1,8 +1,16 @@ import React from 'react'; -const Placeholder: React.FC = () => { +interface PlaceholderProps { + canExpand?: boolean; +} + +const Placeholder: React.FC = ({ canExpand = false }) => { return ( -
    +
    ); diff --git a/src/components/TitleCard/index.tsx b/src/components/TitleCard/index.tsx index f6fa1514..8d4d514c 100644 --- a/src/components/TitleCard/index.tsx +++ b/src/components/TitleCard/index.tsx @@ -19,7 +19,7 @@ interface TitleCardProps { userScore: number; mediaType: MediaType; status?: MediaStatus; - requestId?: number; + canExpand?: boolean; } const TitleCard: React.FC = ({ @@ -30,7 +30,7 @@ const TitleCard: React.FC = ({ title, status, mediaType, - requestId, + canExpand = false, }) => { const [isUpdating, setIsUpdating] = useState(false); const [currentStatus, setCurrentStatus] = useState(status); @@ -55,7 +55,7 @@ const TitleCard: React.FC = ({ const closeModal = useCallback(() => setShowRequestModal(false), []); return ( -
    +
    { ]; return ( -
    -
    -
    -

    - -

    -
    -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -