parent
4c6d6b726e
commit
45c53bea86
@ -1,293 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import Alert from 'Components/Alert';
|
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
|
||||||
import FilterMenu from 'Components/Menu/FilterMenu';
|
|
||||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
|
||||||
import PageContent from 'Components/Page/PageContent';
|
|
||||||
import PageContentBody from 'Components/Page/PageContentBody';
|
|
||||||
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
|
||||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
|
||||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
|
||||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
|
||||||
import Table from 'Components/Table/Table';
|
|
||||||
import TableBody from 'Components/Table/TableBody';
|
|
||||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
|
||||||
import TablePager from 'Components/Table/TablePager';
|
|
||||||
import { align, icons, kinds } from 'Helpers/Props';
|
|
||||||
import getFilterValue from 'Utilities/Filter/getFilterValue';
|
|
||||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
|
||||||
import translate from 'Utilities/String/translate';
|
|
||||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
|
||||||
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
|
|
||||||
import selectAll from 'Utilities/Table/selectAll';
|
|
||||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
|
||||||
import CutoffUnmetRowConnector from './CutoffUnmetRowConnector';
|
|
||||||
|
|
||||||
function getMonitoredValue(props) {
|
|
||||||
const {
|
|
||||||
filters,
|
|
||||||
selectedFilterKey
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return getFilterValue(filters, selectedFilterKey, 'monitored', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
class CutoffUnmet extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
allSelected: false,
|
|
||||||
allUnselected: false,
|
|
||||||
lastToggled: null,
|
|
||||||
selectedState: {},
|
|
||||||
isConfirmSearchAllCutoffUnmetModalOpen: false,
|
|
||||||
isInteractiveImportModalOpen: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
if (hasDifferentItems(prevProps.items, this.props.items)) {
|
|
||||||
this.setState((state) => {
|
|
||||||
return removeOldSelectedState(state, prevProps.items);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Control
|
|
||||||
|
|
||||||
getSelectedIds = () => {
|
|
||||||
return getSelectedIds(this.state.selectedState);
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onFilterMenuItemPress = (filterKey, filterValue) => {
|
|
||||||
this.props.onFilterSelect(filterKey, filterValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
onSelectAllChange = ({ value }) => {
|
|
||||||
this.setState(selectAll(this.state.selectedState, value));
|
|
||||||
};
|
|
||||||
|
|
||||||
onSelectedChange = ({ id, value, shiftKey = false }) => {
|
|
||||||
this.setState((state) => {
|
|
||||||
return toggleSelected(state, this.props.items, id, value, shiftKey);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onSearchSelectedPress = () => {
|
|
||||||
const selected = this.getSelectedIds();
|
|
||||||
|
|
||||||
this.props.onSearchSelectedPress(selected);
|
|
||||||
};
|
|
||||||
|
|
||||||
onToggleSelectedPress = () => {
|
|
||||||
const episodeIds = this.getSelectedIds();
|
|
||||||
|
|
||||||
this.props.batchToggleCutoffUnmetEpisodes({
|
|
||||||
episodeIds,
|
|
||||||
monitored: !getMonitoredValue(this.props)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onSearchAllCutoffUnmetPress = () => {
|
|
||||||
this.setState({ isConfirmSearchAllCutoffUnmetModalOpen: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
onSearchAllCutoffUnmetConfirmed = () => {
|
|
||||||
const {
|
|
||||||
selectedFilterKey,
|
|
||||||
onSearchAllCutoffUnmetPress
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
// TODO: Custom filters will need to check whether there is a monitored
|
|
||||||
// filter once implemented.
|
|
||||||
|
|
||||||
onSearchAllCutoffUnmetPress(selectedFilterKey === 'monitored');
|
|
||||||
this.setState({ isConfirmSearchAllCutoffUnmetModalOpen: false });
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmSearchAllCutoffUnmetModalClose = () => {
|
|
||||||
this.setState({ isConfirmSearchAllCutoffUnmetModalOpen: false });
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
isFetching,
|
|
||||||
isPopulated,
|
|
||||||
error,
|
|
||||||
items,
|
|
||||||
selectedFilterKey,
|
|
||||||
filters,
|
|
||||||
columns,
|
|
||||||
totalRecords,
|
|
||||||
isSearchingForCutoffUnmetEpisodes,
|
|
||||||
isSaving,
|
|
||||||
onFilterSelect,
|
|
||||||
...otherProps
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const {
|
|
||||||
allSelected,
|
|
||||||
allUnselected,
|
|
||||||
selectedState,
|
|
||||||
isConfirmSearchAllCutoffUnmetModalOpen
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const itemsSelected = !!this.getSelectedIds().length;
|
|
||||||
const isShowingMonitored = getMonitoredValue(this.props);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContent title={translate('CutoffUnmet')}>
|
|
||||||
<PageToolbar>
|
|
||||||
<PageToolbarSection>
|
|
||||||
<PageToolbarButton
|
|
||||||
label={itemsSelected ? translate('SearchSelected') : translate('SearchAll')}
|
|
||||||
iconName={icons.SEARCH}
|
|
||||||
isDisabled={isSearchingForCutoffUnmetEpisodes}
|
|
||||||
isSpinning={isSearchingForCutoffUnmetEpisodes}
|
|
||||||
onPress={itemsSelected ? this.onSearchSelectedPress : this.onSearchAllCutoffUnmetPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<PageToolbarSeparator />
|
|
||||||
|
|
||||||
<PageToolbarButton
|
|
||||||
label={isShowingMonitored ? translate('UnmonitorSelected') : translate('MonitorSelected')}
|
|
||||||
iconName={icons.MONITORED}
|
|
||||||
isDisabled={!itemsSelected}
|
|
||||||
isSpinning={isSaving}
|
|
||||||
onPress={this.onToggleSelectedPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</PageToolbarSection>
|
|
||||||
|
|
||||||
<PageToolbarSection alignContent={align.RIGHT}>
|
|
||||||
<TableOptionsModalWrapper
|
|
||||||
{...otherProps}
|
|
||||||
columns={columns}
|
|
||||||
>
|
|
||||||
<PageToolbarButton
|
|
||||||
label={translate('Options')}
|
|
||||||
iconName={icons.TABLE}
|
|
||||||
/>
|
|
||||||
</TableOptionsModalWrapper>
|
|
||||||
|
|
||||||
<FilterMenu
|
|
||||||
alignMenu={align.RIGHT}
|
|
||||||
selectedFilterKey={selectedFilterKey}
|
|
||||||
filters={filters}
|
|
||||||
customFilters={[]}
|
|
||||||
onFilterSelect={onFilterSelect}
|
|
||||||
/>
|
|
||||||
</PageToolbarSection>
|
|
||||||
</PageToolbar>
|
|
||||||
|
|
||||||
<PageContentBody>
|
|
||||||
{
|
|
||||||
isFetching && !isPopulated &&
|
|
||||||
<LoadingIndicator />
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
!isFetching && error &&
|
|
||||||
<Alert kind={kinds.DANGER}>
|
|
||||||
{translate('CutoffUnmetLoadError')}
|
|
||||||
</Alert>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
isPopulated && !error && !items.length &&
|
|
||||||
<Alert kind={kinds.INFO}>
|
|
||||||
{translate('CutoffUnmetNoItems')}
|
|
||||||
</Alert>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
isPopulated && !error && !!items.length &&
|
|
||||||
<div>
|
|
||||||
<Table
|
|
||||||
columns={columns}
|
|
||||||
selectAll={true}
|
|
||||||
allSelected={allSelected}
|
|
||||||
allUnselected={allUnselected}
|
|
||||||
{...otherProps}
|
|
||||||
onSelectAllChange={this.onSelectAllChange}
|
|
||||||
>
|
|
||||||
<TableBody>
|
|
||||||
{
|
|
||||||
items.map((item) => {
|
|
||||||
return (
|
|
||||||
<CutoffUnmetRowConnector
|
|
||||||
key={item.id}
|
|
||||||
isSelected={selectedState[item.id]}
|
|
||||||
columns={columns}
|
|
||||||
{...item}
|
|
||||||
onSelectedChange={this.onSelectedChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
|
|
||||||
<TablePager
|
|
||||||
totalRecords={totalRecords}
|
|
||||||
isFetching={isFetching}
|
|
||||||
{...otherProps}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ConfirmModal
|
|
||||||
isOpen={isConfirmSearchAllCutoffUnmetModalOpen}
|
|
||||||
kind={kinds.DANGER}
|
|
||||||
title={translate('SearchForCutoffUnmetEpisodes')}
|
|
||||||
message={
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
{translate('SearchForCutoffUnmetEpisodesConfirmationCount', { totalRecords })}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{translate('MassSearchCancelWarning')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
confirmLabel={translate('Search')}
|
|
||||||
onConfirm={this.onSearchAllCutoffUnmetConfirmed}
|
|
||||||
onCancel={this.onConfirmSearchAllCutoffUnmetModalClose}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</PageContentBody>
|
|
||||||
</PageContent>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CutoffUnmet.propTypes = {
|
|
||||||
isFetching: PropTypes.bool.isRequired,
|
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
|
||||||
error: PropTypes.object,
|
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
selectedFilterKey: PropTypes.string.isRequired,
|
|
||||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
totalRecords: PropTypes.number,
|
|
||||||
isSearchingForCutoffUnmetEpisodes: PropTypes.bool.isRequired,
|
|
||||||
isSaving: PropTypes.bool.isRequired,
|
|
||||||
onFilterSelect: PropTypes.func.isRequired,
|
|
||||||
onSearchSelectedPress: PropTypes.func.isRequired,
|
|
||||||
batchToggleCutoffUnmetEpisodes: PropTypes.func.isRequired,
|
|
||||||
onSearchAllCutoffUnmetPress: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CutoffUnmet;
|
|
@ -0,0 +1,355 @@
|
|||||||
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import AppState, { Filter } from 'App/State/AppState';
|
||||||
|
import * as commandNames from 'Commands/commandNames';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
|
import FilterMenu from 'Components/Menu/FilterMenu';
|
||||||
|
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||||
|
import PageContent from 'Components/Page/PageContent';
|
||||||
|
import PageContentBody from 'Components/Page/PageContentBody';
|
||||||
|
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||||
|
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||||
|
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||||
|
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||||
|
import Table from 'Components/Table/Table';
|
||||||
|
import TableBody from 'Components/Table/TableBody';
|
||||||
|
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||||
|
import TablePager from 'Components/Table/TablePager';
|
||||||
|
import usePaging from 'Components/Table/usePaging';
|
||||||
|
import useCurrentPage from 'Helpers/Hooks/useCurrentPage';
|
||||||
|
import useSelectState from 'Helpers/Hooks/useSelectState';
|
||||||
|
import { align, icons, kinds } from 'Helpers/Props';
|
||||||
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
|
import {
|
||||||
|
batchToggleCutoffUnmetEpisodes,
|
||||||
|
clearCutoffUnmet,
|
||||||
|
fetchCutoffUnmet,
|
||||||
|
gotoCutoffUnmetPage,
|
||||||
|
setCutoffUnmetFilter,
|
||||||
|
setCutoffUnmetSort,
|
||||||
|
setCutoffUnmetTableOption,
|
||||||
|
} from 'Store/Actions/wantedActions';
|
||||||
|
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||||
|
import { CheckInputChanged } from 'typings/inputs';
|
||||||
|
import { SelectStateInputProps } from 'typings/props';
|
||||||
|
import { TableOptionsChangePayload } from 'typings/Table';
|
||||||
|
import getFilterValue from 'Utilities/Filter/getFilterValue';
|
||||||
|
import {
|
||||||
|
registerPagePopulator,
|
||||||
|
unregisterPagePopulator,
|
||||||
|
} from 'Utilities/pagePopulator';
|
||||||
|
import translate from 'Utilities/String/translate';
|
||||||
|
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||||
|
import CutoffUnmetRow from './CutoffUnmetRow';
|
||||||
|
|
||||||
|
function getMonitoredValue(
|
||||||
|
filters: Filter[],
|
||||||
|
selectedFilterKey: string
|
||||||
|
): boolean {
|
||||||
|
return !!getFilterValue(filters, selectedFilterKey, 'monitored', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CutoffUnmet() {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const requestCurrentPage = useCurrentPage();
|
||||||
|
|
||||||
|
const {
|
||||||
|
isFetching,
|
||||||
|
isPopulated,
|
||||||
|
error,
|
||||||
|
items,
|
||||||
|
columns,
|
||||||
|
selectedFilterKey,
|
||||||
|
filters,
|
||||||
|
sortKey,
|
||||||
|
sortDirection,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
totalPages,
|
||||||
|
totalRecords = 0,
|
||||||
|
} = useSelector((state: AppState) => state.wanted.cutoffUnmet);
|
||||||
|
|
||||||
|
const isSearchingForAllEpisodes = useSelector(
|
||||||
|
createCommandExecutingSelector(commandNames.CUTOFF_UNMET_EPISODE_SEARCH)
|
||||||
|
);
|
||||||
|
const isSearchingForSelectedEpisodes = useSelector(
|
||||||
|
createCommandExecutingSelector(commandNames.EPISODE_SEARCH)
|
||||||
|
);
|
||||||
|
|
||||||
|
const [selectState, setSelectState] = useSelectState();
|
||||||
|
const { allSelected, allUnselected, selectedState } = selectState;
|
||||||
|
|
||||||
|
const [isConfirmSearchAllModalOpen, setIsConfirmSearchAllModalOpen] =
|
||||||
|
useState(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
handleFirstPagePress,
|
||||||
|
handlePreviousPagePress,
|
||||||
|
handleNextPagePress,
|
||||||
|
handleLastPagePress,
|
||||||
|
handlePageSelect,
|
||||||
|
} = usePaging({
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
gotoPage: gotoCutoffUnmetPage,
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedIds = useMemo(() => {
|
||||||
|
return getSelectedIds(selectedState);
|
||||||
|
}, [selectedState]);
|
||||||
|
|
||||||
|
const isSaving = useMemo(() => {
|
||||||
|
return items.filter((m) => m.isSaving).length > 1;
|
||||||
|
}, [items]);
|
||||||
|
|
||||||
|
const itemsSelected = !!selectedIds.length;
|
||||||
|
const isShowingMonitored = getMonitoredValue(filters, selectedFilterKey);
|
||||||
|
const isSearchingForEpisodes =
|
||||||
|
isSearchingForAllEpisodes || isSearchingForSelectedEpisodes;
|
||||||
|
|
||||||
|
const handleSelectAllChange = useCallback(
|
||||||
|
({ value }: CheckInputChanged) => {
|
||||||
|
setSelectState({ type: value ? 'selectAll' : 'unselectAll', items });
|
||||||
|
},
|
||||||
|
[items, setSelectState]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSelectedChange = useCallback(
|
||||||
|
({ id, value, shiftKey = false }: SelectStateInputProps) => {
|
||||||
|
setSelectState({
|
||||||
|
type: 'toggleSelected',
|
||||||
|
items,
|
||||||
|
id,
|
||||||
|
isSelected: value,
|
||||||
|
shiftKey,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[items, setSelectState]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSearchSelectedPress = useCallback(() => {
|
||||||
|
dispatch(
|
||||||
|
executeCommand({
|
||||||
|
name: commandNames.EPISODE_SEARCH,
|
||||||
|
episodeIds: selectedIds,
|
||||||
|
commandFinished: () => {
|
||||||
|
dispatch(fetchCutoffUnmet());
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}, [selectedIds, dispatch]);
|
||||||
|
|
||||||
|
const handleSearchAllPress = useCallback(() => {
|
||||||
|
setIsConfirmSearchAllModalOpen(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleConfirmSearchAllCutoffUnmetModalClose = useCallback(() => {
|
||||||
|
setIsConfirmSearchAllModalOpen(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleSearchAllCutoffUnmetConfirmed = useCallback(() => {
|
||||||
|
dispatch(
|
||||||
|
executeCommand({
|
||||||
|
name: commandNames.CUTOFF_UNMET_EPISODE_SEARCH,
|
||||||
|
commandFinished: () => {
|
||||||
|
dispatch(fetchCutoffUnmet());
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
setIsConfirmSearchAllModalOpen(false);
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
const handleToggleSelectedPress = useCallback(() => {
|
||||||
|
dispatch(
|
||||||
|
batchToggleCutoffUnmetEpisodes({
|
||||||
|
episodeIds: selectedIds,
|
||||||
|
monitored: !isShowingMonitored,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}, [isShowingMonitored, selectedIds, dispatch]);
|
||||||
|
|
||||||
|
const handleFilterSelect = useCallback(
|
||||||
|
(filterKey: number | string) => {
|
||||||
|
dispatch(setCutoffUnmetFilter({ selectedFilterKey: filterKey }));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSortPress = useCallback(
|
||||||
|
(sortKey: string) => {
|
||||||
|
dispatch(setCutoffUnmetSort({ sortKey }));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTableOptionChange = useCallback(
|
||||||
|
(payload: TableOptionsChangePayload) => {
|
||||||
|
dispatch(setCutoffUnmetTableOption(payload));
|
||||||
|
|
||||||
|
if (payload.pageSize) {
|
||||||
|
dispatch(gotoCutoffUnmetPage({ page: 1 }));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (requestCurrentPage) {
|
||||||
|
dispatch(fetchCutoffUnmet());
|
||||||
|
} else {
|
||||||
|
dispatch(gotoCutoffUnmetPage({ page: 1 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
dispatch(clearCutoffUnmet());
|
||||||
|
};
|
||||||
|
}, [requestCurrentPage, dispatch]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const repopulate = () => {
|
||||||
|
dispatch(fetchCutoffUnmet());
|
||||||
|
};
|
||||||
|
|
||||||
|
registerPagePopulator(repopulate);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unregisterPagePopulator(repopulate);
|
||||||
|
};
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContent title={translate('CutoffUnmet')}>
|
||||||
|
<PageToolbar>
|
||||||
|
<PageToolbarSection>
|
||||||
|
<PageToolbarButton
|
||||||
|
label={
|
||||||
|
itemsSelected
|
||||||
|
? translate('SearchSelected')
|
||||||
|
: translate('SearchAll')
|
||||||
|
}
|
||||||
|
iconName={icons.SEARCH}
|
||||||
|
isDisabled={isSearchingForEpisodes}
|
||||||
|
isSpinning={isSearchingForEpisodes}
|
||||||
|
onPress={
|
||||||
|
itemsSelected ? handleSearchSelectedPress : handleSearchAllPress
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<PageToolbarSeparator />
|
||||||
|
|
||||||
|
<PageToolbarButton
|
||||||
|
label={
|
||||||
|
isShowingMonitored
|
||||||
|
? translate('UnmonitorSelected')
|
||||||
|
: translate('MonitorSelected')
|
||||||
|
}
|
||||||
|
iconName={icons.MONITORED}
|
||||||
|
isDisabled={!itemsSelected}
|
||||||
|
isSpinning={isSaving}
|
||||||
|
onPress={handleToggleSelectedPress}
|
||||||
|
/>
|
||||||
|
</PageToolbarSection>
|
||||||
|
|
||||||
|
<PageToolbarSection alignContent={align.RIGHT}>
|
||||||
|
<TableOptionsModalWrapper
|
||||||
|
columns={columns}
|
||||||
|
pageSize={pageSize}
|
||||||
|
onTableOptionChange={handleTableOptionChange}
|
||||||
|
>
|
||||||
|
<PageToolbarButton
|
||||||
|
label={translate('Options')}
|
||||||
|
iconName={icons.TABLE}
|
||||||
|
/>
|
||||||
|
</TableOptionsModalWrapper>
|
||||||
|
|
||||||
|
<FilterMenu
|
||||||
|
alignMenu={align.RIGHT}
|
||||||
|
selectedFilterKey={selectedFilterKey}
|
||||||
|
filters={filters}
|
||||||
|
customFilters={[]}
|
||||||
|
onFilterSelect={handleFilterSelect}
|
||||||
|
/>
|
||||||
|
</PageToolbarSection>
|
||||||
|
</PageToolbar>
|
||||||
|
|
||||||
|
<PageContentBody>
|
||||||
|
{isFetching && !isPopulated ? <LoadingIndicator /> : null}
|
||||||
|
|
||||||
|
{!isFetching && error ? (
|
||||||
|
<Alert kind={kinds.DANGER}>{translate('CutoffUnmetLoadError')}</Alert>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{isPopulated && !error && !items.length ? (
|
||||||
|
<Alert kind={kinds.INFO}>{translate('CutoffUnmetNoItems')}</Alert>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{isPopulated && !error && !!items.length ? (
|
||||||
|
<div>
|
||||||
|
<Table
|
||||||
|
selectAll={true}
|
||||||
|
allSelected={allSelected}
|
||||||
|
allUnselected={allUnselected}
|
||||||
|
columns={columns}
|
||||||
|
pageSize={pageSize}
|
||||||
|
sortKey={sortKey}
|
||||||
|
sortDirection={sortDirection}
|
||||||
|
onTableOptionChange={handleTableOptionChange}
|
||||||
|
onSelectAllChange={handleSelectAllChange}
|
||||||
|
onSortPress={handleSortPress}
|
||||||
|
>
|
||||||
|
<TableBody>
|
||||||
|
{items.map((item) => {
|
||||||
|
return (
|
||||||
|
<CutoffUnmetRow
|
||||||
|
key={item.id}
|
||||||
|
isSelected={selectedState[item.id]}
|
||||||
|
columns={columns}
|
||||||
|
{...item}
|
||||||
|
onSelectedChange={handleSelectedChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
|
||||||
|
<TablePager
|
||||||
|
page={page}
|
||||||
|
totalPages={totalPages}
|
||||||
|
totalRecords={totalRecords}
|
||||||
|
isFetching={isFetching}
|
||||||
|
onFirstPagePress={handleFirstPagePress}
|
||||||
|
onPreviousPagePress={handlePreviousPagePress}
|
||||||
|
onNextPagePress={handleNextPagePress}
|
||||||
|
onLastPagePress={handleLastPagePress}
|
||||||
|
onPageSelect={handlePageSelect}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ConfirmModal
|
||||||
|
isOpen={isConfirmSearchAllModalOpen}
|
||||||
|
kind={kinds.DANGER}
|
||||||
|
title={translate('SearchForCutoffUnmetEpisodes')}
|
||||||
|
message={
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
{translate(
|
||||||
|
'SearchForCutoffUnmetEpisodesConfirmationCount',
|
||||||
|
{ totalRecords }
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>{translate('MassSearchCancelWarning')}</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
confirmLabel={translate('Search')}
|
||||||
|
onConfirm={handleSearchAllCutoffUnmetConfirmed}
|
||||||
|
onCancel={handleConfirmSearchAllCutoffUnmetModalClose}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</PageContentBody>
|
||||||
|
</PageContent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CutoffUnmet;
|
@ -1,188 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import * as commandNames from 'Commands/commandNames';
|
|
||||||
import withCurrentPage from 'Components/withCurrentPage';
|
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
|
||||||
import { clearEpisodeFiles, fetchEpisodeFiles } from 'Store/Actions/episodeFileActions';
|
|
||||||
import { clearQueueDetails, fetchQueueDetails } from 'Store/Actions/queueActions';
|
|
||||||
import * as wantedActions from 'Store/Actions/wantedActions';
|
|
||||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
|
||||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
|
||||||
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
|
|
||||||
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
|
||||||
import CutoffUnmet from './CutoffUnmet';
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
(state) => state.wanted.cutoffUnmet,
|
|
||||||
createCommandExecutingSelector(commandNames.CUTOFF_UNMET_EPISODE_SEARCH),
|
|
||||||
createCommandExecutingSelector(commandNames.EPISODE_SEARCH),
|
|
||||||
(cutoffUnmet, isSearchingForAllCutoffUnmetEpisodes, isSearchingForSelectedCutoffUnmetEpisodes) => {
|
|
||||||
return {
|
|
||||||
isSearchingForCutoffUnmetEpisodes: isSearchingForAllCutoffUnmetEpisodes || isSearchingForSelectedCutoffUnmetEpisodes,
|
|
||||||
isSaving: cutoffUnmet.items.filter((m) => m.isSaving).length > 1,
|
|
||||||
...cutoffUnmet
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
...wantedActions,
|
|
||||||
executeCommand,
|
|
||||||
fetchQueueDetails,
|
|
||||||
clearQueueDetails,
|
|
||||||
fetchEpisodeFiles,
|
|
||||||
clearEpisodeFiles
|
|
||||||
};
|
|
||||||
|
|
||||||
class CutoffUnmetConnector extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const {
|
|
||||||
useCurrentPage,
|
|
||||||
fetchCutoffUnmet,
|
|
||||||
gotoCutoffUnmetFirstPage
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
registerPagePopulator(this.repopulate, ['seriesUpdated', 'episodeFileUpdated', 'episodeFileDeleted']);
|
|
||||||
|
|
||||||
if (useCurrentPage) {
|
|
||||||
fetchCutoffUnmet();
|
|
||||||
} else {
|
|
||||||
gotoCutoffUnmetFirstPage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
if (hasDifferentItems(prevProps.items, this.props.items)) {
|
|
||||||
const episodeIds = selectUniqueIds(this.props.items, 'id');
|
|
||||||
const episodeFileIds = selectUniqueIds(this.props.items, 'episodeFileId');
|
|
||||||
|
|
||||||
this.props.fetchQueueDetails({ episodeIds });
|
|
||||||
|
|
||||||
if (episodeFileIds.length) {
|
|
||||||
this.props.fetchEpisodeFiles({ episodeFileIds });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
unregisterPagePopulator(this.repopulate);
|
|
||||||
this.props.clearCutoffUnmet();
|
|
||||||
this.props.clearQueueDetails();
|
|
||||||
this.props.clearEpisodeFiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Control
|
|
||||||
|
|
||||||
repopulate = () => {
|
|
||||||
this.props.fetchCutoffUnmet();
|
|
||||||
};
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onFirstPagePress = () => {
|
|
||||||
this.props.gotoCutoffUnmetFirstPage();
|
|
||||||
};
|
|
||||||
|
|
||||||
onPreviousPagePress = () => {
|
|
||||||
this.props.gotoCutoffUnmetPreviousPage();
|
|
||||||
};
|
|
||||||
|
|
||||||
onNextPagePress = () => {
|
|
||||||
this.props.gotoCutoffUnmetNextPage();
|
|
||||||
};
|
|
||||||
|
|
||||||
onLastPagePress = () => {
|
|
||||||
this.props.gotoCutoffUnmetLastPage();
|
|
||||||
};
|
|
||||||
|
|
||||||
onPageSelect = (page) => {
|
|
||||||
this.props.gotoCutoffUnmetPage({ page });
|
|
||||||
};
|
|
||||||
|
|
||||||
onSortPress = (sortKey) => {
|
|
||||||
this.props.setCutoffUnmetSort({ sortKey });
|
|
||||||
};
|
|
||||||
|
|
||||||
onFilterSelect = (selectedFilterKey) => {
|
|
||||||
this.props.setCutoffUnmetFilter({ selectedFilterKey });
|
|
||||||
};
|
|
||||||
|
|
||||||
onTableOptionChange = (payload) => {
|
|
||||||
this.props.setCutoffUnmetTableOption(payload);
|
|
||||||
|
|
||||||
if (payload.pageSize) {
|
|
||||||
this.props.gotoCutoffUnmetFirstPage();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onSearchSelectedPress = (selected) => {
|
|
||||||
this.props.executeCommand({
|
|
||||||
name: commandNames.EPISODE_SEARCH,
|
|
||||||
episodeIds: selected,
|
|
||||||
commandFinished: this.repopulate
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onSearchAllCutoffUnmetPress = (monitored) => {
|
|
||||||
this.props.executeCommand({
|
|
||||||
name: commandNames.CUTOFF_UNMET_EPISODE_SEARCH,
|
|
||||||
monitored,
|
|
||||||
commandFinished: this.repopulate
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<CutoffUnmet
|
|
||||||
onFirstPagePress={this.onFirstPagePress}
|
|
||||||
onPreviousPagePress={this.onPreviousPagePress}
|
|
||||||
onNextPagePress={this.onNextPagePress}
|
|
||||||
onLastPagePress={this.onLastPagePress}
|
|
||||||
onPageSelect={this.onPageSelect}
|
|
||||||
onSortPress={this.onSortPress}
|
|
||||||
onFilterSelect={this.onFilterSelect}
|
|
||||||
onTableOptionChange={this.onTableOptionChange}
|
|
||||||
onSearchSelectedPress={this.onSearchSelectedPress}
|
|
||||||
onToggleSelectedPress={this.onToggleSelectedPress}
|
|
||||||
onSearchAllCutoffUnmetPress={this.onSearchAllCutoffUnmetPress}
|
|
||||||
{...this.props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CutoffUnmetConnector.propTypes = {
|
|
||||||
useCurrentPage: PropTypes.bool.isRequired,
|
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
fetchCutoffUnmet: PropTypes.func.isRequired,
|
|
||||||
gotoCutoffUnmetFirstPage: PropTypes.func.isRequired,
|
|
||||||
gotoCutoffUnmetPreviousPage: PropTypes.func.isRequired,
|
|
||||||
gotoCutoffUnmetNextPage: PropTypes.func.isRequired,
|
|
||||||
gotoCutoffUnmetLastPage: PropTypes.func.isRequired,
|
|
||||||
gotoCutoffUnmetPage: PropTypes.func.isRequired,
|
|
||||||
setCutoffUnmetSort: PropTypes.func.isRequired,
|
|
||||||
setCutoffUnmetFilter: PropTypes.func.isRequired,
|
|
||||||
setCutoffUnmetTableOption: PropTypes.func.isRequired,
|
|
||||||
clearCutoffUnmet: PropTypes.func.isRequired,
|
|
||||||
executeCommand: PropTypes.func.isRequired,
|
|
||||||
fetchQueueDetails: PropTypes.func.isRequired,
|
|
||||||
clearQueueDetails: PropTypes.func.isRequired,
|
|
||||||
fetchEpisodeFiles: PropTypes.func.isRequired,
|
|
||||||
clearEpisodeFiles: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withCurrentPage(
|
|
||||||
connect(createMapStateToProps, mapDispatchToProps)(CutoffUnmetConnector)
|
|
||||||
);
|
|
@ -1,187 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import RelativeDateCell from 'Components/Table/Cells/RelativeDateCell';
|
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
|
||||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
|
||||||
import TableRow from 'Components/Table/TableRow';
|
|
||||||
import episodeEntities from 'Episode/episodeEntities';
|
|
||||||
import EpisodeSearchCell from 'Episode/EpisodeSearchCell';
|
|
||||||
import EpisodeStatus from 'Episode/EpisodeStatus';
|
|
||||||
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
|
||||||
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
|
|
||||||
import EpisodeFileLanguages from 'EpisodeFile/EpisodeFileLanguages';
|
|
||||||
import SeriesTitleLink from 'Series/SeriesTitleLink';
|
|
||||||
import styles from './CutoffUnmetRow.css';
|
|
||||||
|
|
||||||
function CutoffUnmetRow(props) {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
episodeFileId,
|
|
||||||
series,
|
|
||||||
seasonNumber,
|
|
||||||
episodeNumber,
|
|
||||||
absoluteEpisodeNumber,
|
|
||||||
sceneSeasonNumber,
|
|
||||||
sceneEpisodeNumber,
|
|
||||||
sceneAbsoluteEpisodeNumber,
|
|
||||||
unverifiedSceneNumbering,
|
|
||||||
airDateUtc,
|
|
||||||
lastSearchTime,
|
|
||||||
title,
|
|
||||||
isSelected,
|
|
||||||
columns,
|
|
||||||
onSelectedChange
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableRow>
|
|
||||||
<TableSelectCell
|
|
||||||
id={id}
|
|
||||||
isSelected={isSelected}
|
|
||||||
onSelectedChange={onSelectedChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{
|
|
||||||
columns.map((column) => {
|
|
||||||
const {
|
|
||||||
name,
|
|
||||||
isVisible
|
|
||||||
} = column;
|
|
||||||
|
|
||||||
if (!isVisible) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'series.sortTitle') {
|
|
||||||
return (
|
|
||||||
<TableRowCell key={name}>
|
|
||||||
<SeriesTitleLink
|
|
||||||
titleSlug={series.titleSlug}
|
|
||||||
title={series.title}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'episode') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.episode}
|
|
||||||
>
|
|
||||||
<SeasonEpisodeNumber
|
|
||||||
seasonNumber={seasonNumber}
|
|
||||||
episodeNumber={episodeNumber}
|
|
||||||
absoluteEpisodeNumber={absoluteEpisodeNumber}
|
|
||||||
seriesType={series.seriesType}
|
|
||||||
alternateTitles={series.alternateTitles}
|
|
||||||
sceneSeasonNumber={sceneSeasonNumber}
|
|
||||||
sceneEpisodeNumber={sceneEpisodeNumber}
|
|
||||||
sceneAbsoluteEpisodeNumber={sceneAbsoluteEpisodeNumber}
|
|
||||||
unverifiedSceneNumbering={unverifiedSceneNumbering}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'episodes.title') {
|
|
||||||
return (
|
|
||||||
<TableRowCell key={name}>
|
|
||||||
<EpisodeTitleLink
|
|
||||||
episodeId={id}
|
|
||||||
seriesId={series.id}
|
|
||||||
episodeEntity={episodeEntities.WANTED_CUTOFF_UNMET}
|
|
||||||
episodeTitle={title}
|
|
||||||
showOpenSeriesButton={true}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'episodes.airDateUtc') {
|
|
||||||
return (
|
|
||||||
<RelativeDateCell
|
|
||||||
key={name}
|
|
||||||
date={airDateUtc}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'episodes.lastSearchTime') {
|
|
||||||
return (
|
|
||||||
<RelativeDateCell
|
|
||||||
key={name}
|
|
||||||
date={lastSearchTime}
|
|
||||||
includeSeconds={true}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'languages') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.languages}
|
|
||||||
>
|
|
||||||
<EpisodeFileLanguages
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'status') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.status}
|
|
||||||
>
|
|
||||||
<EpisodeStatus
|
|
||||||
episodeId={id}
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
episodeEntity={episodeEntities.WANTED_CUTOFF_UNMET}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'actions') {
|
|
||||||
return (
|
|
||||||
<EpisodeSearchCell
|
|
||||||
key={name}
|
|
||||||
episodeId={id}
|
|
||||||
seriesId={series.id}
|
|
||||||
episodeTitle={title}
|
|
||||||
episodeEntity={episodeEntities.WANTED_CUTOFF_UNMET}
|
|
||||||
showOpenSeriesButton={true}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
CutoffUnmetRow.propTypes = {
|
|
||||||
id: PropTypes.number.isRequired,
|
|
||||||
episodeFileId: PropTypes.number,
|
|
||||||
series: PropTypes.object.isRequired,
|
|
||||||
seasonNumber: PropTypes.number.isRequired,
|
|
||||||
episodeNumber: PropTypes.number.isRequired,
|
|
||||||
absoluteEpisodeNumber: PropTypes.number,
|
|
||||||
sceneSeasonNumber: PropTypes.number,
|
|
||||||
sceneEpisodeNumber: PropTypes.number,
|
|
||||||
sceneAbsoluteEpisodeNumber: PropTypes.number,
|
|
||||||
unverifiedSceneNumbering: PropTypes.bool.isRequired,
|
|
||||||
airDateUtc: PropTypes.string.isRequired,
|
|
||||||
lastSearchTime: PropTypes.string,
|
|
||||||
title: PropTypes.string.isRequired,
|
|
||||||
isSelected: PropTypes.bool,
|
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
onSelectedChange: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CutoffUnmetRow;
|
|
@ -0,0 +1,171 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import RelativeDateCell from 'Components/Table/Cells/RelativeDateCell';
|
||||||
|
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||||
|
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||||
|
import Column from 'Components/Table/Column';
|
||||||
|
import TableRow from 'Components/Table/TableRow';
|
||||||
|
import EpisodeSearchCell from 'Episode/EpisodeSearchCell';
|
||||||
|
import EpisodeStatus from 'Episode/EpisodeStatus';
|
||||||
|
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
||||||
|
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
|
||||||
|
import EpisodeFileLanguages from 'EpisodeFile/EpisodeFileLanguages';
|
||||||
|
import SeriesTitleLink from 'Series/SeriesTitleLink';
|
||||||
|
import useSeries from 'Series/useSeries';
|
||||||
|
import { SelectStateInputProps } from 'typings/props';
|
||||||
|
import styles from './CutoffUnmetRow.css';
|
||||||
|
|
||||||
|
interface CutoffUnmetRowProps {
|
||||||
|
id: number;
|
||||||
|
seriesId: number;
|
||||||
|
episodeFileId?: number;
|
||||||
|
seasonNumber: number;
|
||||||
|
episodeNumber: number;
|
||||||
|
absoluteEpisodeNumber?: number;
|
||||||
|
sceneSeasonNumber?: number;
|
||||||
|
sceneEpisodeNumber?: number;
|
||||||
|
sceneAbsoluteEpisodeNumber?: number;
|
||||||
|
unverifiedSceneNumbering: boolean;
|
||||||
|
airDateUtc?: string;
|
||||||
|
lastSearchTime?: string;
|
||||||
|
title: string;
|
||||||
|
isSelected?: boolean;
|
||||||
|
columns: Column[];
|
||||||
|
onSelectedChange: (options: SelectStateInputProps) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CutoffUnmetRow({
|
||||||
|
id,
|
||||||
|
seriesId,
|
||||||
|
episodeFileId,
|
||||||
|
seasonNumber,
|
||||||
|
episodeNumber,
|
||||||
|
absoluteEpisodeNumber,
|
||||||
|
sceneSeasonNumber,
|
||||||
|
sceneEpisodeNumber,
|
||||||
|
sceneAbsoluteEpisodeNumber,
|
||||||
|
unverifiedSceneNumbering,
|
||||||
|
airDateUtc,
|
||||||
|
lastSearchTime,
|
||||||
|
title,
|
||||||
|
isSelected,
|
||||||
|
columns,
|
||||||
|
onSelectedChange,
|
||||||
|
}: CutoffUnmetRowProps) {
|
||||||
|
const series = useSeries(seriesId);
|
||||||
|
|
||||||
|
if (!series || !episodeFileId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
<TableSelectCell
|
||||||
|
id={id}
|
||||||
|
isSelected={isSelected}
|
||||||
|
onSelectedChange={onSelectedChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{columns.map((column) => {
|
||||||
|
const { name, isVisible } = column;
|
||||||
|
|
||||||
|
if (!isVisible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'series.sortTitle') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name}>
|
||||||
|
<SeriesTitleLink
|
||||||
|
titleSlug={series.titleSlug}
|
||||||
|
title={series.title}
|
||||||
|
/>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'episode') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name} className={styles.episode}>
|
||||||
|
<SeasonEpisodeNumber
|
||||||
|
seasonNumber={seasonNumber}
|
||||||
|
episodeNumber={episodeNumber}
|
||||||
|
absoluteEpisodeNumber={absoluteEpisodeNumber}
|
||||||
|
seriesType={series.seriesType}
|
||||||
|
alternateTitles={series.alternateTitles}
|
||||||
|
sceneSeasonNumber={sceneSeasonNumber}
|
||||||
|
sceneEpisodeNumber={sceneEpisodeNumber}
|
||||||
|
sceneAbsoluteEpisodeNumber={sceneAbsoluteEpisodeNumber}
|
||||||
|
unverifiedSceneNumbering={unverifiedSceneNumbering}
|
||||||
|
/>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'episodes.title') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name}>
|
||||||
|
<EpisodeTitleLink
|
||||||
|
episodeId={id}
|
||||||
|
seriesId={series.id}
|
||||||
|
episodeEntity="wanted.cutoffUnmet"
|
||||||
|
episodeTitle={title}
|
||||||
|
showOpenSeriesButton={true}
|
||||||
|
/>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'episodes.airDateUtc') {
|
||||||
|
return <RelativeDateCell key={name} date={airDateUtc} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'episodes.lastSearchTime') {
|
||||||
|
return (
|
||||||
|
<RelativeDateCell
|
||||||
|
key={name}
|
||||||
|
date={lastSearchTime}
|
||||||
|
includeSeconds={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'languages') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name} className={styles.languages}>
|
||||||
|
<EpisodeFileLanguages episodeFileId={episodeFileId} />
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'status') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name} className={styles.status}>
|
||||||
|
<EpisodeStatus
|
||||||
|
episodeId={id}
|
||||||
|
episodeFileId={episodeFileId}
|
||||||
|
episodeEntity="wanted.cutoffUnmet"
|
||||||
|
/>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'actions') {
|
||||||
|
return (
|
||||||
|
<EpisodeSearchCell
|
||||||
|
key={name}
|
||||||
|
episodeId={id}
|
||||||
|
seriesId={series.id}
|
||||||
|
episodeTitle={title}
|
||||||
|
episodeEntity="wanted.cutoffUnmet"
|
||||||
|
showOpenSeriesButton={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CutoffUnmetRow;
|
@ -1,17 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import createSeriesSelector from 'Store/Selectors/createSeriesSelector';
|
|
||||||
import CutoffUnmetRow from './CutoffUnmetRow';
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
createSeriesSelector(),
|
|
||||||
(series) => {
|
|
||||||
return {
|
|
||||||
series
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps)(CutoffUnmetRow);
|
|
Loading…
Reference in new issue