diff --git a/src/view/components/RecommendationContainer.tsx b/src/view/components/RecommendationContainer.tsx index 7501585a5d..75756a8a1f 100644 --- a/src/view/components/RecommendationContainer.tsx +++ b/src/view/components/RecommendationContainer.tsx @@ -1,13 +1,9 @@ -import '../../elements/emby-itemscontainer/emby-itemscontainer'; - import { RecommendationDto } from '@thornbill/jellyfin-sdk/dist/generated-client'; -import React, { FunctionComponent, useEffect, useRef } from 'react'; +import React, { FunctionComponent } from 'react'; -import cardBuilder from '../../components/cardbuilder/cardBuilder'; import globalize from '../../scripts/globalize'; -import ItemsContainerElement from '../../elements/ItemsContainerElement'; -import ItemsScrollerContainerElement from '../../elements/ItemsScrollerContainerElement'; import escapeHTML from 'escape-html'; +import SectionContainer from './SectionContainer'; type RecommendationContainerProps = { getPortraitShape: () => string; @@ -16,8 +12,6 @@ type RecommendationContainerProps = { } const RecommendationContainer: FunctionComponent = ({ getPortraitShape, enableScrollX, recommendation = {} }: RecommendationContainerProps) => { - const element = useRef(null); - let title = ''; switch (recommendation.RecommendationType) { @@ -40,40 +34,15 @@ const RecommendationContainer: FunctionComponent = break; } - useEffect(() => { - cardBuilder.buildCards(recommendation.Items || [], { - itemsContainer: element.current?.querySelector('.itemsContainer'), + return -
-
-

- {escapeHTML(title)} -

-
- - {enableScrollX() ? : } - -
- - ); + showYear: true + }} + />; }; export default RecommendationContainer; diff --git a/src/view/components/ResumableItemsContainer.tsx b/src/view/components/ResumableItemsContainer.tsx deleted file mode 100644 index b26b8613fa..0000000000 --- a/src/view/components/ResumableItemsContainer.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import '../../elements/emby-itemscontainer/emby-itemscontainer'; - -import { BaseItemDtoQueryResult } from '@thornbill/jellyfin-sdk/dist/generated-client'; -import React, { FunctionComponent, useEffect, useRef } from 'react'; - -import cardBuilder from '../../components/cardbuilder/cardBuilder'; -import globalize from '../../scripts/globalize'; -import ItemsContainerElement from '../../elements/ItemsContainerElement'; -import ItemsScrollerContainerElement from '../../elements/ItemsScrollerContainerElement'; - -type ResumableItemsContainerProps = { - getThumbShape: () => string; - enableScrollX: () => boolean; - itemsResult?: BaseItemDtoQueryResult; -} - -const ResumableItemsContainer: FunctionComponent = ({ getThumbShape, enableScrollX, itemsResult = {} }: ResumableItemsContainerProps) => { - const element = useRef(null); - - useEffect(() => { - const allowBottomPadding = !enableScrollX(); - cardBuilder.buildCards(itemsResult.Items || [], { - itemsContainer: element.current?.querySelector('.itemsContainer'), - parentContainer: element.current?.querySelector('#resumableSection'), - preferThumb: true, - shape: getThumbShape(), - scalable: true, - overlayPlayButton: true, - allowBottomPadding: allowBottomPadding, - cardLayout: false, - showTitle: true, - showYear: true, - centerText: true - }); - }, [enableScrollX, getThumbShape, itemsResult.Items]); - - return ( -
-
-
-

- {globalize.translate('HeaderContinueWatching')} -

-
- - {enableScrollX() ? : } - -
-
- ); -}; - -export default ResumableItemsContainer; diff --git a/src/view/components/RecentlyAddedItemsContainer.tsx b/src/view/components/SectionContainer.tsx similarity index 67% rename from src/view/components/RecentlyAddedItemsContainer.tsx rename to src/view/components/SectionContainer.tsx index 60c6571bd6..2268fe292c 100644 --- a/src/view/components/RecentlyAddedItemsContainer.tsx +++ b/src/view/components/SectionContainer.tsx @@ -4,39 +4,44 @@ import { BaseItemDto } from '@thornbill/jellyfin-sdk/dist/generated-client'; import React, { FunctionComponent, useEffect, useRef } from 'react'; import cardBuilder from '../../components/cardbuilder/cardBuilder'; -import globalize from '../../scripts/globalize'; import ItemsContainerElement from '../../elements/ItemsContainerElement'; import ItemsScrollerContainerElement from '../../elements/ItemsScrollerContainerElement'; +import { ICardOptions } from './type'; -type RecentlyAddedItemsContainerProps = { - getPortraitShape: () => string; +type SectionContainerProps = { + sectionTitle: string; enableScrollX: () => boolean; items?: BaseItemDto[]; + cardOptions?: ICardOptions; } -const RecentlyAddedItemsContainer: FunctionComponent = ({ getPortraitShape, enableScrollX, items = [] }: RecentlyAddedItemsContainerProps) => { +const SectionContainer: FunctionComponent = ({ + sectionTitle, + enableScrollX, + items = [], + cardOptions = {} +}: SectionContainerProps) => { const element = useRef(null); useEffect(() => { cardBuilder.buildCards(items, { itemsContainer: element.current?.querySelector('.itemsContainer'), - parentContainer: element.current?.querySelector('#recentlyAddedItemsSection'), - shape: getPortraitShape(), + parentContainer: element.current?.querySelector('.verticalSection'), scalable: true, overlayPlayButton: true, - allowBottomPadding: true, showTitle: true, - showYear: true, - centerText: true + centerText: true, + cardLayout: false, + ...cardOptions }); - }, [enableScrollX, getPortraitShape, items]); + }, [cardOptions, enableScrollX, items]); return (
-
+

- {globalize.translate('HeaderLatestMovies')} + {sectionTitle}

@@ -54,4 +59,4 @@ const RecentlyAddedItemsContainer: FunctionComponent = (props: IProps) => { const [ latestItems, setLatestItems ] = useState([]); - const [ resumeItemsResult, setResumeItemsResult ] = useState(); + const [ resumeResult, setResumeResult ] = useState({}); const [ recommendations, setRecommendations ] = useState([]); const element = useRef(null); @@ -37,6 +36,31 @@ const SuggestionsView: FunctionComponent = (props: IProps) => { }); }, []); + const loadResume = useCallback((page, userId, parentId) => { + loading.show(); + const screenWidth = dom.getWindowSize().innerWidth; + const options = { + SortBy: 'DatePlayed', + SortOrder: 'Descending', + IncludeItemTypes: 'Movie', + Filters: 'IsResumable', + Limit: screenWidth >= 1600 ? 5 : 3, + Recursive: true, + Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo', + CollapseBoxSetItems: false, + ParentId: parentId, + ImageTypeLimit: 1, + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', + EnableTotalRecordCount: false + }; + window.ApiClient.getItems(userId, options).then(result => { + setResumeResult(result); + + loading.hide(); + autoFocus(page); + }); + }, [autoFocus]); + const loadLatest = useCallback((page: HTMLDivElement, userId: string, parentId: string | null) => { const options = { IncludeItemTypes: 'Movie', @@ -50,43 +74,16 @@ const SuggestionsView: FunctionComponent = (props: IProps) => { window.ApiClient.getJSON(window.ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(items => { setLatestItems(items); - // FIXME: Wait for all sections to load - autoFocus(page); - }); - }, [autoFocus]); - - const loadResume = useCallback((page, userId, parentId) => { - loading.show(); - const screenWidth = dom.getWindowSize(); - const options = { - SortBy: 'DatePlayed', - SortOrder: 'Descending', - IncludeItemTypes: 'Movie', - Filters: 'IsResumable', - Limit: screenWidth.innerWidth >= 1600 ? 5 : 3, - Recursive: true, - Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo', - CollapseBoxSetItems: false, - ParentId: parentId, - ImageTypeLimit: 1, - EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', - EnableTotalRecordCount: false - }; - window.ApiClient.getItems(userId, options).then(result => { - setResumeItemsResult(result); - - loading.hide(); - // FIXME: Wait for all sections to load autoFocus(page); }); }, [autoFocus]); const loadSuggestions = useCallback((page, userId) => { - const screenWidth = dom.getWindowSize(); + const screenWidth = dom.getWindowSize().innerWidth; let itemLimit = 5; - if (screenWidth.innerWidth >= 1600) { + if (screenWidth >= 1600) { itemLimit = 8; - } else if (screenWidth.innerWidth >= 1200) { + } else if (screenWidth >= 1200) { itemLimit = 6; } const url = window.window.ApiClient.getUrl('Movies/Recommendations', { @@ -100,7 +97,6 @@ const SuggestionsView: FunctionComponent = (props: IProps) => { window.ApiClient.getJSON(url).then(result => { setRecommendations(result); - // FIXME: Wait for all sections to load autoFocus(page); }); }, [autoFocus]); @@ -126,18 +122,33 @@ const SuggestionsView: FunctionComponent = (props: IProps) => { return (
- + - + -
- {!recommendations.length ?
-

{globalize.translate('MessageNothingHere')}

-

{globalize.translate('MessageNoMovieSuggestionsAvailable')}

-
: recommendations.map((recommendation, index) => { - return ; - })} -
+ {!recommendations.length ?
+

{globalize.translate('MessageNothingHere')}

+

{globalize.translate('MessageNoMovieSuggestionsAvailable')}

+
: recommendations.map((recommendation, index) => { + return ; + })}
); };