mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
refactor: extract reusable component
This commit is contained in:
parent
4882d9c8cc
commit
d370afd0b2
17 changed files with 437 additions and 216 deletions
|
@ -9,8 +9,8 @@ import { ParentId } from 'types/library';
|
|||
|
||||
interface GenresItemsContainerProps {
|
||||
parentId: ParentId;
|
||||
collectionType: CollectionType;
|
||||
itemType: BaseItemKind;
|
||||
collectionType: CollectionType | undefined;
|
||||
itemType: BaseItemKind[];
|
||||
}
|
||||
|
||||
const GenresItemsContainer: FC<GenresItemsContainerProps> = ({
|
||||
|
|
|
@ -16,8 +16,8 @@ import { ParentId } from 'types/library';
|
|||
|
||||
interface GenresSectionContainerProps {
|
||||
parentId: ParentId;
|
||||
collectionType: CollectionType;
|
||||
itemType: BaseItemKind;
|
||||
collectionType: CollectionType | undefined;
|
||||
itemType: BaseItemKind[];
|
||||
genre: BaseItemDto;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ const GenresSectionContainer: FC<GenresSectionContainerProps> = ({
|
|||
return {
|
||||
sortBy: [ItemSortBy.Random],
|
||||
sortOrder: [SortOrder.Ascending],
|
||||
includeItemTypes: [itemType],
|
||||
includeItemTypes: itemType,
|
||||
recursive: true,
|
||||
fields: [
|
||||
ItemFields.PrimaryImageAspectRatio,
|
||||
|
@ -70,9 +70,9 @@ const GenresSectionContainer: FC<GenresSectionContainerProps> = ({
|
|||
showTitle: true,
|
||||
centerText: true,
|
||||
cardLayout: false,
|
||||
shape: itemType === BaseItemKind.MusicAlbum ? 'overflowSquare' : 'overflowPortrait',
|
||||
showParentTitle: itemType === BaseItemKind.MusicAlbum,
|
||||
showYear: itemType !== BaseItemKind.MusicAlbum
|
||||
shape: collectionType === CollectionType.Music ? 'overflowSquare' : 'overflowPortrait',
|
||||
showParentTitle: collectionType === CollectionType.Music,
|
||||
showYear: collectionType !== CollectionType.Music
|
||||
}}
|
||||
/>;
|
||||
};
|
||||
|
|
23
src/apps/experimental/components/library/GenresView.tsx
Normal file
23
src/apps/experimental/components/library/GenresView.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
||||
import React, { FC } from 'react';
|
||||
import GenresItemsContainer from './GenresItemsContainer';
|
||||
import { ParentId } from 'types/library';
|
||||
import { CollectionType } from 'types/collectionType';
|
||||
|
||||
interface GenresViewProps {
|
||||
parentId: ParentId;
|
||||
collectionType: CollectionType | undefined;
|
||||
itemType: BaseItemKind[];
|
||||
}
|
||||
|
||||
const GenresView: FC<GenresViewProps> = ({ parentId, collectionType, itemType }) => {
|
||||
return (
|
||||
<GenresItemsContainer
|
||||
parentId={parentId}
|
||||
collectionType={collectionType}
|
||||
itemType={itemType}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default GenresView;
|
65
src/apps/experimental/components/library/PageTabContent.tsx
Normal file
65
src/apps/experimental/components/library/PageTabContent.tsx
Normal file
|
@ -0,0 +1,65 @@
|
|||
import React, { FC } from 'react';
|
||||
import SuggestionsView from './SuggestionsView';
|
||||
import UpcomingView from './UpcomingView';
|
||||
import GenresView from './GenresView';
|
||||
import ItemsView from './ItemsView';
|
||||
import { LibraryTab } from 'types/libraryTab';
|
||||
import { ParentId } from 'types/library';
|
||||
import { LibraryTabContent } from 'types/libraryTabContent';
|
||||
|
||||
interface PageTabContentProps {
|
||||
parentId: ParentId;
|
||||
currentTab: LibraryTabContent;
|
||||
}
|
||||
|
||||
const PageTabContent: FC<PageTabContentProps> = ({ parentId, currentTab }) => {
|
||||
if (currentTab.viewType === LibraryTab.Suggestions) {
|
||||
return (
|
||||
<SuggestionsView
|
||||
parentId={parentId}
|
||||
suggestionSectionViews={
|
||||
currentTab.sectionsType?.suggestionSectionsView
|
||||
}
|
||||
isMovieRecommendations={
|
||||
currentTab.sectionsType?.isMovieRecommendations
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (currentTab.viewType === LibraryTab.Upcoming) {
|
||||
return <UpcomingView parentId={parentId} />;
|
||||
}
|
||||
|
||||
if (currentTab.viewType === LibraryTab.Genres) {
|
||||
return (
|
||||
<GenresView
|
||||
parentId={parentId}
|
||||
collectionType={currentTab.collectionType}
|
||||
itemType={currentTab.itemType || []}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ItemsView
|
||||
viewType={currentTab.viewType}
|
||||
parentId={parentId}
|
||||
collectionType={currentTab.collectionType}
|
||||
isBtnPlayAllEnabled={currentTab.isBtnPlayAllEnabled}
|
||||
isBtnQueueEnabled={currentTab.isBtnQueueEnabled}
|
||||
isBtnShuffleEnabled={currentTab.isBtnShuffleEnabled}
|
||||
isBtnNewCollectionEnabled={currentTab.isBtnNewCollectionEnabled}
|
||||
isBtnFilterEnabled={currentTab.isBtnFilterEnabled}
|
||||
isBtnGridListEnabled={currentTab.isBtnGridListEnabled}
|
||||
isBtnSortEnabled={currentTab.isBtnSortEnabled}
|
||||
isAlphabetPickerEnabled={currentTab.isAlphabetPickerEnabled}
|
||||
itemType={currentTab.itemType || []}
|
||||
noItemsMessage={
|
||||
currentTab.noItemsMessage || 'MessageNoItemsAvailable'
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageTabContent;
|
|
@ -0,0 +1,46 @@
|
|||
import React, { FC } from 'react';
|
||||
import { useGetMovieRecommendations } from 'hooks/useFetchItems';
|
||||
import Loading from 'components/loading/LoadingComponent';
|
||||
import globalize from 'scripts/globalize';
|
||||
import RecommendationContainer from './RecommendationContainer';
|
||||
import { ParentId } from 'types/library';
|
||||
|
||||
interface RecommendationItemsContainerProps {
|
||||
parentId?: ParentId;
|
||||
}
|
||||
|
||||
const RecommendationItemsContainer: FC<RecommendationItemsContainerProps> = ({
|
||||
parentId
|
||||
}) => {
|
||||
const { isLoading, data: movieRecommendationsItems } =
|
||||
useGetMovieRecommendations(parentId);
|
||||
|
||||
if (isLoading) return <Loading />;
|
||||
|
||||
if (!movieRecommendationsItems?.length) {
|
||||
return (
|
||||
<div className='noItemsMessage centerMessage'>
|
||||
<h1>{globalize.translate('MessageNothingHere')}</h1>
|
||||
<p>
|
||||
{globalize.translate('MessageNoMovieSuggestionsAvailable')}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{movieRecommendationsItems.map((recommendation, index) => {
|
||||
return (
|
||||
<RecommendationContainer
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={`${recommendation.CategoryId}-${index}`} // use a unique id return value may have duplicate id
|
||||
recommendation={recommendation}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecommendationItemsContainer;
|
33
src/apps/experimental/components/library/SuggestionsView.tsx
Normal file
33
src/apps/experimental/components/library/SuggestionsView.tsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
import React, { FC } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import SuggestionsItemsContainer from './SuggestionsItemsContainer';
|
||||
import RecommendationItemsContainer from './RecommendationItemsContainer';
|
||||
import { ParentId } from 'types/library';
|
||||
import { SectionsView } from 'types/suggestionsSections';
|
||||
|
||||
interface SuggestionsViewProps {
|
||||
parentId: ParentId;
|
||||
suggestionSectionViews: SectionsView[] | undefined;
|
||||
isMovieRecommendations: boolean | undefined;
|
||||
}
|
||||
|
||||
const SuggestionsView: FC<SuggestionsViewProps> = ({
|
||||
parentId,
|
||||
suggestionSectionViews = [],
|
||||
isMovieRecommendations = false
|
||||
}) => {
|
||||
return (
|
||||
<Box>
|
||||
<SuggestionsItemsContainer
|
||||
parentId={parentId}
|
||||
sectionsView={suggestionSectionViews}
|
||||
/>
|
||||
|
||||
{isMovieRecommendations && (
|
||||
<RecommendationItemsContainer parentId={parentId} />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SuggestionsView;
|
48
src/apps/experimental/components/library/UpcomingView.tsx
Normal file
48
src/apps/experimental/components/library/UpcomingView.tsx
Normal file
|
@ -0,0 +1,48 @@
|
|||
import React, { FC } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import { useGetGroupsUpcomingEpisodes } from 'hooks/useFetchItems';
|
||||
import Loading from 'components/loading/LoadingComponent';
|
||||
import globalize from 'scripts/globalize';
|
||||
import SectionContainer from './SectionContainer';
|
||||
import { LibraryViewProps } from 'types/library';
|
||||
|
||||
const UpcomingView: FC<LibraryViewProps> = ({ parentId }) => {
|
||||
const { isLoading, data: groupsUpcomingEpisodes } = useGetGroupsUpcomingEpisodes(parentId);
|
||||
|
||||
if (isLoading) return <Loading />;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{!groupsUpcomingEpisodes?.length ? (
|
||||
<div className='noItemsMessage centerMessage'>
|
||||
<h1>{globalize.translate('MessageNothingHere')}</h1>
|
||||
<p>
|
||||
{globalize.translate(
|
||||
'MessagePleaseEnsureInternetMetadata'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
groupsUpcomingEpisodes?.map((group) => (
|
||||
<SectionContainer
|
||||
key={group.name}
|
||||
sectionTitle={group.name}
|
||||
items={group.items ?? []}
|
||||
cardOptions={{
|
||||
shape: 'overflowBackdrop',
|
||||
showLocationTypeIndicator: false,
|
||||
showParentTitle: true,
|
||||
preferThumb: true,
|
||||
lazy: true,
|
||||
showDetailsMenu: true,
|
||||
missingIndicator: false,
|
||||
cardLayout: false
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpcomingView;
|
Loading…
Add table
Add a link
Reference in a new issue