diff --git a/src/apps/dashboard/components/widgets/ItemCountsWidget.tsx b/src/apps/dashboard/components/widgets/ItemCountsWidget.tsx index f4a5e79870..1488b5ebfe 100644 --- a/src/apps/dashboard/components/widgets/ItemCountsWidget.tsx +++ b/src/apps/dashboard/components/widgets/ItemCountsWidget.tsx @@ -1,3 +1,4 @@ +import type { ItemCounts } from '@jellyfin/sdk/lib/generated-client/models/item-counts'; import Book from '@mui/icons-material/Book'; import Movie from '@mui/icons-material/Movie'; import MusicNote from '@mui/icons-material/MusicNote'; @@ -5,12 +6,51 @@ import MusicVideo from '@mui/icons-material/MusicVideo'; import Tv from '@mui/icons-material/Tv'; import VideoLibrary from '@mui/icons-material/VideoLibrary'; import Grid from '@mui/material/Grid2'; +import SvgIcon from '@mui/material/SvgIcon'; import React, { useMemo } from 'react'; import { useItemCounts } from 'apps/dashboard/features/metrics/api/useItemCounts'; import MetricCard, { type MetricCardProps } from 'apps/dashboard/features/metrics/components/MetricCard'; import globalize from 'lib/globalize'; +interface MetricDefinition { + key: keyof ItemCounts + i18n: string +} + +interface CardDefinition { + Icon: typeof SvgIcon + metrics: MetricDefinition[] +} + +const CARD_DEFINITIONS: CardDefinition[] = [ + { + Icon: Movie, + metrics: [{ key: 'MovieCount', i18n: 'Movies' }] + }, { + Icon: Tv, + metrics: [ + { key: 'SeriesCount', i18n: 'Series' }, + { key: 'EpisodeCount', i18n: 'Episodes' } + ] + }, { + Icon: MusicNote, + metrics: [ + { key: 'AlbumCount', i18n: 'Albums' }, + { key: 'SongCount', i18n: 'Songs' } + ] + }, { + Icon: MusicVideo, + metrics: [{ key: 'MusicVideoCount', i18n: 'MusicVideos' }] + }, { + Icon: Book, + metrics: [{ key: 'BookCount', i18n: 'Books' }] + }, { + Icon: VideoLibrary, + metrics: [{ key: 'BoxSetCount', i18n: 'Collections' }] + } +]; + const ItemCountsWidget = () => { const { data: counts, @@ -18,75 +58,20 @@ const ItemCountsWidget = () => { } = useItemCounts(); const cards: MetricCardProps[] = useMemo(() => { - const cardProps: MetricCardProps[] = []; - - if (isPending || counts?.MovieCount) { - cardProps.push({ - Icon: Movie, - metrics: [{ - label: globalize.translate('Movies'), - value: counts?.MovieCount - }] - }); - } - - if (isPending || counts?.SeriesCount || counts?.EpisodeCount) { - cardProps.push({ - Icon: Tv, - metrics: [{ - label: globalize.translate('Series'), - value: counts?.SeriesCount - }, { - label: globalize.translate('Episodes'), - value: counts?.EpisodeCount - }] - }); - } - - if (isPending || counts?.AlbumCount || counts?.SongCount) { - cardProps.push({ - Icon: MusicNote, - metrics: [{ - label: globalize.translate('Albums'), - value: counts?.AlbumCount - }, { - label: globalize.translate('Songs'), - value: counts?.SongCount - }] - }); - } - - if (isPending || counts?.MusicVideoCount) { - cardProps.push({ - Icon: MusicVideo, - metrics: [{ - label: globalize.translate('MusicVideos'), - value: counts?.MusicVideoCount - }] - }); - } - - if (isPending || counts?.BookCount) { - cardProps.push({ - Icon: Book, - metrics: [{ - label: globalize.translate('Books'), - value: counts?.BookCount - }] - }); - } - - if (isPending || counts?.BoxSetCount) { - cardProps.push({ - Icon: VideoLibrary, - metrics: [{ - label: globalize.translate('Collections'), - value: counts?.BoxSetCount - }] - }); - } - - return cardProps; + return CARD_DEFINITIONS + .filter(def => ( + // Include all cards while the request is pending + isPending + // Check if the metrics are present in counts + || def.metrics.some(({ key }) => counts?.[key]) + )) + .map(({ Icon, metrics }) => ({ + Icon, + metrics: metrics.map(({ i18n, key }) => ({ + label: globalize.translate(i18n), + value: counts?.[key] + })) + })); }, [ counts, isPending ]); return (