Refactor ItemCountsWidget to reduce duplication

This commit is contained in:
Bill Thornton
2025-06-25 17:37:57 -04:00
parent 3c29b1ad5d
commit e9747adf48

View File

@@ -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 (