diff --git a/frontend/src/Series/Index/SeriesIndexFooter.tsx b/frontend/src/Series/Index/SeriesIndexFooter.tsx index dc0a4a07f..fe3b545b9 100644 --- a/frontend/src/Series/Index/SeriesIndexFooter.tsx +++ b/frontend/src/Series/Index/SeriesIndexFooter.tsx @@ -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 ( @@ -132,44 +182,74 @@ export default function SeriesIndexFooter() {
- + - +