New: Display stats for all series in index footer
This commit is contained in:
parent
d2509798e9
commit
8601f35f6e
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
function calculateSeriesStatistics(series: SeriesStatistics[]) {
|
||||
return series.reduce(
|
||||
(acc, s) => {
|
||||
const { statistics = {} as Statistics } = s;
|
||||
const {
|
||||
episodeCount = 0,
|
||||
episodeFileCount = 0,
|
||||
sizeOnDisk = 0,
|
||||
} = statistics;
|
||||
|
||||
acc.episodes += episodeCount;
|
||||
acc.episodeFiles += episodeFileCount;
|
||||
acc.totalFileSize += sizeOnDisk;
|
||||
|
||||
if (s.status === 'ended') {
|
||||
acc.ended++;
|
||||
} else {
|
||||
acc.continuing++;
|
||||
}
|
||||
|
||||
if (s.monitored) {
|
||||
acc.monitored++;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
const {
|
||||
episodes: allEpisodes,
|
||||
episodeFiles: allEpisodeFiles,
|
||||
ended: allEnded,
|
||||
continuing: allContinuing,
|
||||
monitored: allMonitored,
|
||||
totalFileSize: allTotalFileSize,
|
||||
} = useMemo(() => calculateSeriesStatistics(allSeries), [allSeries]);
|
||||
|
||||
const {
|
||||
episodeCount = 0,
|
||||
episodeFileCount = 0,
|
||||
sizeOnDisk = 0,
|
||||
} = statistics;
|
||||
const {
|
||||
episodes,
|
||||
episodeFiles,
|
||||
ended,
|
||||
continuing,
|
||||
monitored,
|
||||
totalFileSize,
|
||||
} = useMemo(() => calculateSeriesStatistics(series), [series]);
|
||||
|
||||
episodes += episodeCount;
|
||||
episodeFiles += episodeFileCount;
|
||||
|
||||
if (s.status === 'ended') {
|
||||
ended++;
|
||||
} else {
|
||||
continuing++;
|
||||
}
|
||||
|
||||
if (s.monitored) {
|
||||
monitored++;
|
||||
}
|
||||
|
||||
totalFileSize += sizeOnDisk;
|
||||
});
|
||||
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>
|
||||
|
|
Loading…
Reference in New Issue