1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Refactoring Section Container

This commit is contained in:
grafixeyehero 2024-09-23 02:53:44 +03:00 committed by Bill Thornton
parent c3e253d98d
commit 12995545b9
11 changed files with 257 additions and 183 deletions

View file

@ -2,7 +2,7 @@ import type { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/bas
import type { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
import React, { FC } from 'react';
import { useGetGenres } from 'hooks/useFetchItems';
import globalize from 'lib/globalize';
import NoItemsMessage from 'components/common/NoItemsMessage';
import Loading from 'components/loading/LoadingComponent';
import GenresSectionContainer from './GenresSectionContainer';
import type { ParentId } from 'types/library';
@ -25,27 +25,18 @@ const GenresItemsContainer: FC<GenresItemsContainerProps> = ({
}
if (!genresResult?.Items?.length) {
return (
<div className='noItemsMessage centerMessage'>
<h1>{globalize.translate('MessageNothingHere')}</h1>
<p>{globalize.translate('MessageNoGenresAvailable')}</p>
</div>
);
return <NoItemsMessage message='MessageNoGenresAvailable' />;
}
return (
<>
{genresResult.Items.map((genre) => (
<GenresSectionContainer
key={genre.Id}
collectionType={collectionType}
parentId={parentId}
itemType={itemType}
genre={genre}
/>
))}
</>
);
return genresResult.Items.map((genre) => (
<GenresSectionContainer
key={genre.Id}
collectionType={collectionType}
parentId={parentId}
itemType={itemType}
genre={genre}
/>
));
};
export default GenresItemsContainer;

View file

@ -8,7 +8,7 @@ import React, { type FC } from 'react';
import { useGetItems } from 'hooks/useFetchItems';
import Loading from 'components/loading/LoadingComponent';
import { appRouter } from 'components/router/appRouter';
import SectionContainer from './SectionContainer';
import SectionContainer from 'components/common/SectionContainer';
import { CardShape } from 'utils/card';
import type { ParentId } from 'types/library';
import type { ItemDto } from 'types/base/models/item-dto';
@ -59,9 +59,12 @@ const GenresSectionContainer: FC<GenresSectionContainerProps> = ({
}
return <SectionContainer
sectionTitle={genre.Name || ''}
items={itemsResult?.Items || []}
url={getRouteUrl(genre)}
key={genre.Name}
sectionHeaderProps={{
title: genre.Name || '',
url: getRouteUrl(genre)
}}
items={itemsResult?.Items}
cardOptions={{
scalable: true,
overlayPlayButton: true,

View file

@ -181,7 +181,7 @@ const ItemsView: FC<ItemsViewProps> = ({
const getItems = useCallback(() => {
if (!itemsResult?.Items?.length) {
return <NoItemsMessage noItemsMessage={noItemsMessage} />;
return <NoItemsMessage message={noItemsMessage} />;
}
if (libraryViewSettings.ViewMode === ViewMode.ListView) {

View file

@ -3,7 +3,8 @@ import { useGetProgramsSectionsWithItems, useGetTimers } from 'hooks/useFetchIte
import { appRouter } from 'components/router/appRouter';
import globalize from 'lib/globalize';
import Loading from 'components/loading/LoadingComponent';
import SectionContainer from './SectionContainer';
import NoItemsMessage from 'components/common/NoItemsMessage';
import SectionContainer from 'components/common/SectionContainer';
import { CardShape } from 'utils/card';
import type { ParentId } from 'types/library';
import type { Section, SectionType } from 'types/sections';
@ -30,14 +31,7 @@ const ProgramsSectionView: FC<ProgramsSectionViewProps> = ({
}
if (!sectionsWithItems?.length && !upcomingRecordings?.length) {
return (
<div className='noItemsMessage centerMessage'>
<h1>{globalize.translate('MessageNothingHere')}</h1>
<p>
{globalize.translate('MessageNoItemsAvailable')}
</p>
</div>
);
return <NoItemsMessage />;
}
const getRouteUrl = (section: Section) => {
@ -58,23 +52,33 @@ const ProgramsSectionView: FC<ProgramsSectionViewProps> = ({
{sectionsWithItems?.map(({ section, items }) => (
<SectionContainer
key={section.type}
sectionTitle={globalize.translate(section.name)}
items={items ?? []}
url={getRouteUrl(section)}
reloadItems={refetch}
sectionHeaderProps={{
title: globalize.translate(section.name),
url: getRouteUrl(section)
}}
itemsContainerProps={{
queryKey: ['ProgramSectionWithItems'],
reloadItems: refetch
}}
items={items}
cardOptions={{
...section.cardOptions,
queryKey: ['ProgramSectionWithItems']
}}
/>
))}
{upcomingRecordings?.map((group) => (
<SectionContainer
key={group.name}
sectionTitle={group.name}
items={group.timerInfo ?? []}
sectionHeaderProps={{
title: group.name
}}
itemsContainerProps={{
queryKey: ['Timers'],
reloadItems: refetch
}}
items={group.timerInfo }
cardOptions={{
queryKey: ['Timers'],
shape: CardShape.BackdropOverflow,

View file

@ -1,65 +0,0 @@
import React, { FC } from 'react';
import ItemsContainer from 'elements/emby-itemscontainer/ItemsContainer';
import Scroller from 'elements/emby-scroller/Scroller';
import LinkButton from 'elements/emby-button/LinkButton';
import Cards from 'components/cardbuilder/Card/Cards';
import type { CardOptions } from 'types/cardOptions';
import type { ItemDto } from 'types/base/models/item-dto';
interface SectionContainerProps {
url?: string;
sectionTitle: string;
items: ItemDto[];
cardOptions: CardOptions;
reloadItems?: () => void;
}
const SectionContainer: FC<SectionContainerProps> = ({
sectionTitle,
url,
items,
cardOptions,
reloadItems
}) => {
return (
<div className='verticalSection'>
<div className='sectionTitleContainer sectionTitleContainer-cards padded-left'>
{url && items.length > 5 ? (
<LinkButton
className='more button-flat button-flat-mini sectionTitleTextButton btnMoreFromGenre'
href={url}
>
<h2 className='sectionTitle sectionTitle-cards'>
{sectionTitle}
</h2>
<span
className='material-icons chevron_right'
aria-hidden='true'
></span>
</LinkButton>
) : (
<h2 className='sectionTitle sectionTitle-cards'>
{sectionTitle}
</h2>
)}
</div>
<Scroller
className='padded-top-focusscale padded-bottom-focusscale'
isMouseWheelEnabled={false}
isCenterFocusEnabled={true}
>
<ItemsContainer
className='itemsContainer scrollSlider focuscontainer-x'
reloadItems={reloadItems}
queryKey={cardOptions.queryKey}
>
<Cards items={items} cardOptions={cardOptions} />
</ItemsContainer>
</Scroller>
</div>
);
};
export default SectionContainer;

View file

@ -8,7 +8,8 @@ import {
import { appRouter } from 'components/router/appRouter';
import globalize from 'lib/globalize';
import Loading from 'components/loading/LoadingComponent';
import SectionContainer from './SectionContainer';
import NoItemsMessage from 'components/common/NoItemsMessage';
import SectionContainer from '../../../../components/common/SectionContainer';
import { CardShape } from 'utils/card';
import type { ParentId } from 'types/library';
import type { Section, SectionType } from 'types/sections';
@ -38,12 +39,7 @@ const SuggestionsSectionView: FC<SuggestionsSectionViewProps> = ({
}
if (!sectionsWithItems?.length && !movieRecommendationsItems?.length) {
return (
<div className='noItemsMessage centerMessage'>
<h1>{globalize.translate('MessageNothingHere')}</h1>
<p>{globalize.translate('MessageNoItemsAvailable')}</p>
</div>
);
return <NoItemsMessage />;
}
const getRouteUrl = (section: Section) => {
@ -96,9 +92,14 @@ const SuggestionsSectionView: FC<SuggestionsSectionViewProps> = ({
{sectionsWithItems?.map(({ section, items }) => (
<SectionContainer
key={section.type}
sectionTitle={globalize.translate(section.name)}
items={items ?? []}
url={getRouteUrl(section)}
sectionHeaderProps={{
title: globalize.translate(section.name),
url: getRouteUrl(section)
}}
itemsContainerProps={{
queryKey: ['SuggestionSectionWithItems']
}}
items={items}
cardOptions={{
...section.cardOptions,
queryKey: ['SuggestionSectionWithItems'],
@ -114,8 +115,13 @@ const SuggestionsSectionView: FC<SuggestionsSectionViewProps> = ({
<SectionContainer
// eslint-disable-next-line react/no-array-index-key
key={`${recommendation.CategoryId}-${index}`} // use a unique id return value may have duplicate id
sectionTitle={getRecommendationTittle(recommendation)}
items={(recommendation.Items as ItemDto[]) ?? []}
sectionHeaderProps={{
title: getRecommendationTittle(recommendation)
}}
itemsContainerProps={{
queryKey: ['MovieRecommendations']
}}
items={recommendation.Items as ItemDto[]}
cardOptions={{
queryKey: ['MovieRecommendations'],
shape: CardShape.PortraitOverflow,

View file

@ -1,49 +1,44 @@
import React, { type FC } from 'react';
import Box from '@mui/material/Box';
import { useGetGroupsUpcomingEpisodes } from 'hooks/useFetchItems';
import Loading from 'components/loading/LoadingComponent';
import globalize from 'lib/globalize';
import SectionContainer from './SectionContainer';
import NoItemsMessage from 'components/common/NoItemsMessage';
import SectionContainer from 'components/common/SectionContainer';
import { CardShape } from 'utils/card';
import type { LibraryViewProps } from 'types/library';
const UpcomingView: FC<LibraryViewProps> = ({ parentId }) => {
const { isLoading, data: groupsUpcomingEpisodes } = useGetGroupsUpcomingEpisodes(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: CardShape.BackdropOverflow,
showLocationTypeIndicator: false,
showParentTitle: true,
preferThumb: true,
lazy: true,
showDetailsMenu: true,
missingIndicator: false,
cardLayout: false
}}
/>
))
)}
</Box>
);
if (!groupsUpcomingEpisodes?.length) {
return <NoItemsMessage message='MessagePleaseEnsureInternetMetadata' />;
}
return groupsUpcomingEpisodes?.map((group) => (
<SectionContainer
key={group.name}
sectionHeaderProps={{
title: group.name
}}
itemsContainerProps={{
queryKey: ['GroupsUpcomingEpisodes']
}}
items={group.items}
cardOptions={{
shape: CardShape.BackdropOverflow,
showLocationTypeIndicator: false,
showParentTitle: true,
preferThumb: true,
lazy: true,
showDetailsMenu: true,
missingIndicator: false,
cardLayout: false,
queryKey: ['GroupsUpcomingEpisodes']
}}
/>
));
};
export default UpcomingView;