New: Display stats for all series in index footer

This commit is contained in:
Bogdan 2024-06-15 19:18:16 +03:00
parent d2509798e9
commit 8601f35f6e
1 changed files with 121 additions and 41 deletions

View File

@ -1,18 +1,40 @@
import classNames from 'classnames';
import React from 'react';
import React, { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import { ColorImpairedConsumer } from 'App/ColorImpairedContext';
import SeriesAppState from 'App/State/SeriesAppState';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import { Statistics } from 'Series/Series';
import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import createDeepEqualSelector from 'Store/Selectors/createDeepEqualSelector';
import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import styles from './SeriesIndexFooter.css';
function createUnoptimizedSelector() {
interface SeriesStatistics {
monitored: boolean;
status: string;
statistics: Statistics;
}
function createAllSeriesStatisticsSelector() {
return createSelector(createAllSeriesSelector(), (series) => {
return series.map((s) => {
const { monitored, status, statistics } = s;
return {
monitored,
status,
statistics,
};
});
});
}
function createUnoptimizedSeriesSelector() {
return createSelector(
createClientSideCollectionSelector('series', 'seriesIndex'),
(series: SeriesAppState) => {
@ -31,47 +53,75 @@ function createUnoptimizedSelector() {
function createSeriesSelector() {
return createDeepEqualSelector(
createUnoptimizedSelector(),
createUnoptimizedSeriesSelector(),
(series) => series
);
}
export default function SeriesIndexFooter() {
const series = useSelector(createSeriesSelector());
const count = series.length;
let episodes = 0;
let episodeFiles = 0;
let ended = 0;
let continuing = 0;
let monitored = 0;
let totalFileSize = 0;
series.forEach((s) => {
const {
statistics = { episodeCount: 0, episodeFileCount: 0, sizeOnDisk: 0 },
} = s;
function calculateSeriesStatistics(series: SeriesStatistics[]) {
return series.reduce(
(acc, s) => {
const { statistics = {} as Statistics } = s;
const {
episodeCount = 0,
episodeFileCount = 0,
sizeOnDisk = 0,
} = statistics;
episodes += episodeCount;
episodeFiles += episodeFileCount;
acc.episodes += episodeCount;
acc.episodeFiles += episodeFileCount;
acc.totalFileSize += sizeOnDisk;
if (s.status === 'ended') {
ended++;
acc.ended++;
} else {
continuing++;
acc.continuing++;
}
if (s.monitored) {
monitored++;
acc.monitored++;
}
totalFileSize += sizeOnDisk;
});
return acc;
},
{
episodes: 0,
episodeFiles: 0,
totalFileSize: 0,
ended: 0,
continuing: 0,
monitored: 0,
}
);
}
export default function SeriesIndexFooter() {
const allSeries = useSelector(createAllSeriesStatisticsSelector());
const series = useSelector(createSeriesSelector());
const allCount = allSeries.length;
const count = series.length;
const {
episodes: allEpisodes,
episodeFiles: allEpisodeFiles,
ended: allEnded,
continuing: allContinuing,
monitored: allMonitored,
totalFileSize: allTotalFileSize,
} = useMemo(() => calculateSeriesStatistics(allSeries), [allSeries]);
const {
episodes,
episodeFiles,
ended,
continuing,
monitored,
totalFileSize,
} = useMemo(() => calculateSeriesStatistics(series), [series]);
const unmonitored = count - monitored;
const allUnmonitored = allCount - allMonitored;
return (
<ColorImpairedConsumer>
@ -132,44 +182,74 @@ export default function SeriesIndexFooter() {
<div className={styles.statistics}>
<DescriptionList>
<DescriptionListItem title={translate('Series')} data={count} />
<DescriptionListItem
title={translate('Series')}
data={count === allCount ? count : `${count}/${allCount}`}
/>
<DescriptionListItem title={translate('Ended')} data={ended} />
<DescriptionListItem
title={translate('Ended')}
data={count === allCount ? ended : `${ended}/${allEnded}`}
/>
<DescriptionListItem
title={translate('Continuing')}
data={continuing}
data={
count === allCount
? continuing
: `${continuing}/${allContinuing}`
}
/>
</DescriptionList>
<DescriptionList>
<DescriptionListItem
title={translate('Monitored')}
data={monitored}
data={
count === allCount
? monitored
: `${monitored}/${allMonitored}`
}
/>
<DescriptionListItem
title={translate('Unmonitored')}
data={count - monitored}
data={
count === allCount
? unmonitored
: `${unmonitored}/${allUnmonitored}`
}
/>
</DescriptionList>
<DescriptionList>
<DescriptionListItem
title={translate('Episodes')}
data={episodes}
data={
count === allCount ? episodes : `${episodes}/${allEpisodes}`
}
/>
<DescriptionListItem
title={translate('Files')}
data={episodeFiles}
data={
count === allCount
? episodeFiles
: `${episodeFiles}/${allEpisodeFiles}`
}
/>
</DescriptionList>
<DescriptionList>
<DescriptionListItem
title={translate('TotalFileSize')}
data={formatBytes(totalFileSize)}
data={
count === allCount
? formatBytes(totalFileSize)
: `${formatBytes(totalFileSize)}/${formatBytes(
allTotalFileSize
)}`
}
/>
</DescriptionList>
</div>