import classNames from 'classnames'; import React, { useCallback, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useSelect } from 'App/SelectContext'; import { REFRESH_SERIES, SERIES_SEARCH } from 'Commands/commandNames'; import CheckInput from 'Components/Form/CheckInput'; import HeartRating from 'Components/HeartRating'; import IconButton from 'Components/Link/IconButton'; import Link from 'Components/Link/Link'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector'; import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell'; import VirtualTableSelectCell from 'Components/Table/Cells/VirtualTableSelectCell'; import Column from 'Components/Table/Column'; import TagListConnector from 'Components/TagListConnector'; import { icons } from 'Helpers/Props'; import DeleteSeriesModal from 'Series/Delete/DeleteSeriesModal'; import EditSeriesModalConnector from 'Series/Edit/EditSeriesModalConnector'; import createSeriesIndexItemSelector from 'Series/Index/createSeriesIndexItemSelector'; import { Statistics } from 'Series/Series'; import SeriesBanner from 'Series/SeriesBanner'; import SeriesTitleLink from 'Series/SeriesTitleLink'; import { executeCommand } from 'Store/Actions/commandActions'; import { SelectStateInputProps } from 'typings/props'; import formatBytes from 'Utilities/Number/formatBytes'; import titleCase from 'Utilities/String/titleCase'; import SeriesIndexProgressBar from '../ProgressBar/SeriesIndexProgressBar'; import hasGrowableColumns from './hasGrowableColumns'; import SeasonsCell from './SeasonsCell'; import selectTableOptions from './selectTableOptions'; import SeriesStatusCell from './SeriesStatusCell'; import styles from './SeriesIndexRow.css'; interface SeriesIndexRowProps { seriesId: number; sortKey: string; columns: Column[]; isSelectMode: boolean; } function SeriesIndexRow(props: SeriesIndexRowProps) { const { seriesId, columns, isSelectMode } = props; const { series, qualityProfile, latestSeason, isRefreshingSeries, isSearchingSeries, } = useSelector(createSeriesIndexItemSelector(props.seriesId)); const { showBanners, showSearchAction } = useSelector(selectTableOptions); const { title, monitored, status, path, titleSlug, nextAiring, previousAiring, added, statistics = {} as Statistics, seasonFolder, images, seriesType, network, originalLanguage, certification, year, useSceneNumbering, genres = [], ratings, seasons = [], tags = [], isSaving = false, } = series; const { seasonCount = 0, episodeCount = 0, episodeFileCount = 0, totalEpisodeCount = 0, sizeOnDisk = 0, releaseGroups = [], } = statistics; const dispatch = useDispatch(); const [hasBannerError, setHasBannerError] = useState(false); const [isEditSeriesModalOpen, setIsEditSeriesModalOpen] = useState(false); const [isDeleteSeriesModalOpen, setIsDeleteSeriesModalOpen] = useState(false); const [selectState, selectDispatch] = useSelect(); const onRefreshPress = useCallback(() => { dispatch( executeCommand({ name: REFRESH_SERIES, seriesId, }) ); }, [seriesId, dispatch]); const onSearchPress = useCallback(() => { dispatch( executeCommand({ name: SERIES_SEARCH, seriesId, }) ); }, [seriesId, dispatch]); const onBannerLoadError = useCallback(() => { setHasBannerError(true); }, [setHasBannerError]); const onBannerLoad = useCallback(() => { setHasBannerError(false); }, [setHasBannerError]); const onEditSeriesPress = useCallback(() => { setIsEditSeriesModalOpen(true); }, [setIsEditSeriesModalOpen]); const onEditSeriesModalClose = useCallback(() => { setIsEditSeriesModalOpen(false); }, [setIsEditSeriesModalOpen]); const onDeleteSeriesPress = useCallback(() => { setIsEditSeriesModalOpen(false); setIsDeleteSeriesModalOpen(true); }, [setIsDeleteSeriesModalOpen]); const onDeleteSeriesModalClose = useCallback(() => { setIsDeleteSeriesModalOpen(false); }, [setIsDeleteSeriesModalOpen]); const checkInputCallback = useCallback(() => { // Mock handler to satisfy `onChange` being required for `CheckInput`. }, []); const onSelectedChange = useCallback( ({ id, value, shiftKey }: SelectStateInputProps) => { selectDispatch({ type: 'toggleSelected', id, isSelected: value, shiftKey, }); }, [selectDispatch] ); return ( <> {isSelectMode ? ( ) : null} {columns.map((column) => { const { name, isVisible } = column; if (!isVisible) { return null; } if (name === 'status') { return ( ); } if (name === 'sortTitle') { return ( {showBanners ? ( {hasBannerError && (
{title}
)} ) : ( )}
); } if (name === 'seriesType') { return ( {titleCase(seriesType)} ); } if (name === 'network') { return ( {network} ); } if (name === 'originalLanguage') { return ( {originalLanguage.name} ); } if (name === 'qualityProfileId') { return ( {qualityProfile.name} ); } if (name === 'nextAiring') { return ( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore ts(2739) ); } if (name === 'previousAiring') { return ( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore ts(2739) ); } if (name === 'added') { return ( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore ts(2739) ); } if (name === 'seasonCount') { return ( ); } if (name === 'seasonFolder') { return ( ); } if (name === 'episodeProgress') { return ( ); } if (name === 'latestSeason') { if (!latestSeason) { return ; } const seasonStatistics = latestSeason.statistics || {}; return ( ); } if (name === 'episodeCount') { return ( {totalEpisodeCount} ); } if (name === 'year') { return ( {year} ); } if (name === 'path') { return ( {path} ); } if (name === 'sizeOnDisk') { return ( {formatBytes(sizeOnDisk)} ); } if (name === 'genres') { const joinedGenres = genres.join(', '); return ( {joinedGenres} ); } if (name === 'ratings') { return ( ); } if (name === 'certification') { return ( {certification} ); } if (name === 'releaseGroups') { const joinedReleaseGroups = releaseGroups.join(', '); const truncatedReleaseGroups = releaseGroups.length > 3 ? `${releaseGroups.slice(0, 3).join(', ')}...` : joinedReleaseGroups; return ( {truncatedReleaseGroups} ); } if (name === 'tags') { return ( ); } if (name === 'useSceneNumbering') { return ( ); } if (name === 'actions') { return ( {showSearchAction ? ( ) : null} ); } return null; })} ); } export default SeriesIndexRow;