From ac79c51196d7fa0439c5b239f27cc44ec0771d2c Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 9 Jul 2020 21:43:21 -0400 Subject: [PATCH] New: Monitor Collections from Movie Details Page --- frontend/src/Movie/Details/MovieDetails.js | 9 +- frontend/src/Movie/MovieCollection.css | 9 ++ frontend/src/Movie/MovieCollection.js | 38 ++++++++ .../src/Movie/MovieCollectionConnector.js | 95 +++++++++++++++++++ .../createMovieCollectionListSelector.js | 33 +++++++ 5 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 frontend/src/Movie/MovieCollection.css create mode 100644 frontend/src/Movie/MovieCollection.js create mode 100644 frontend/src/Movie/MovieCollectionConnector.js create mode 100644 frontend/src/Store/Selectors/createMovieCollectionListSelector.js diff --git a/frontend/src/Movie/Details/MovieDetails.js b/frontend/src/Movie/Details/MovieDetails.js index a3b9e6b05..0f09a055f 100644 --- a/frontend/src/Movie/Details/MovieDetails.js +++ b/frontend/src/Movie/Details/MovieDetails.js @@ -36,6 +36,7 @@ import MovieHistoryTable from 'Movie/History/MovieHistoryTable'; import MovieTitlesTable from './Titles/MovieTitlesTable'; import MovieCastPostersConnector from './Credits/Cast/MovieCastPostersConnector'; import MovieCrewPostersConnector from './Credits/Crew/MovieCrewPostersConnector'; +import MovieCollectionConnector from './../MovieCollectionConnector'; import MovieDetailsLinks from './MovieDetailsLinks'; import InteractiveSearchTable from 'InteractiveSearch/InteractiveSearchTable'; import InteractiveSearchFilterMenuConnector from 'InteractiveSearch/InteractiveSearchFilterMenuConnector'; @@ -538,9 +539,11 @@ class MovieDetails extends Component { title="Collection" size={sizes.LARGE} > - - {collection.name} - + } diff --git a/frontend/src/Movie/MovieCollection.css b/frontend/src/Movie/MovieCollection.css new file mode 100644 index 000000000..585998fef --- /dev/null +++ b/frontend/src/Movie/MovieCollection.css @@ -0,0 +1,9 @@ +.monitorToggleButton { + composes: toggleButton from '~Components/MonitorToggleButton.css'; + + width: 15px; + + &:hover { + color: $iconButtonHoverLightColor; + } +} diff --git a/frontend/src/Movie/MovieCollection.js b/frontend/src/Movie/MovieCollection.js new file mode 100644 index 000000000..a42b2b421 --- /dev/null +++ b/frontend/src/Movie/MovieCollection.js @@ -0,0 +1,38 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import MonitorToggleButton from 'Components/MonitorToggleButton'; +import styles from './MovieCollection.css'; + +function MovieCollection(props) { + const { + name, + collectionList, + isSaving, + onMonitorTogglePress + } = props; + + const monitored = collectionList !== undefined && collectionList.enabled && collectionList.enableAuto; + + return ( +
+ + {name} +
+ ); +} + +MovieCollection.propTypes = { + tmdbId: PropTypes.number.isRequired, + name: PropTypes.string.isRequired, + collectionList: PropTypes.object, + isSaving: PropTypes.bool.isRequired, + onMonitorTogglePress: PropTypes.func.isRequired +}; + +export default MovieCollection; diff --git a/frontend/src/Movie/MovieCollectionConnector.js b/frontend/src/Movie/MovieCollectionConnector.js new file mode 100644 index 000000000..a40654675 --- /dev/null +++ b/frontend/src/Movie/MovieCollectionConnector.js @@ -0,0 +1,95 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { createSelector } from 'reselect'; +import { connect } from 'react-redux'; +import createMovieSelector from 'Store/Selectors/createMovieSelector'; +import createMovieCollectionListSelector from 'Store/Selectors/createMovieCollectionListSelector'; +import { selectNetImportSchema, setNetImportValue, setNetImportFieldValue, saveNetImport } from 'Store/Actions/settingsActions'; +import MovieCollection from './MovieCollection'; + +function createMapStateToProps() { + return createSelector( + createMovieSelector(), + createMovieCollectionListSelector(), + (state) => state.settings.netImports, + (movie, collectionList, netImports) => { + const { + monitored, + qualityProfileId, + path, + minimumAvailability + } = movie; + + return { + collectionList, + monitored, + qualityProfileId, + path, + minimumAvailability, + isSaving: netImports.isSaving + }; + } + ); +} + +const mapDispatchToProps = { + selectNetImportSchema, + setNetImportFieldValue, + setNetImportValue, + saveNetImport +}; + +class MovieCollectionConnector extends Component { + + // + // Listeners + + onMonitorTogglePress = (monitored) => { + if (this.props.collectionList) { + this.props.setNetImportValue({ name: 'enabled', value: monitored }); + this.props.setNetImportValue({ name: 'enableAuto', value: monitored }); + this.props.saveNetImport({ id: this.props.collectionList.id }); + } else { + this.props.selectNetImportSchema({ implementation: 'TMDbCollectionImport', presetName: undefined }); + this.props.setNetImportFieldValue({ name: 'collectionId', value: this.props.tmdbId.toString() }); + this.props.setNetImportValue({ name: 'enabled', value: true }); + this.props.setNetImportValue({ name: 'enableAuto', value: true }); + this.props.setNetImportValue({ name: 'name', value: `${this.props.name} - ${this.props.tmdbId}` }); + this.props.setNetImportValue({ name: 'rootFolderPath', value: this.props.path }); + this.props.setNetImportValue({ name: 'qualityProfileId', value: this.props.qualityProfileId }); + this.props.setNetImportValue({ name: 'monitored', value: this.props.monitored }); + this.props.setNetImportValue({ name: 'minimumAvailability', value: this.props.minimumAvailability }); + this.props.saveNetImport(); + } + } + + // + // Render + + render() { + return ( + + ); + } +} + +MovieCollectionConnector.propTypes = { + tmdbId: PropTypes.number.isRequired, + movieId: PropTypes.number.isRequired, + name: PropTypes.string.isRequired, + collectionList: PropTypes.object, + monitored: PropTypes.bool.isRequired, + qualityProfileId: PropTypes.number.isRequired, + path: PropTypes.string.isRequired, + minimumAvailability: PropTypes.string.isRequired, + isSaving: PropTypes.bool.isRequired, + selectNetImportSchema: PropTypes.func.isRequired, + setNetImportFieldValue: PropTypes.func.isRequired, + setNetImportValue: PropTypes.func.isRequired, + saveNetImport: PropTypes.func.isRequired +}; + +export default connect(createMapStateToProps, mapDispatchToProps)(MovieCollectionConnector); diff --git a/frontend/src/Store/Selectors/createMovieCollectionListSelector.js b/frontend/src/Store/Selectors/createMovieCollectionListSelector.js new file mode 100644 index 000000000..d8d700fdd --- /dev/null +++ b/frontend/src/Store/Selectors/createMovieCollectionListSelector.js @@ -0,0 +1,33 @@ +import _ from 'lodash'; +import { createSelector } from 'reselect'; + +function createMovieCollectionListSelector() { + return createSelector( + (state, { tmdbId }) => tmdbId, + (state) => state.settings.netImports.items, + (tmdbId, netImports) => { + const netImportIds = _.reduce(netImports, (acc, list) => { + if (list.implementation === 'TMDbCollectionImport') { + const collectionIdField = list.fields.find((field) => { + return field.name === 'collectionId'; + }); + + if (collectionIdField && parseInt(collectionIdField.value) === tmdbId) { + acc.push(list); + return acc; + } + } + + return acc; + }, []); + + if (netImportIds.length === 0) { + return undefined; + } + + return netImportIds[0]; + } + ); +} + +export default createMovieCollectionListSelector;