import _ from 'lodash'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import isAfter from 'Utilities/Date/isAfter'; import isBefore from 'Utilities/Date/isBefore'; import formatBytes from 'Utilities/Number/formatBytes'; import getToggledRange from 'Utilities/Table/getToggledRange'; import { align, icons, kinds, sizes, sortDirections, tooltipPositions } from 'Helpers/Props'; import Icon from 'Components/Icon'; import IconButton from 'Components/Link/IconButton'; import Label from 'Components/Label'; import Link from 'Components/Link/Link'; import MonitorToggleButton from 'Components/MonitorToggleButton'; import SpinnerIcon from 'Components/SpinnerIcon'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import Menu from 'Components/Menu/Menu'; import MenuButton from 'Components/Menu/MenuButton'; import MenuContent from 'Components/Menu/MenuContent'; import MenuItem from 'Components/Menu/MenuItem'; import Table from 'Components/Table/Table'; import TableBody from 'Components/Table/TableBody'; import Popover from 'Components/Tooltip/Popover'; import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal'; import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector'; import SeriesHistoryModal from 'Series/History/SeriesHistoryModal'; import SeasonInteractiveSearchModalConnector from 'Series/Search/SeasonInteractiveSearchModalConnector'; import EpisodeRowConnector from './EpisodeRowConnector'; import SeasonInfo from './SeasonInfo'; import styles from './SeriesDetailsSeason.css'; function getSeasonStatistics(episodes) { let episodeCount = 0; let episodeFileCount = 0; let totalEpisodeCount = 0; let monitoredEpisodeCount = 0; let hasMonitoredEpisodes = false; const sizeOnDisk = 0; episodes.forEach((episode) => { if (episode.episodeFileId || (episode.monitored && isBefore(episode.airDateUtc))) { episodeCount++; } if (episode.episodeFileId) { episodeFileCount++; } if (episode.monitored) { monitoredEpisodeCount++; hasMonitoredEpisodes = true; } totalEpisodeCount++; }); return { episodeCount, episodeFileCount, totalEpisodeCount, monitoredEpisodeCount, hasMonitoredEpisodes, sizeOnDisk }; } function getEpisodeCountKind(monitored, episodeFileCount, episodeCount) { if (episodeFileCount === episodeCount && episodeCount > 0) { return kinds.SUCCESS; } if (!monitored) { return kinds.WARNING; } return kinds.DANGER; } class SeriesDetailsSeason extends Component { // // Lifecycle constructor(props, context) { super(props, context); this.state = { isOrganizeModalOpen: false, isManageEpisodesOpen: false, isHistoryModalOpen: false, isInteractiveSearchModalOpen: false, lastToggledEpisode: null }; } componentDidMount() { this._expandByDefault(); } componentDidUpdate(prevProps) { const { seriesId, items } = this.props; if (prevProps.seriesId !== seriesId) { this._expandByDefault(); return; } if ( getSeasonStatistics(prevProps.items).episodeFileCount > 0 && getSeasonStatistics(items).episodeFileCount === 0 ) { this.setState({ isOrganizeModalOpen: false, isManageEpisodesOpen: false }); } } // // Control _expandByDefault() { const { seasonNumber, onExpandPress, items } = this.props; const expand = _.some(items, (item) => { return isAfter(item.airDateUtc) || isAfter(item.airDateUtc, { days: -30 }); }); onExpandPress(seasonNumber, expand && seasonNumber > 0); } // // Listeners onOrganizePress = () => { this.setState({ isOrganizeModalOpen: true }); } onOrganizeModalClose = () => { this.setState({ isOrganizeModalOpen: false }); } onManageEpisodesPress = () => { this.setState({ isManageEpisodesOpen: true }); } onManageEpisodesModalClose = () => { this.setState({ isManageEpisodesOpen: false }); } onHistoryPress = () => { this.setState({ isHistoryModalOpen: true }); } onHistoryModalClose = () => { this.setState({ isHistoryModalOpen: false }); } onInteractiveSearchPress = () => { this.setState({ isInteractiveSearchModalOpen: true }); } onInteractiveSearchModalClose = () => { this.setState({ isInteractiveSearchModalOpen: false }); } onExpandPress = () => { const { seasonNumber, isExpanded } = this.props; this.props.onExpandPress(seasonNumber, !isExpanded); } onMonitorEpisodePress = (episodeId, monitored, { shiftKey }) => { const lastToggled = this.state.lastToggledEpisode; const episodeIds = [episodeId]; if (shiftKey && lastToggled) { const { lower, upper } = getToggledRange(this.props.items, episodeId, lastToggled); const items = this.props.items; for (let i = lower; i < upper; i++) { episodeIds.push(items[i].id); } } this.setState({ lastToggledEpisode: episodeId }); this.props.onMonitorEpisodePress(_.uniq(episodeIds), monitored); } // // Render render() { const { seriesId, path, monitored, seasonNumber, items, columns, statistics, isSaving, isExpanded, isSearching, seriesMonitored, isSmallScreen, onTableOptionChange, onMonitorSeasonPress, onSearchPress } = this.props; const { episodeCount, episodeFileCount, totalEpisodeCount, monitoredEpisodeCount, hasMonitoredEpisodes } = getSeasonStatistics(items); const { isOrganizeModalOpen, isManageEpisodesOpen, isHistoryModalOpen, isInteractiveSearchModalOpen } = this.state; const title = seasonNumber === 0 ? 'Specials' : `Season ${seasonNumber}`; return (
{title} {episodeFileCount} / {episodeCount} } title="Season Information" body={
} position={tooltipPositions.BOTTOM} /> { statistics.sizeOnDisk ?
{formatBytes(statistics.sizeOnDisk)}
: null }
{ !isSmallScreen &&   } { isSmallScreen ? Search Interactive Search Preview Rename Manage Episodes History :
}
{ isExpanded &&
{ items.length ? { items.map((item) => { return ( ); }) }
:
No episodes in this season
}
}
); } } SeriesDetailsSeason.propTypes = { seriesId: PropTypes.number.isRequired, path: PropTypes.string.isRequired, monitored: PropTypes.bool.isRequired, seasonNumber: PropTypes.number.isRequired, items: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired, statistics: PropTypes.object.isRequired, isSaving: PropTypes.bool, isExpanded: PropTypes.bool, isSearching: PropTypes.bool.isRequired, seriesMonitored: PropTypes.bool.isRequired, isSmallScreen: PropTypes.bool.isRequired, onTableOptionChange: PropTypes.func.isRequired, onMonitorSeasonPress: PropTypes.func.isRequired, onExpandPress: PropTypes.func.isRequired, onMonitorEpisodePress: PropTypes.func.isRequired, onSearchPress: PropTypes.func.isRequired }; SeriesDetailsSeason.defaultProps = { statistics: {} }; export default SeriesDetailsSeason;