import $ from 'jquery'; import { createAction } from 'redux-actions'; import { batchActions } from 'redux-batched-actions'; import createAjaxRequest from 'Utilities/createAjaxRequest'; import sortByName from 'Utilities/Array/sortByName'; import { filterBuilderTypes, filterBuilderValueTypes, sortDirections } from 'Helpers/Props'; import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer'; import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer'; import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer'; import { createThunk, handleThunks } from 'Store/thunks'; import createHandleActions from './Creators/createHandleActions'; import { set, updateItem } from './baseActions'; import { filters, filterPredicates, sortPredicates } from './movieActions'; // // Variables export const section = 'movieIndex'; // // State export const defaultState = { isSaving: false, saveError: null, isDeleting: false, deleteError: null, 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, showStudio: true, showQualityProfile: true, showAdded: false, showPath: false, showSizeOnDisk: false, showSearchAction: false }, tableOptions: { showSearchAction: false }, columns: [ { name: 'select', columnLabel: 'Select', isSortable: false, isVisible: true, isModifiable: false, isHidden: true }, { name: 'status', columnLabel: 'Release Status', isSortable: true, isVisible: true, isModifiable: false }, { name: 'sortTitle', label: 'Movie Title', isSortable: true, isVisible: true, isModifiable: false }, { name: 'collection', label: 'Collection', isSortable: true, isVisible: false }, { name: 'studio', label: 'Studio', isSortable: true, isVisible: true }, { name: 'qualityProfileId', label: 'Quality Profile', isSortable: true, isVisible: true }, { name: 'added', label: 'Added', isSortable: true, isVisible: false }, { name: 'inCinemas', label: 'In Cinemas', isSortable: true, isVisible: false }, { name: 'physicalRelease', label: 'Physical Release', isSortable: true, isVisible: false }, { name: 'minimumAvailability', label: 'Min Availability', 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: 'movieStatus', label: 'Status', isSortable: true, isVisible: true }, { 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: 'actions', columnLabel: 'Actions', isVisible: true, isModifiable: false } ], sortPredicates: { ...sortPredicates, studio: function(item) { const studio = item.studio; return studio ? studio.toLowerCase() : ''; }, collection: function(item) { const { collection ={} } = item; return collection.name; }, ratings: function(item) { const { ratings = {} } = item; return ratings.value; } }, selectedFilterKey: 'all', filters, filterPredicates, filterBuilderProps: [ { name: 'monitored', label: 'Monitored', type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.BOOL }, { name: 'status', label: 'Status', type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.MOVIE_STATUS }, { name: 'studio', label: 'Studio', type: filterBuilderTypes.EXACT, optionsSelector: function(items) { const tagList = items.reduce((acc, movie) => { if (movie.studio) { acc.push({ id: movie.studio, name: movie.studio }); } return acc; }, []); return tagList.sort(sortByName); } }, { name: 'collection', label: 'Collection', type: filterBuilderTypes.ARRAY, optionsSelector: function(items) { const collectionList = items.reduce((acc, movie) => { if (movie.collection) { acc.push({ id: movie.collection.name, name: movie.collection.name }); } return acc; }, []); return collectionList.sort(sortByName); } }, { name: 'qualityProfileId', label: 'Quality Profile', type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.QUALITY_PROFILE }, { name: 'added', label: 'Added', type: filterBuilderTypes.DATE, valueType: filterBuilderValueTypes.DATE }, { name: 'inCinemas', label: 'In Cinemas', type: filterBuilderTypes.DATE, valueType: filterBuilderValueTypes.DATE }, { name: 'physicalRelease', label: 'Physical Release', type: filterBuilderTypes.DATE, valueType: filterBuilderValueTypes.DATE }, { 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 genreList = items.reduce((acc, movie) => { movie.genres.forEach((genre) => { acc.push({ id: genre, name: genre }); }); return acc; }, []); return genreList.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 } ] }; export const persistState = [ 'movieIndex.sortKey', 'movieIndex.sortDirection', 'movieIndex.selectedFilterKey', 'movieIndex.customFilters', 'movieIndex.view', 'movieIndex.columns', 'movieIndex.posterOptions', 'movieIndex.overviewOptions', 'movieIndex.tableOptions' ]; // // Actions Types export const SET_MOVIE_SORT = 'movieIndex/setMovieSort'; export const SET_MOVIE_FILTER = 'movieIndex/setMovieFilter'; export const SET_MOVIE_VIEW = 'movieIndex/setMovieView'; export const SET_MOVIE_TABLE_OPTION = 'movieIndex/setMovieTableOption'; export const SET_MOVIE_POSTER_OPTION = 'movieIndex/setMoviePosterOption'; export const SET_MOVIE_OVERVIEW_OPTION = 'movieIndex/setMovieOverviewOption'; export const SAVE_MOVIE_EDITOR = 'movieIndex/saveMovieEditor'; export const BULK_DELETE_MOVIE = 'movieIndex/bulkDeleteMovie'; // // Action Creators export const setMovieSort = createAction(SET_MOVIE_SORT); export const setMovieFilter = createAction(SET_MOVIE_FILTER); export const setMovieView = createAction(SET_MOVIE_VIEW); export const setMovieTableOption = createAction(SET_MOVIE_TABLE_OPTION); export const setMoviePosterOption = createAction(SET_MOVIE_POSTER_OPTION); export const setMovieOverviewOption = createAction(SET_MOVIE_OVERVIEW_OPTION); export const saveMovieEditor = createThunk(SAVE_MOVIE_EDITOR); export const bulkDeleteMovie = createThunk(BULK_DELETE_MOVIE); // // Action Handlers export const actionHandlers = handleThunks({ [SAVE_MOVIE_EDITOR]: function(getState, payload, dispatch) { dispatch(set({ section, isSaving: true })); const promise = createAjaxRequest({ url: '/movie/editor', method: 'PUT', data: JSON.stringify(payload), dataType: 'json' }).request; promise.done((data) => { dispatch(batchActions([ ...data.map((movie) => { return updateItem({ id: movie.id, section: 'movies', ...movie }); }), set({ section, isSaving: false, saveError: null }) ])); }); promise.fail((xhr) => { dispatch(set({ section, isSaving: false, saveError: xhr })); }); }, [BULK_DELETE_MOVIE]: function(getState, payload, dispatch) { const { id, ...queryParams } = payload; dispatch(set({ section, isDeleting: true })); const promise = createAjaxRequest({ url: `/movie/editor?${$.param(queryParams, true)}`, method: 'DELETE', data: JSON.stringify(payload), dataType: 'json' }).request; promise.done(() => { // SignaR will take care of removing the movie from the collection dispatch(set({ section, isDeleting: false, deleteError: null })); }); promise.fail((xhr) => { dispatch(set({ section, isDeleting: false, deleteError: xhr })); }); } }); // // Reducers export const reducers = createHandleActions({ [SET_MOVIE_SORT]: createSetClientSideCollectionSortReducer(section), [SET_MOVIE_FILTER]: createSetClientSideCollectionFilterReducer(section), [SET_MOVIE_VIEW]: function(state, { payload }) { return Object.assign({}, state, { view: payload.view }); }, [SET_MOVIE_TABLE_OPTION]: createSetTableOptionReducer(section), [SET_MOVIE_POSTER_OPTION]: function(state, { payload }) { const posterOptions = state.posterOptions; return { ...state, posterOptions: { ...posterOptions, ...payload } }; }, [SET_MOVIE_OVERVIEW_OPTION]: function(state, { payload }) { const overviewOptions = state.overviewOptions; return { ...state, overviewOptions: { ...overviewOptions, ...payload } }; } }, defaultState, section);