Update the movie store to be immutable

This commit is contained in:
Grégoire Delattre 2017-06-02 13:49:31 +02:00
parent 697997c0ae
commit 80db4383a3
15 changed files with 277 additions and 284 deletions

View File

@ -14,7 +14,18 @@ export function updateLastMovieFetchUrl(url) {
export function selectMovie(imdbId) {
return {
type: 'SELECT_MOVIE',
imdbId
payload: {
imdbId,
},
}
}
export function updateFilter(filter) {
return {
type: 'MOVIE_UPDATE_FILTER',
payload: {
filter,
},
}
}
@ -28,7 +39,11 @@ export function getMovieExploreOptions() {
export function getMovieDetails(imdbId) {
return request(
'MOVIE_GET_DETAILS',
configureAxios().post(`/movies/${imdbId}/refresh`)
configureAxios().post(`/movies/${imdbId}/refresh`),
null,
{
imdbId,
}
)
}
@ -48,7 +63,6 @@ export function addMovieToWishlist(imdbId) {
'MOVIE_ADD_TO_WISHLIST',
configureAxios().post(`/wishlist/movies/${imdbId}`),
[
addAlertOk("Movie added to the wishlist"),
updateMovieWishlistStore(imdbId, true),
],
)
@ -59,7 +73,6 @@ export function deleteMovieFromWishlist(imdbId) {
'MOVIE_DELETE_FROM_WISHLIST',
configureAxios().delete(`/wishlist/movies/${imdbId}`),
[
addAlertOk("Movie deleted from the wishlist"),
updateMovieWishlistStore(imdbId, false),
],
)

View File

@ -10,7 +10,7 @@ export function refreshSubtitles(type, id, season, episode) {
'MOVIE_SUBTITLES_UPDATE',
configureAxios().post(`${resourceURL}/subtitles/refresh`),
null,
{ imdb_id: id },
{ imdbId: id },
)
case 'episode':
var resourceURL = `/shows/${id}/seasons/${season}/episodes/${episode}`
@ -19,12 +19,12 @@ export function refreshSubtitles(type, id, season, episode) {
configureAxios().post(`${resourceURL}/subtitles/refresh`),
null,
{
imdb_id: id,
imdbId: id,
season: season,
episode: episode,
},
)
default:
console.log("refreshSubtitles - Unknown type " + type)
console.warn("refreshSubtitles - Unknown type " + type)
}
}

View File

