From 9e5ae81f4ee1c66071cd9453588b0a7e8c1f2898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Fri, 2 Jun 2017 13:49:58 +0200 Subject: [PATCH] Update the shows store to be immutable --- src/public/js/actions/shows.js | 24 ++- src/public/js/components/list/details.js | 2 +- src/public/js/components/shows/list.js | 40 ++--- src/public/js/components/shows/listButtons.js | 13 +- src/public/js/reducers/shows.js | 142 +++++++----------- src/public/js/routes.js | 2 +- 6 files changed, 104 insertions(+), 119 deletions(-) diff --git a/src/public/js/actions/shows.js b/src/public/js/actions/shows.js index 20c5c28..b658f79 100644 --- a/src/public/js/actions/shows.js +++ b/src/public/js/actions/shows.js @@ -15,7 +15,9 @@ export function fetchShows(url) { export function getShowDetails(imdbId) { return request( 'SHOW_GET_DETAILS', - configureAxios().post(`/shows/${imdbId}/refresh`) + configureAxios().post(`/shows/${imdbId}/refresh`), + null, + { imdbId } ) } @@ -36,7 +38,9 @@ export function getEpisodeDetails(imdbId, season, episode) { export function fetchShowDetails(imdbId) { return request( 'SHOW_FETCH_DETAILS', - configureAxios().get(`/shows/${imdbId}`) + configureAxios().get(`/shows/${imdbId}`), + null, + { imdbId } ) } @@ -48,7 +52,6 @@ export function addShowToWishlist(imdbId, season = null, episode = null) { episode: episode, }), [ - addAlertOk("Show added to the wishlist"), updateShowWishlistStore(imdbId, true, season, episode), ], ) @@ -59,7 +62,6 @@ export function deleteShowFromWishlist(imdbId) { 'SHOW_DELETE_FROM_WISHLIST', configureAxios().delete(`/wishlist/shows/${imdbId}`), [ - addAlertOk("Show deleted from the wishlist"), updateShowWishlistStore(imdbId, false), ], ) @@ -87,10 +89,22 @@ export function getShowExploreOptions() { export function selectShow(imdbId) { return { type: 'SELECT_SHOW', - imdbId + payload: { + imdbId, + } } } +export function updateFilter(filter) { + return { + type: 'SHOWS_UPDATE_FILTER', + payload: { + filter, + }, + } +} + + export function updateLastShowsFetchUrl(url) { return { type: 'UPDATE_LAST_SHOWS_FETCH_URL', diff --git a/src/public/js/components/list/details.js b/src/public/js/components/list/details.js index 97b3d8f..4388296 100644 --- a/src/public/js/components/list/details.js +++ b/src/public/js/components/list/details.js @@ -16,7 +16,7 @@ export default function ListDetails(props) { const trackedSeason = props.data.get('tracked_season'); const trackedEpisode = props.data.get('tracked_episode'); - if (trackedEpisode !== undefined && trackedSeason !== undefined) { + if (trackedEpisode !== null && trackedSeason !== null) { if ((trackedSeason === 0) && (trackedEpisode === 0)) { wishlistStr = "Whole show tracked"; } else { diff --git a/src/public/js/components/shows/list.js b/src/public/js/components/shows/list.js index 38c705a..be414d3 100644 --- a/src/public/js/components/shows/list.js +++ b/src/public/js/components/shows/list.js @@ -2,45 +2,47 @@ import React from 'react' import { connect } from 'react-redux' import { bindActionCreators } from 'redux' import { selectShow, addShowToWishlist, - deleteShowFromWishlist, getShowDetails } from '../../actions/shows' + deleteShowFromWishlist, getShowDetails, updateFilter } from '../../actions/shows' import ListDetails from '../list/details' import ListPosters from '../list/posters' import ShowButtons from './listButtons' function mapStateToProps(state) { - return { showsStore: state.showsStore }; + return { + loading : state.showsStore.get('loading'), + shows : state.showsStore.get('shows'), + filter : state.showsStore.get('filter'), + selectedImdbId : state.showsStore.get('selectedImdbId'), + lastFetchUrl : state.showsStore.get('lastFetchUrl'), + exploreOptions : state.showsStore.get('exploreOptions'), + }; } const mapDispatchToProps = (dispatch) => bindActionCreators({ selectShow, addShowToWishlist, - deleteShowFromWishlist, getShowDetails }, dispatch) + deleteShowFromWishlist, getShowDetails, updateFilter }, dispatch) class ShowList extends React.Component { render() { - const shows = this.props.showsStore.shows; - const selectedShowId = this.props.showsStore.selectedImdbId; - let index = shows.map((el) => el.imdb_id).indexOf(selectedShowId); - if (index === -1) { - index = 0; + let selectedShow; + if (this.props.selectedImdbId !== "") { + selectedShow = this.props.shows.get(this.props.selectedImdbId); } - const selectedShow = shows[index]; return (
{selectedShow && @@ -49,7 +51,7 @@ class ShowList extends React.Component { deleteFromWishlist={this.props.deleteShowFromWishlist} addToWishlist={this.props.addShowToWishlist} getDetails={this.props.getShowDetails} - fetching={this.props.showsStore.getDetails} + updateFilter={this.props.updateFilter} /> } diff --git a/src/public/js/components/shows/listButtons.js b/src/public/js/components/shows/listButtons.js index 34ec5ed..1d923e3 100644 --- a/src/public/js/components/shows/listButtons.js +++ b/src/public/js/components/shows/listButtons.js @@ -6,7 +6,7 @@ import { DropdownButton } from 'react-bootstrap' import { WishlistButton, RefreshButton } from '../buttons/actions' export default function ShowButtons(props) { - const imdbLink = `http://www.imdb.com/title/${props.show.imdb_id}`; + const imdbLink = `http://www.imdb.com/title/${props.show.get('imdb_id')}`; return (
IMDB - + Details
@@ -27,16 +26,16 @@ export default function ShowButtons(props) { } function ActionsButton(props) { - let wishlisted = (props.show.tracked_season !== null && props.show.tracked_episode !== null); + let wishlisted = (props.show.get('tracked_season') !== null && props.show.get('tracked_episode') !== null); return ( 0) { - selectedImdbId = action.payload.response.data[0].imdb_id; - } - return Object.assign({}, state, { - shows: action.payload.response.data, - selectedImdbId: selectedImdbId, - filter: defaultState.filter, - loading: false, - }) - case 'SHOW_GET_DETAILS_PENDING': - return Object.assign({}, state, { - getDetails: true, - }) - case 'SHOW_GET_DETAILS_FULFILLED': - return Object.assign({}, state, { - shows: updateShowDetails(state.shows.slice(), action.payload.response.data), - getDetails: false, - }) - case 'EXPLORE_SHOWS_PENDING': - return Object.assign({}, state, { - loading: true, - }) - case 'EXPLORE_SHOWS_FULFILLED': - return Object.assign({}, state, { - shows: action.payload.response.data, - loading: false, - }) - case 'SHOW_GET_EXPLORE_OPTIONS_FULFILLED': - return Object.assign({}, state, { - exploreOptions: action.payload.response.data, - }) - case 'SHOW_UPDATE_STORE_WISHLIST': - return Object.assign({}, state, { - shows: updateShowsStoreWishlist(state.shows.slice(), action.payload), - }) - case 'UPDATE_LAST_SHOWS_FETCH_URL': - return Object.assign({}, state, { - lastShowsFetchUrl: action.payload.url, - }) - case 'SELECT_SHOW': - // Don't select the show if we're fetching another show's details - if (state.fetchingDetails) { - return state + if (shows.size > 0) { + // Sort by year + shows = shows.sort((a,b) => b.get('year') - a.get('year')); + selectedImdbId = shows.first().get('imdb_id'); } - return Object.assign({}, state, { - selectedImdbId: action.imdbId, - }) + return state.delete('shows').merge(Map({ + shows: shows, + filter: "", + loading: false, + selectedImdbId: selectedImdbId, + })) + case 'SHOW_GET_DETAILS_PENDING': + return state.setIn(['shows', action.payload.main.imdbId, 'fetchingDetails'], true); + case 'SHOW_GET_DETAILS_FULFILLED': + let show = action.payload.response.data; + show.fetchingDetails = false; + show.fetchingSubtitles = false; + return state.setIn(['shows', show.imdb_id], fromJS(show)); + case 'SHOW_GET_EXPLORE_OPTIONS_FULFILLED': + return state.set('exploreOptions', fromJS(action.payload.response.data)); + case 'SHOW_UPDATE_STORE_WISHLIST': + let season = action.payload.season; + let episode = action.payload.episode; + if (action.payload.wishlisted) { + if (season === null) { + season = 0; + } + if (episode === null) { + episode = 0; + } + } + + return state.mergeIn(['shows', action.payload.imdbId], Map({ + tracked_season: season, + tracked_episode: episode, + })); + case 'UPDATE_LAST_SHOWS_FETCH_URL': + return state.set('lastFetchUrl', action.payload.url); + case 'SELECT_SHOW': + return state.set('selectedImdbId', action.payload.imdbId); + case 'SHOWS_UPDATE_FILTER': + return state.set('filter', action.payload.filter); default: return state } } - -// Update the store containing all the shows -function updateShowsStoreWishlist(shows, payload) { - if (shows.length === 0) { - return shows; - } - - let index = shows.map((el) => el.imdb_id).indexOf(payload.imdbId); - let season = payload.season; - let episode = payload.episode; - if (payload.wishlisted) { - if (season === null) { - season = 0; - } - if (episode === null) { - episode = 0; - } - } - shows[index].tracked_season = season; - shows[index].tracked_episode = episode; - return shows -} - -function updateShowDetails(shows, data) { - let index = shows.map((el) => el.imdb_id).indexOf(data.imdb_id); - shows[index] = data; - return shows -} diff --git a/src/public/js/routes.js b/src/public/js/routes.js index 2bff9c7..c59b7b8 100644 --- a/src/public/js/routes.js +++ b/src/public/js/routes.js @@ -191,7 +191,7 @@ export default function getRoutes(App) { loginCheck(nextState, replace, next, function() { var state = store.getState(); // Fetch the explore options - if (Object.keys(state.showsStore.exploreOptions).length === 0) { + if (state.showsStore.get('exploreOptions').size === 0) { store.dispatch(getShowExploreOptions()); } store.dispatch(fetchShows(