import moment from 'moment'; import { createAction } from 'redux-actions'; import sortByName from 'Utilities/Array/sortByName'; import { filterBuilderTypes, filterBuilderValueTypes, filterTypePredicates, sortDirections } from 'Helpers/Props'; import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer'; import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer'; import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer'; import createHandleActions from './Creators/createHandleActions'; import { filters, filterPredicates, sortPredicates } from './seriesActions'; // // Variables export const section = 'seriesIndex'; // // State export const defaultState = { sortKey: 'sortTitle', sortDirection: sortDirections.ASCENDING, secondarySortKey: 'sortTitle', secondarySortDirection: sortDirections.ASCENDING, view: 'posters', posterOptions: { detailedProgressBar: false, size: 'large', showTitle: false, showMonitored: true, showQualityProfile: true, showSearchAction: false }, overviewOptions: { detailedProgressBar: false, size: 'medium', showMonitored: true, showNetwork: true, showQualityProfile: true, showPreviousAiring: false, showAdded: false, showSeasonCount: true, showPath: false, showSizeOnDisk: false, showSearchAction: false }, tableOptions: { showBanners: false, showSearchAction: false }, columns: [ { name: 'status', columnLabel: 'Status', isSortable: true, isVisible: true, isModifiable: false }, { name: 'sortTitle', label: 'Series Title', isSortable: true, isVisible: true, isModifiable: false }, { name: 'seriesType', label: 'Type', isSortable: true, isVisible: false }, { name: 'network', label: 'Network', isSortable: true, isVisible: true }, { name: 'qualityProfileId', label: 'Quality Profile', isSortable: true, isVisible: true }, { name: 'languageProfileId', label: 'Language Profile', isSortable: true, isVisible: false }, { name: 'nextAiring', label: 'Next Airing', isSortable: true, isVisible: true }, { name: 'previousAiring', label: 'Previous Airing', isSortable: true, isVisible: false }, { name: 'added', label: 'Added', isSortable: true, isVisible: false }, { name: 'seasonCount', label: 'Seasons', isSortable: true, isVisible: true }, { name: 'episodeProgress', label: 'Episodes', isSortable: true, isVisible: true }, { name: 'episodeCount', label: 'Episode Count', isSortable: true, isVisible: false }, { name: 'latestSeason', label: 'Latest Season', isSortable: true, isVisible: false }, { name: 'year', label: 'Year', isSortable: true, isVisible: false }, { name: 'path', label: 'Path', isSortable: true, isVisible: false }, { name: 'sizeOnDisk', label: 'Size on Disk', isSortable: true, isVisible: false }, { name: 'genres', label: 'Genres', isSortable: false, isVisible: false }, { name: 'ratings', label: 'Rating', isSortable: true, isVisible: false }, { name: 'certification', label: 'Certification', isSortable: false, isVisible: false }, { name: 'tags', label: 'Tags', isSortable: false, isVisible: false }, { name: 'useSceneNumbering', label: 'Scene Numbering', isSortable: true, isVisible: false }, { name: 'actions', columnLabel: 'Actions', isVisible: true, isModifiable: false } ], sortPredicates: { ...sortPredicates, network: function(item) { const network = item.network; return network ? network.toLowerCase() : ''; }, nextAiring: function(item, direction) { const nextAiring = item.nextAiring; if (nextAiring) { return moment(nextAiring).unix(); } if (direction === sortDirections.DESCENDING) { return 0; } return Number.MAX_VALUE; }, episodeProgress: function(item) { const { statistics = {} } = item; const { episodeCount = 0, episodeFileCount } = statistics; const progress = episodeCount ? episodeFileCount / episodeCount * 100 : 100; return progress + episodeCount / 1000000; }, episodeCount: function(item) { const { statistics = {} } = item; return statistics.totalEpisodeCount || 0; }, seasonCount: function(item) { const { statistics = {} } = item; return statistics.seasonCount; }, ratings: function(item) { const { ratings = {} } = item; return ratings.value; } }, selectedFilterKey: 'all', filters, filterPredicates: { ...filterPredicates, episodeProgress: function(item, filterValue, type) { const { statistics = {} } = item; const { episodeCount = 0, episodeFileCount } = statistics; const progress = episodeCount ? episodeFileCount / episodeCount * 100 : 100; const predicate = filterTypePredicates[type]; return predicate(progress, filterValue); } }, filterBuilderProps: [ { name: 'monitored', label: 'Monitored', type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.BOOL }, { name: 'status', label: 'Status', type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.SERIES_STATUS }, { name: 'seriesType', label: 'Type', type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.SERIES_TYPES }, { name: 'network', label: 'Network', type: filterBuilderTypes.STRING, optionsSelector: function(items) { const tagList = items.reduce((acc, series) => { if (series.network) { acc.push({ id: series.network, name: series.network }); } return acc; }, []); return tagList.sort(sortByName); } }, { name: 'qualityProfileId', label: 'Quality Profile', type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.QUALITY_PROFILE }, { name: 'languageProfileId', label: 'Language Profile', type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.LANGUAGE_PROFILE }, { name: 'nextAiring', label: 'Next Airing', type: filterBuilderTypes.DATE, valueType: filterBuilderValueTypes.DATE }, { name: 'previousAiring', label: 'Previous Airing', type: filterBuilderTypes.DATE, valueType: filterBuilderValueTypes.DATE }, { name: 'added', label: 'Added', type: filterBuilderTypes.DATE, valueType: filterBuilderValueTypes.DATE }, { name: 'seasonCount', label: 'Season Count', type: filterBuilderTypes.NUMBER }, { name: 'episodeProgress', label: 'Episode Progress', type: filterBuilderTypes.NUMBER }, { name: 'path', label: 'Path', type: filterBuilderTypes.STRING }, { name: 'sizeOnDisk', label: 'Size on Disk', type: filterBuilderTypes.NUMBER, valueType: filterBuilderValueTypes.BYTES }, { name: 'genres', label: 'Genres', type: filterBuilderTypes.ARRAY, optionsSelector: function(items) { const tagList = items.reduce((acc, series) => { series.genres.forEach((genre) => { acc.push({ id: genre, name: genre }); }); return acc; }, []); return tagList.sort(sortByName); } }, { name: 'ratings', label: 'Rating', type: filterBuilderTypes.NUMBER }, { name: 'certification', label: 'Certification', type: filterBuilderTypes.EXACT }, { name: 'tags', label: 'Tags', type: filterBuilderTypes.ARRAY, valueType: filterBuilderValueTypes.TAG }, { name: 'useSceneNumbering', label: 'Scene Numbering', type: filterBuilderTypes.EXACT } ] }; export const persistState = [ 'seriesIndex.sortKey', 'seriesIndex.sortDirection', 'seriesIndex.selectedFilterKey', 'seriesIndex.customFilters', 'seriesIndex.view', 'seriesIndex.columns', 'seriesIndex.posterOptions', 'seriesIndex.overviewOptions', 'seriesIndex.tableOptions' ]; // // Actions Types export const SET_SERIES_SORT = 'seriesIndex/setSeriesSort'; export const SET_SERIES_FILTER = 'seriesIndex/setSeriesFilter'; export const SET_SERIES_VIEW = 'seriesIndex/setSeriesView'; export const SET_SERIES_TABLE_OPTION = 'seriesIndex/setSeriesTableOption'; export const SET_SERIES_POSTER_OPTION = 'seriesIndex/setSeriesPosterOption'; export const SET_SERIES_OVERVIEW_OPTION = 'seriesIndex/setSeriesOverviewOption'; // // Action Creators export const setSeriesSort = createAction(SET_SERIES_SORT); export const setSeriesFilter = createAction(SET_SERIES_FILTER); export const setSeriesView = createAction(SET_SERIES_VIEW); export const setSeriesTableOption = createAction(SET_SERIES_TABLE_OPTION); export const setSeriesPosterOption = createAction(SET_SERIES_POSTER_OPTION); export const setSeriesOverviewOption = createAction(SET_SERIES_OVERVIEW_OPTION); // // Reducers export const reducers = createHandleActions({ [SET_SERIES_SORT]: createSetClientSideCollectionSortReducer(section), [SET_SERIES_FILTER]: createSetClientSideCollectionFilterReducer(section), [SET_SERIES_VIEW]: function(state, { payload }) { return Object.assign({}, state, { view: payload.view }); }, [SET_SERIES_TABLE_OPTION]: createSetTableOptionReducer(section), [SET_SERIES_POSTER_OPTION]: function(state, { payload }) { const posterOptions = state.posterOptions; return { ...state, posterOptions: { ...posterOptions, ...payload } }; }, [SET_SERIES_OVERVIEW_OPTION]: function(state, { payload }) { const overviewOptions = state.overviewOptions; return { ...state, overviewOptions: { ...overviewOptions, ...payload } }; } }, defaultState, section);