@ -42,7 +42,7 @@ import getRoutes from './routes'
function mapStateToProps(state) {
let torrentCount = 0;
if (state.torrentStore.has('torrents')) {
if (state.torrentStore.has('torrents') && state.torrentStore.get('torrents') !== undefined) {
torrentCount = state.torrentStore.get('torrents').size;
}
return {

View File

@ -1,4 +1,5 @@
import React from 'react'
import { toJS } from 'immutable'
import { Button, Dropdown, MenuItem, Modal } from 'react-bootstrap'
@ -69,20 +70,13 @@ export default class DownloadButton extends React.Component {
class Player extends React.Component {
constructor(props) {
super(props);
var subtitles = [];
if (props.subtitles && props.subtitles.length) {
subtitles = props.subtitles;
}
this.state = {
subtitles: subtitles,
};
}
render() {
return (
<div className="embed-responsive embed-responsive-16by9">
<video controls>
<source src={this.props.url} type="video/mp4"/>
{this.props.subtitles.map(function(el, index) {
{this.props.subtitles !== undefined && subtitles.toKeyedSeq().map(function(el, index) {
return (
<track
key={index}

View File

@ -9,9 +9,8 @@ export default class SubtitlesButton extends React.Component {
}
handleClick(e, url) {
e.preventDefault();
if (this.props.fetching) {
return
}
if (this.props.fetching) { return }
// Refresh the subtitles
this.props.refreshSubtitles(this.props.type, this.props.resourceID, this.props.season, this.props.episode);
}
@ -35,16 +34,16 @@ export default class SubtitlesButton extends React.Component {
case 'action':
return (
<MenuItem key={index} onClick={(event) => this.handleClick(event, e.url)}>
{this.props.fetchingSubtitles ||
{this.props.fetching ||
<span>
<i className="fa fa-refresh">
</i> Refresh
<i className="fa fa-refresh">
</i> Refresh
</span>
}
{this.props.fetchingSubtitles &&
{this.props.fetching &&
<span>
<i className="fa fa-spin fa-refresh">
</i> Refreshing
<i className="fa fa-spin fa-refresh">
</i> Refreshing
</span>
}
</MenuItem>
@ -77,7 +76,7 @@ function buildMenuItems(subtitles) {
});
// If there is no subtitles, stop here
if (!subtitles) {
if (subtitles == undefined) {
return entries;
}
@ -88,8 +87,8 @@ function buildMenuItems(subtitles) {
entries.push({
type: "entry",
// Take only the last part of fr_FR
lang: sub.language.split("_")[1],
url: sub.url,
lang: sub.get('language').split("_")[1],
url: sub.get('url'),
});
}

View File

@ -1,46 +1,47 @@
import React from 'react'
export default function ListDetails(props) {
let genres;
if (props.data.genres) {
let genres = props.data.get('genres');
if (genres !== undefined) {
// Uppercase first genres
genres = props.data.genres.map(
genres = genres.toJS().map(
(word) => word[0].toUpperCase() + word.substr(1)
).join(', ');
}
let wishlistStr = "";
if (props.data.wishlisted === true) {
if (props.data.get('wishlisted') === true) {
wishlistStr = "Wishlisted";
}
if (props.data.tracked_episode !== null && props.data.tracked_season != null) {
let season = props.data.tracked_season;
let episode = props.data.tracked_episode;
if ((season === 0) && (episode === 0)) {
const trackedSeason = props.data.get('tracked_season');
const trackedEpisode = props.data.get('tracked_episode');
if (trackedEpisode !== undefined && trackedSeason !== undefined) {
if ((trackedSeason === 0) && (trackedEpisode === 0)) {
wishlistStr = "Whole show tracked";
} else {
wishlistStr = `Tracked from season ${season} episode ${episode}`;
wishlistStr = `Tracked from season ${trackedSeason} episode ${trackedEpisode}`;
}
}
return (
<div className="col-xs-7 col-md-4">
<div className="affix">
<h1 className="hidden-xs">{props.data.title}</h1>
<h3 className="visible-xs">{props.data.title}</h3>
<h1 className="hidden-xs">{props.data.get('title')}</h1>
<h3 className="visible-xs">{props.data.get('title')}</h3>
{wishlistStr !== "" &&
<span className="label label-default">
<i className="fa fa-bookmark"></i> {wishlistStr}
</span>
}
<h4>{props.data.year}</h4>
{props.data.runtime &&
<h4>{props.data.get('year')}</h4>
{props.data.get('runtime') !== undefined &&
<p>
<i className="fa fa-clock-o"></i>
&nbsp;{props.data.runtime} min
&nbsp;{props.data.get('runtime')} min
</p>
}
{props.data.genres &&
{genres !== undefined &&
<p>
<i className="fa fa-tags"></i>
&nbsp;{genres}
@ -48,12 +49,12 @@ export default function ListDetails(props) {
}
<p>
<i className="fa fa-star-o"></i>
&nbsp;{Number(props.data.rating).toFixed(1)}&nbsp;
{props.data.votes &&
<small>({props.data.votes} counts)</small>
&nbsp;{Number(props.data.get('rating')).toFixed(1)}&nbsp;
{props.data.get('votes') !== undefined &&
<small>({props.data.get('votes')} counts)</small>
}
</p>
<p className="plot">{props.data.plot}</p>
<p className="plot">{props.data.get('plot')}</p>
</div>
{props.children}
</div>

View File

@ -9,7 +9,7 @@ export default class ExplorerOptions extends React.Component {
}
handleSourceChange(event) {
let source = event.target.value;
let category = this.props.options[event.target.value][0];
let category = this.props.options.get(event.target.value).first();
this.props.router.push(`/${this.props.type}/explore/${source}/${category}`);
}
handleCategoryChange(event) {
@ -40,7 +40,7 @@ export default class ExplorerOptions extends React.Component {
}
// Options are not yet fetched
if (Object.keys(this.props.options).length === 0) {
if (this.props.options.size === 0) {
return null;
}
@ -51,7 +51,7 @@ export default class ExplorerOptions extends React.Component {
let source = this.props.params.source;
let category = this.props.params.category;
let categories = this.props.options[this.props.params.source];
let categories = this.props.options.get(this.props.params.source);
return (
<div className="row">
@ -67,8 +67,9 @@ export default class ExplorerOptions extends React.Component {
onChange={this.handleSourceChange}
value={source}
>
{Object.keys(this.props.options).map(function(source) {
return (<option key={source} value={source}>{this.prettyName(source)}</option>)
{this.props.options.entrySeq().map(function([source, categories]) {
return (
<option key={source} value={source}>{this.prettyName(source)}</option>)
}, this)}
</FormControl>
</FormGroup>

View File

@ -1,30 +1,42 @@
import React from 'react'
import { Control, Form } from 'react-redux-form';
export default function ListFilter(props) {
if (!props.display) {
return null;
export default class ListFilter extends React.PureComponent {
constructor(props) {
super(props);
this.state = { filter: '' };
this.handleChange = this.handleChange.bind(this);
}
handleChange(ev) {
if (ev) { ev.preventDefault(); }
const value = this.input.value;
if (this.state.filter === value) { return }
this.setState({ filter: value });
if (props.listSize === 0) {
return null;
// Start filtering at 3 chars
if (value.length >= 3) {
this.props.updateFilter(value);
} else {
this.props.updateFilter('');
}
}
return (
<div className="row">
<div className="col-xs-12 col-md-12 list-filter">
<Form model={props.formModel} className="input-group hidebtn-xs" >
<Control.text
model={props.controlModel}
className="form-control input-sm"
placeholder={props.controlPlaceHolder}
updateOn="change"
/>
<span className="input-group-btn hidden-xs">
<button className="btn btn-default btn-sm" type="button">Filter</button>
</span>
</Form>
render() {
return (
<div className="row">
<div className="col-xs-12 col-md-12 list-filter">
<form className="input-group" onSubmit={(ev) => this.handleChange(ev)}>
<input
className="form-control input-sm"
placeholder={this.props.placeHolder}
onChange={this.handleChange}
ref={(input) => this.input = input}
value={this.state.filter}
/>
<span className="input-group-btn hidden-xs">
<button className="btn btn-default btn-sm" type="button">Filter</button>
</span>
</form>
</div>
</div>
</div>
);
);
}
}

View File

@ -1,30 +1,35 @@
import React from 'react'
export default function ListPoster(props) {
const selected = props.selected ? ' thumbnail-selected' : '';
const imgClass = 'thumbnail' + selected;
const displayClearFixLg = (props.index % 6) === 0;
const displayClearFixMd = (props.index % 4) === 0;
const displayClearFixSm = (props.index % 2) === 0;
return (
<div>
{displayClearFixLg &&
<div className="clearfix visible-lg"></div>
}
{displayClearFixMd &&
<div className="clearfix visible-md"></div>
}
{displayClearFixSm &&
<div className="clearfix visible-sm"></div>
}
<div className="col-xs-12 col-sm-6 col-md-3 col-lg-2">
<a className={imgClass}>
<img
src={props.data.poster_url}
onClick={props.onClick}
/>
</a>
export default class ListPoster extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
const selected = this.props.selected ? ' thumbnail-selected' : '';
const imgClass = 'thumbnail' + selected;
const displayClearFixLg = (this.props.index % 6) === 0;
const displayClearFixMd = (this.props.index % 4) === 0;
const displayClearFixSm = (this.props.index % 2) === 0;
return (
<div>
{displayClearFixLg &&
<div className="clearfix visible-lg"></div>
}
{displayClearFixMd &&
<div className="clearfix visible-md"></div>
}
{displayClearFixSm &&
<div className="clearfix visible-sm"></div>
}
<div className="col-xs-12 col-sm-6 col-md-3 col-lg-2">
<a className={imgClass}>
<img
src={this.props.data.get('poster_url')}
onClick={this.props.onClick}
/>
</a>
</div>
</div>
</div>
);
);
}
}

View File

@ -1,4 +1,5 @@
import React from 'react'
import { Map, List, fromJS } from 'immutable'
import fuzzy from 'fuzzy';
import InfiniteScroll from 'react-infinite-scroller';
@ -24,14 +25,14 @@ export default class ListPosters extends React.Component {
return;
}
if (!this.props.data.length) {
if (this.props.data === undefined) {
return;
}
this.setState(this.getNextState(this.props));
}
getNextState(props) {
let totalListSize = props.data.length;
let totalListSize = props.data !== undefined ? props.data.size : 0;
let currentListSize = (this.state && this.state.items) ? this.state.items : 0;
let nextListSize = currentListSize + DEFAULT_ADD_EXTRA_ITEMS;
let hasMore = true;
@ -47,44 +48,44 @@ export default class ListPosters extends React.Component {
};
}
componentWillReceiveProps(nextProps) {
if (this.props.data.length !== nextProps.data.length) {
if (this.props.data === undefined) { return }
if (nextProps.data === undefined) { return }
if (this.props.data.size !== nextProps.data.size) {
this.setState(this.getNextState(nextProps));
}
}
render() {
let elmts = this.props.data.slice();
const listSize = elmts.length;
let elmts = this.props.data;
const listSize = elmts !== undefined ? elmts.size : 0;
const colSize = (listSize !== 0) ? "col-xs-5 col-md-8" : "col-xs-12";
// Filter the list of elements
if (this.props.filter !== "") {
const filtered = fuzzy.filter(this.props.filter, elmts, {
extract: (el) => el.title
});
elmts = filtered.map((el) => el.original);
} else {
elmts = elmts.slice(0, this.state.items);
}
// Filter the list of elements
if (this.props.filter !== "") {
elmts = elmts.filter((v) => fuzzy.test(this.props.filter, v.get('title')), this);
} else {
elmts = elmts.slice(0, this.state.items);
}
// Chose when to display filter / explore options
let displayFilter = true;
if (this.props.params
if ((this.props.params
&& this.props.params.category
&& this.props.params.category !== ""
&& this.props.params.source
&& this.props.params.source !== "") {
&& this.props.params.source !== "")
|| (listSize === 0)) {
displayFilter = false;
}
return (
<div className={colSize}>
<ListFilter
listSize={listSize}
display={displayFilter}
formModel={this.props.formModel}
controlModel={this.props.filterControlModel}
controlPlaceHolder={this.props.filterControlPlaceHolder}
/>
{displayFilter &&
<ListFilter
updateFilter={this.props.updateFilter}
placeHolder={this.props.placeHolder}
/>
}
<ExplorerOptions
type={this.props.type}
display={!displayFilter}
@ -105,39 +106,45 @@ export default class ListPosters extends React.Component {
}
}
function Posters(props) {
if (props.loading) {
return (<Loader />);
class Posters extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
if (this.props.loading) {
return (<Loader />);
}
if (this.props.elmts.size === 0) {
return (
<div className="jumbotron">
<h2>No result</h2>
</div>
);
}
if (props.elmts.length === 0) {
return (
<div className="jumbotron">
<h2>No result</h2>
<div>
<InfiniteScroll
hasMore={this.props.hasMore}
loadMore={this.props.loadMore}
className="row"
>
{this.props.elmts.toIndexedSeq().map(function(movie, index) {
const imdbId = movie.get('imdb_id');
const selected = (imdbId === this.props.selectedImdbId) ? true : false;
return (
<ListPoster
index={index}
data={movie}
key={imdbId}
selected={selected}
onClick={() => this.props.onClick(imdbId)}
/>
)
} ,this)}
</InfiniteScroll>
</div>
);
}
return (
<div>
<InfiniteScroll
hasMore={props.hasMore}
loadMore={props.loadMore}
className="row"
>
{props.elmts.map(function(el, index) {
const selected = (el.imdb_id === props.selectedImdbId) ? true : false;
return (
<ListPoster
index={index}
data={el}
key={el.imdb_id}
selected={selected}
onClick={() => props.onClick(el.imdb_id)}
/>
)}
)}
</InfiniteScroll>
</div>
);
}

View File

@ -3,8 +3,8 @@ import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { addTorrent } from '../../actions/torrents'
import { refreshSubtitles } from '../../actions/subtitles'
import { addMovieToWishlist, deleteMovieFromWishlist,
getMovieDetails, selectMovie } from '../../actions/movies'
import { addMovieToWishlist, deleteMovie, deleteMovieFromWishlist,
getMovieDetails, selectMovie, updateFilter } from '../../actions/movies'
import DownloadButton from '../buttons/download'
import SubtitlesButton from '../buttons/subtitles'
@ -14,48 +14,55 @@ import ListPosters from '../list/posters'
import ListDetails from '../list/details'
function mapStateToProps(state) {
return { movieStore: state.movieStore };
return {
loading : state.movieStore.get('loading'),
movies : state.movieStore.get('movies'),
filter : state.movieStore.get('filter'),
selectedImdbId : state.movieStore.get('selectedImdbId'),
lastFetchUrl : state.movieStore.get('lastFetchUrl'),
exploreOptions : state.movieStore.get('exploreOptions'),
};
}
const mapDispatchToProps = (dipatch) =>
bindActionCreators({ selectMovie, getMovieDetails, addTorrent,
addMovieToWishlist, deleteMovieFromWishlist, refreshSubtitles }, dipatch)
addMovieToWishlist, deleteMovie, deleteMovieFromWishlist,
refreshSubtitles, updateFilter }, dipatch)
function MovieButtons(props) {
const imdb_link = `http://www.imdb.com/title/${props.movie.imdb_id}`;
const hasMovie = (props.movie.polochon_url !== "");
const imdb_link = `http://www.imdb.com/title/${props.movie.get('imdb_id')}`;
const hasMovie = (props.movie.get('polochon_url') !== "");
return (
<div className="list-details-buttons btn-toolbar">
<ActionsButton
fetching={props.fetching}
movieId={props.movie.imdb_id}
fetching={props.movie.get('fetchingDetails')}
movieId={props.movie.get('imdb_id')}
getDetails={props.getMovieDetails}
deleteMovie={props.deleteMovie}
hasMovie={hasMovie}
wishlisted={props.movie.wishlisted}
wishlisted={props.movie.get('wishlisted')}
addToWishlist={props.addToWishlist}
deleteFromWishlist={props.deleteFromWishlist}
lastFetchUrl={props.lastFetchUrl}
fetchMovies={props.fetchMovies}
/>
{props.movie.torrents &&
{props.movie.get('torrents') !== null &&
<TorrentsButton
torrents={props.movie.torrents}
torrents={props.movie.get('torrents')}
addTorrent={props.addTorrent}
/>
}
<DownloadButton
url={props.movie.polochon_url}
subtitles={props.movie.subtitles}
url={props.movie.get('polochon_url')}
subtitles={props.movie.get('subtitles')}
/>
<SubtitlesButton
url={props.movie.polochon_url}
subtitles={props.movie.subtitles}
fetching={props.movie.get('fetchingSubtitles')}
url={props.movie.get('polochon_url')}
subtitles={props.movie.get('subtitles')}
refreshSubtitles={props.refreshSubtitles}
resourceID={props.movie.imdb_id}
data={props.movie}
resourceID={props.movie.get('imdb_id')}
type="movie"
/>
@ -71,42 +78,36 @@ class MovieList extends React.Component {
super(props);
}
render() {
const movies = this.props.movieStore.movies;
const selectedMovieId = this.props.movieStore.selectedImdbId;
let index = movies.map((el) => el.imdb_id).indexOf(selectedMovieId);
if (index === -1) {
index = 0;
let selectedMovie = undefined;
if (this.props.movies !== undefined && this.props.movies.has(this.props.selectedImdbId)) {
selectedMovie = this.props.movies.get(this.props.selectedImdbId);
}
const selectedMovie = movies[index];
return (
<div className="row" id="container">
<ListPosters
data={movies}
data={this.props.movies}
type="movies"
formModel="movieStore"
filterControlModel="movieStore.filter"
filterControlPlaceHolder="Filter movies..."
exploreOptions={this.props.movieStore.exploreOptions}
selectedImdbId={selectedMovieId}
filter={this.props.movieStore.filter}
perPage={this.props.movieStore.perPage}
placeHolder="Filter movies..."
exploreOptions={this.props.exploreOptions}
selectedImdbId={this.props.selectedImdbId}
updateFilter={this.props.updateFilter}
filter={this.props.filter}
onClick={this.props.selectMovie}
params={this.props.params}
router={this.props.router}
loading={this.props.movieStore.loading}
loading={this.props.loading}
/>
{selectedMovie &&
{selectedMovie !== undefined &&
<ListDetails data={selectedMovie}>
<MovieButtons
movie={selectedMovie}
fetching={this.props.movieStore.fetchingDetails}
getMovieDetails={this.props.getMovieDetails}
addTorrent={this.props.addTorrent}
deleteMovie={this.props.deleteMovie}
addToWishlist={this.props.addMovieToWishlist}
deleteFromWishlist={this.props.deleteMovieFromWishlist}
lastFetchUrl={this.props.movieStore.lastFetchUrl}
lastFetchUrl={this.props.lastFetchUrl}
refreshSubtitles={this.props.refreshSubtitles}
/>
</ListDetails>

View File

@ -41,20 +41,12 @@ export default class TorrentsButton extends React.Component {
}
function buildMenuItems(torrents) {
// Organise by source
let sources = {}
for (let torrent of torrents) {
if (!sources[torrent.source]) {
sources[torrent.source] = [];
}
sources[torrent.source].push(torrent);
}
const t = torrents.groupBy((el) => el.get('source'));
// Build the array of entries
let entries = [];
let sourceNames = Object.keys(sources);
let dividerCount = sourceNames.length - 1;
for (let source of sourceNames) {
let dividerCount = t.size - 1;
for (let [source, torrentList] of t.entrySeq()) {
// Push the title
entries.push({
type: "header",
@ -62,11 +54,11 @@ function buildMenuItems(torrents) {
});
// Push the torrents
for (let torrent of sources[source]) {
for (let torrent of torrentList) {
entries.push({
type: "entry",
quality: torrent.quality,
url: torrent.url,
quality: torrent.get('quality'),
url: torrent.get('url'),
});
}

View File

@ -1,96 +1,63 @@
const defaultState = {
import { OrderedMap, Map, fromJS } from 'immutable'
const defaultState = Map({
loading: false,
movies: [],
movies: OrderedMap(),
filter: "",
perPage: 30,
selectedImdbId: "",
fetchingDetails: false,
lastFetchUrl: "",
exploreOptions: {},
};
exploreOptions: Map(),
});
export default function movieStore(state = defaultState, action) {
switch (action.type) {
case 'MOVIE_LIST_FETCH_PENDING':
return Object.assign({}, state, {
loading: true,
})
return state.set('loading', true);
case 'MOVIE_LIST_FETCH_FULFILLED':
let movies = Map();
action.payload.response.data.map(function (movie) {
movie.fetchingDetails = false;
movie.fetchingSubtitles = false;
movies = movies.set(movie.imdb_id, fromJS(movie));
})
// Select the first movie if the list is not empty
let selectedImdbId = "";
// Select the first movie
if (action.payload.response.data.length > 0) {
if (movies.size > 0) {
// Sort by year
action.payload.response.data.sort((a,b) => b.year - a.year);
selectedImdbId = action.payload.response.data[0].imdb_id;
}
return Object.assign({}, state, {
movies: action.payload.response.data,
selectedImdbId: selectedImdbId,
filter: defaultState.filter,
perPage: defaultState.perPage,
loading: false,
})
case 'MOVIE_GET_DETAILS_PENDING':
return Object.assign({}, state, {
fetchingDetails: true,
})
case 'MOVIE_GET_DETAILS_FULFILLED':
return Object.assign({}, state, {
movies: updateMovieDetails(state.movies.slice(), action.payload.response.data.imdb_id, action.payload.response.data),
fetchingDetails: false,
})
case 'MOVIE_UPDATE_STORE_WISHLIST':
return Object.assign({}, state, {
movies: updateStoreWishlist(state.movies.slice(), action.payload.imdbId, action.payload.wishlisted),
})
case 'MOVIE_GET_EXPLORE_OPTIONS_FULFILLED':
return Object.assign({}, state, {
exploreOptions: action.payload.response.data,
})
case 'UPDATE_LAST_MOVIE_FETCH_URL':
return Object.assign({}, state, {
lastFetchUrl: action.payload.url,
})
case 'MOVIE_SUBTITLES_UPDATE_PENDING':
return Object.assign({}, state, {
movies: updateMovieSubtitles(state.movies.slice(), state.selectedImdbId, true),
})
case 'MOVIE_SUBTITLES_UPDATE_FULFILLED':
console.log("payload :", action.payload);
return Object.assign({}, state, {
movies: updateMovieSubtitles(state.movies.slice(), state.selectedImdbId, false, action.payload.response.data),
})
case 'SELECT_MOVIE':
// Don't select the movie if we're fetching another movie's details
if (state.fetchingDetails) {
return state
movies = movies.sort((a,b) => b.get('year') - a.get('year'));
selectedImdbId = movies.first().get('imdb_id');
}
return Object.assign({}, state, {
selectedImdbId: action.imdbId,
})
return state.delete('movies').merge(Map({
movies: movies,
filter: "",
loading: false,
selectedImdbId: selectedImdbId,
}))
case 'MOVIE_GET_DETAILS_PENDING':
return state.setIn(['movies', action.payload.main.imdbId, 'fetchingDetails'], true);
case 'MOVIE_GET_DETAILS_FULFILLED':
let movie = action.payload.response.data;
movie.fetchingDetails = false;
movie.fetchingSubtitles = false;
return state.setIn(['movies', movie.imdb_id], fromJS(movie));
case 'MOVIE_UPDATE_STORE_WISHLIST':
return state.setIn(['movies', action.payload.imdbId, 'wishlisted'], action.payload.wishlisted);
case 'MOVIE_GET_EXPLORE_OPTIONS_FULFILLED':
return state.set('exploreOptions', fromJS(action.payload.response.data));
case 'UPDATE_LAST_MOVIE_FETCH_URL':
return state.set('lastFetchUrl', action.payload.url);
case 'MOVIE_SUBTITLES_UPDATE_PENDING':
return state.setIn(['movies', action.payload.main.imdbId, 'fetchingSubtitles'], true);
case 'MOVIE_SUBTITLES_UPDATE_FULFILLED':
return state.setIn(['movies', action.payload.main.imdbId, 'fetchingSubtitles'], false).setIn(['movies', action.payload.main.imdbId, 'subtitles'], fromJS(action.payload.data.response));
case 'SELECT_MOVIE':
return state.set('selectedImdbId', action.payload.imdbId);
case 'MOVIE_UPDATE_FILTER':
return state.set('filter', action.payload.filter);
default:
return state
}
}
function updateMovieDetails(movies, imdbId, data) {
let index = movies.map((el) => el.imdb_id).indexOf(imdbId);
movies[index] = data;
return movies
}
function updateStoreWishlist(movies, imdbId, wishlisted) {
let index = movies.map((el) => el.imdb_id).indexOf(imdbId);
movies[index].wishlisted = wishlisted;
return movies
}
function updateMovieSubtitles(movies, imdbId, fetching, data = null) {
let index = movies.map((el) => el.imdb_id).indexOf(imdbId);
if (data) {
movies[index].subtitles = data;
}
movies[index].fetchingSubtitles = fetching;
return movies
}

View File

@ -38,7 +38,8 @@ export function request(eventPrefix, promise, callbackEvents = null, mainPayload
message: response.data.message,
main: mainPayload,
}
})
});
return;
}
dispatch({
type: fulfilled,

View File

@ -130,7 +130,7 @@ export default function getRoutes(App) {
loginCheck(nextState, replace, next, function() {
var state = store.getState();
// Fetch the explore options
if (Object.keys(state.movieStore.exploreOptions).length === 0) {
if (state.movieStore.get('exploreOptions').size === 0) {
store.dispatch(getMovieExploreOptions());
}
store.dispatch(fetchMovies(