Merge branch 'search' into 'master'

Search

See merge request !30
This commit is contained in:
Lucas 2017-01-09 13:14:44 +00:00
commit bc223da3d0
16 changed files with 300 additions and 31 deletions

View File

@ -16,6 +16,7 @@
"react": "^15.3.2", "react": "^15.3.2",
"react-bootstrap": "^0.30.6", "react-bootstrap": "^0.30.6",
"react-dom": "^15.3.2", "react-dom": "^15.3.2",
"react-loading": "^0.0.9",
"react-redux": "^4.4.6", "react-redux": "^4.4.6",
"react-redux-form": "^1.2.4", "react-redux-form": "^1.2.4",
"react-router": "^3.0.0", "react-router": "^3.0.0",

View File

@ -2,11 +2,14 @@ package extmedias
import ( import (
"database/sql" "database/sql"
"errors"
"fmt" "fmt"
"net/http" "net/http"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/auth"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/movies" "gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/movies"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/shows" "gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/shows"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/users"
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web" "gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web"
@ -89,12 +92,19 @@ func GetMediaIDs(env *web.Env, mediaType string, source string, category string,
} }
// GetMovies get some movies // GetMovies get some movies
func GetMovies(env *web.Env, source string, category string, force bool) ([]*movies.Movie, error) { func GetMovies(env *web.Env, user *users.User, source string, category string, force bool) ([]*movies.Movie, error) {
movieIds, err := GetMediaIDs(env, "movie", source, category, force) movieIds, err := GetMediaIDs(env, "movie", source, category, force)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Get the URLs from polochon, we don't really care if it fails for now
var urls map[string]string
urls, err = movies.GetPolochonMoviesURLs(user)
if err != nil {
env.Log.Errorf("error while getting polochon movies url: %s", err)
}
movieList := []*movies.Movie{} movieList := []*movies.Movie{}
for _, id := range movieIds { for _, id := range movieIds {
movie := movies.New(id) movie := movies.New(id)
@ -108,6 +118,13 @@ func GetMovies(env *web.Env, source string, category string, force bool) ([]*mov
env.Log.Errorf("error while getting movie torrents : %s", err) env.Log.Errorf("error while getting movie torrents : %s", err)
continue continue
} }
if urls != nil {
if url, ok := urls[id]; ok {
movie.PolochonURL = url
}
}
movieList = append(movieList, movie) movieList = append(movieList, movie)
} }
return movieList, nil return movieList, nil
@ -157,10 +174,16 @@ func Explore(env *web.Env, w http.ResponseWriter, r *http.Request) error {
category = "popular" category = "popular"
} }
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return env.RenderError(w, errors.New("invalid user"))
}
// Get the medias without trying to refresh them // Get the medias without trying to refresh them
movies, err := GetMovies(env, source, category, false) movies, err := GetMovies(env, user, source, category, false)
if err != nil { if err != nil {
return err return env.RenderError(w, err)
} }
return env.RenderJSON(w, movies) return env.RenderJSON(w, movies)
@ -188,7 +211,7 @@ func ExploreShows(env *web.Env, w http.ResponseWriter, r *http.Request) error {
// Get the medias without trying to refresh them // Get the medias without trying to refresh them
shows, err := GetShows(env, source, category, false) shows, err := GetShows(env, source, category, false)
if err != nil { if err != nil {
return err return env.RenderError(w, err)
} }
return env.RenderJSON(w, shows) return env.RenderJSON(w, shows)
@ -218,13 +241,19 @@ func Refresh(env *web.Env, w http.ResponseWriter, r *http.Request) error {
category = "popular" category = "popular"
} }
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return fmt.Errorf("invalid user type")
}
// We'll refresh the medias for each sources // We'll refresh the medias for each sources
for _, source := range MediaSources { for _, source := range MediaSources {
env.Log.Debugf("refreshing %s", source) env.Log.Debugf("refreshing %s", source)
// GetMedias and refresh them // GetMedias and refresh them
_, err := GetMovies(env, source, category, true) _, err := GetMovies(env, user, source, category, true)
if err != nil { if err != nil {
return err return env.RenderError(w, err)
} }
} }
@ -250,7 +279,7 @@ func RefreshShows(env *web.Env, w http.ResponseWriter, r *http.Request) error {
// GetMedias and refresh them // GetMedias and refresh them
_, err := GetShows(env, source, category, true) _, err := GetShows(env, source, category, true)
if err != nil { if err != nil {
return err return env.RenderError(w, err)
} }
} }

View File

@ -1,6 +1,7 @@
package movies package movies
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"net" "net"
@ -63,6 +64,21 @@ func getPolochonMovies(user *users.User) ([]*Movie, error) {
return movies, nil return movies, nil
} }
// GetPolochonMoviesURLs returns the polochon urls associated with an imdb id
func GetPolochonMoviesURLs(user *users.User) (map[string]string, error) {
movies, err := getPolochonMovies(user)
if err != nil {
return nil, err
}
urls := make(map[string]string, len(movies))
for _, movie := range movies {
urls[movie.ImdbID] = movie.PolochonURL
}
return urls, nil
}
// FromPolochon will returns movies from Polochon // FromPolochon will returns movies from Polochon
func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error { func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error {
v := auth.GetCurrentUser(r, env.Log) v := auth.GetCurrentUser(r, env.Log)
@ -113,15 +129,28 @@ func GetDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) err
// SearchMovie will search movie // SearchMovie will search movie
func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error { func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error {
key := r.FormValue("key") var data struct {
if key == "" { Key string `json:"key"`
}
err := json.NewDecoder(r.Body).Decode(&data)
if err != nil {
return env.RenderError(w, errors.New("failed to get the search key"))
}
if data.Key == "" {
return env.RenderError(w, errors.New("no given key")) return env.RenderError(w, errors.New("no given key"))
} }
v := auth.GetCurrentUser(r, env.Log)
user, ok := v.(*users.User)
if !ok {
return env.RenderError(w, errors.New("invalid user"))
}
var movies []*polochon.Movie var movies []*polochon.Movie
searchers := env.Config.MovieSearchers searchers := env.Config.MovieSearchers
for _, searcher := range searchers { for _, searcher := range searchers {
result, err := searcher.SearchMovie(key, env.Log) result, err := searcher.SearchMovie(data.Key, env.Log)
if err != nil { if err != nil {
env.Log.Errorf("error while searching movie : %s", err) env.Log.Errorf("error while searching movie : %s", err)
continue continue
@ -129,7 +158,14 @@ func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error {
movies = append(movies, result...) movies = append(movies, result...)
} }
env.Log.Debugf("got %d movies doing search %q", len(movies), key) // Get the URLs from polochon, we don't really care if it fails for now
var urls map[string]string
urls, err = GetPolochonMoviesURLs(user)
if err != nil {
env.Log.Errorf("error while getting polochon movies url: %s", err)
}
env.Log.Debugf("got %d movies doing search %q", len(movies), data.Key)
movieList := []*Movie{} movieList := []*Movie{}
for _, m := range movies { for _, m := range movies {
movie := New(m.ImdbID) movie := New(m.ImdbID)
@ -143,6 +179,13 @@ func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error {
env.Log.Errorf("error while getting movie torrents : %s", err) env.Log.Errorf("error while getting movie torrents : %s", err)
continue continue
} }
if urls != nil {
if url, ok := urls[m.ImdbID]; ok {
movie.PolochonURL = url
}
}
movieList = append(movieList, movie) movieList = append(movieList, movie)
} }

View File

@ -1,6 +1,7 @@
package shows package shows
import ( import (
"encoding/json"
"errors" "errors"
"net/http" "net/http"
@ -27,15 +28,21 @@ func GetDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) err
// SearchShow will search a show // SearchShow will search a show
func SearchShow(env *web.Env, w http.ResponseWriter, r *http.Request) error { func SearchShow(env *web.Env, w http.ResponseWriter, r *http.Request) error {
key := r.FormValue("key") var data struct {
if key == "" { Key string `json:"key"`
}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
return env.RenderError(w, errors.New("failed to get the search key"))
}
if data.Key == "" {
return env.RenderError(w, errors.New("no given key")) return env.RenderError(w, errors.New("no given key"))
} }
var shows []*polochon.Show var shows []*polochon.Show
searchers := env.Config.ShowSearchers searchers := env.Config.ShowSearchers
for _, searcher := range searchers { for _, searcher := range searchers {
result, err := searcher.SearchShow(key, env.Log) result, err := searcher.SearchShow(data.Key, env.Log)
if err != nil { if err != nil {
env.Log.Errorf("error while searching show : %s", err) env.Log.Errorf("error while searching show : %s", err)
continue continue
@ -43,7 +50,7 @@ func SearchShow(env *web.Env, w http.ResponseWriter, r *http.Request) error {
shows = append(shows, result...) shows = append(shows, result...)
} }
env.Log.Debugf("got %d shows doing search %q", len(shows), key) env.Log.Debugf("got %d shows doing search %q", len(shows), data.Key)
showList := []*Show{} showList := []*Show{}
for _, s := range shows { for _, s := range shows {
show := New(s.ImdbID) show := New(s.ImdbID)

View File

@ -71,22 +71,24 @@ func main() {
authMiddleware := auth.NewMiddleware(env.Auth, log) authMiddleware := auth.NewMiddleware(env.Auth, log)
// TODO: refresh sould be handled by admins only
env.Handle("/users/login", users.LoginPOSTHandler).Methods("POST") env.Handle("/users/login", users.LoginPOSTHandler).Methods("POST")
env.Handle("/users/signup", users.SignupPOSTHandler).Methods("POST") env.Handle("/users/signup", users.SignupPOSTHandler).Methods("POST")
env.Handle("/users/details", users.DetailsHandler).WithRole(users.UserRole) env.Handle("/users/details", users.DetailsHandler).WithRole(users.UserRole).Methods("GET")
env.Handle("/users/edit", users.EditHandler).WithRole(users.UserRole) env.Handle("/users/edit", users.EditHandler).WithRole(users.UserRole).Methods("POST")
env.Handle("/movies/polochon", movies.FromPolochon).WithRole(users.UserRole) env.Handle("/movies/polochon", movies.FromPolochon).WithRole(users.UserRole).Methods("GET")
env.Handle("/movies/{id:tt[0-9]+}/get_details", movies.GetDetailsHandler).WithRole(users.UserRole) env.Handle("/movies/{id:tt[0-9]+}/get_details", movies.GetDetailsHandler).WithRole(users.UserRole).Methods("GET")
env.Handle("/movies/explore", extmedias.Explore) env.Handle("/movies/explore", extmedias.Explore).WithRole(users.UserRole).Methods("GET")
env.Handle("/movies/refresh", extmedias.Refresh) env.Handle("/movies/refresh", extmedias.Refresh).WithRole(users.UserRole).Methods("POST")
env.Handle("/movies/search", movies.SearchMovie) env.Handle("/movies/search", movies.SearchMovie).WithRole(users.UserRole).Methods("POST")
// env.Handle("/shows/polochon", shows.FromPolochon).WithRole(users.UserRole) // env.Handle("/shows/polochon", shows.FromPolochon).WithRole(users.UserRole)
env.Handle("/shows/{id:tt[0-9]+}", shows.GetDetailsHandler) env.Handle("/shows/{id:tt[0-9]+}", shows.GetDetailsHandler).WithRole(users.UserRole).Methods("GET")
env.Handle("/shows/refresh", extmedias.RefreshShows) env.Handle("/shows/refresh", extmedias.RefreshShows).WithRole(users.UserRole).Methods("POST")
env.Handle("/shows/explore", extmedias.ExploreShows) env.Handle("/shows/explore", extmedias.ExploreShows).WithRole(users.UserRole).Methods("GET")
env.Handle("/shows/search", shows.SearchShow) env.Handle("/shows/search", shows.SearchShow).WithRole(users.UserRole).Methods("POST")
n := negroni.Classic() n := negroni.Classic()
n.Use(authMiddleware) n.Use(authMiddleware)

View File

@ -80,6 +80,13 @@ export function selectMovie(imdbId) {
} }
} }
export function searchMovies(search) {
return request(
'SEARCH_MOVIES',
configureAxios().post('/movies/search', search)
)
}
export function getMovieDetails(imdbId) { export function getMovieDetails(imdbId) {
return request( return request(
'MOVIE_GET_DETAILS', 'MOVIE_GET_DETAILS',
@ -105,6 +112,13 @@ export function fetchShows(url) {
) )
} }
export function searchShows(search) {
return request(
'SEARCH_SHOWS',
configureAxios().post('/shows/search', search)
)
}
export function fetchShowDetails(imdbId) { export function fetchShowDetails(imdbId) {
return request( return request(
'SHOW_FETCH_DETAILS', 'SHOW_FETCH_DETAILS',

View File

@ -83,14 +83,19 @@ const MovieListPopular = (props) => (
const MovieListPolochon = (props) => ( const MovieListPolochon = (props) => (
<MovieList {...props} moviesUrl='/movies/polochon'/> <MovieList {...props} moviesUrl='/movies/polochon'/>
) )
const MovieListSearch = (props) => (
<MovieList {...props} />
)
const ShowListPopular = (props) => ( const ShowListPopular = (props) => (
<ShowList {...props} showsUrl='/shows/explore'/> <ShowList {...props} showsUrl='/shows/explore'/>
) )
const ShowDetailsView = (props) => ( const ShowDetailsView = (props) => (
<ShowDetails {...props} /> <ShowDetails {...props} />
) )
const ShowListSearch = (props) => (
<ShowList {...props} />
)
ReactDOM.render(( ReactDOM.render((
<Provider store={store}> <Provider store={store}>
@ -100,8 +105,10 @@ ReactDOM.render((
<Route path="/users/login" component={UserLoginForm} /> <Route path="/users/login" component={UserLoginForm} />
<Route path="/users/signup" component={UserSignUp} /> <Route path="/users/signup" component={UserSignUp} />
<Route path="/users/edit" component={UserIsAuthenticated(UserEdit)} /> <Route path="/users/edit" component={UserIsAuthenticated(UserEdit)} />
<Route path="/movies/search/:search" component={UserIsAuthenticated(MovieListSearch)} />
<Route path="/movies/popular" component={UserIsAuthenticated(MovieListPopular)} /> <Route path="/movies/popular" component={UserIsAuthenticated(MovieListPopular)} />
<Route path="/movies/polochon(/:page)" component={UserIsAuthenticated(MovieListPolochon)} /> <Route path="/movies/polochon(/:page)" component={UserIsAuthenticated(MovieListPolochon)} />
<Route path="/shows/search/:search" component={UserIsAuthenticated(ShowListSearch)} />
<Route path="/shows/popular" component={UserIsAuthenticated(ShowListPopular)} /> <Route path="/shows/popular" component={UserIsAuthenticated(ShowListPopular)} />
<Route path="/shows/details/:imdbId" component={UserIsAuthenticated(ShowDetailsView)} /> <Route path="/shows/details/:imdbId" component={UserIsAuthenticated(ShowDetailsView)} />
</Route> </Route>

View File

@ -1,6 +1,10 @@
import React from 'react' import React from 'react'
export default function ListDetails(props) { export default function ListDetails(props) {
let genres;
if (props.data.genres) {
genres = props.data.genres.join(', ');
}
return ( return (
<div className="col-xs-7 col-md-4"> <div className="col-xs-7 col-md-4">
<div className="show-detail affix"> <div className="show-detail affix">
@ -12,6 +16,12 @@ export default function ListDetails(props) {
&nbsp;{props.data.runtime} min &nbsp;{props.data.runtime} min
</p> </p>
} }
{props.data.genres &&
<p>
<i className="fa fa-tags"></i>
&nbsp;{genres}
</p>
}
<p> <p>
<i className="fa fa-star-o"></i> <i className="fa fa-star-o"></i>
&nbsp;{props.data.rating} <small>({props.data.votes} counts)</small> &nbsp;{props.data.rating} <small>({props.data.votes} counts)</small>

View File

@ -0,0 +1,17 @@
import React from 'react'
import Loading from 'react-loading'
export default function Loader() {
return (
<div className="row" id="container">
<div className="col-md-6 col-md-offset-3">
<Loading
type="bars"
height="100%"
width="100%"
color="#EBEBEB"
/>
</div>
</div>
)
}

View File

@ -2,6 +2,7 @@ import React from 'react'
import ListPosters from '../list/posters' import ListPosters from '../list/posters'
import ListDetails from '../list/details' import ListDetails from '../list/details'
import Loader from '../loader/loader'
class MovieButtons extends React.Component { class MovieButtons extends React.Component {
constructor(props) { constructor(props) {
@ -53,7 +54,24 @@ class MovieButtons extends React.Component {
export default class MovieList extends React.Component { export default class MovieList extends React.Component {
componentWillMount() { componentWillMount() {
if (this.props.moviesUrl) {
this.props.fetchMovies(this.props.moviesUrl); this.props.fetchMovies(this.props.moviesUrl);
} else if (this.props.params && this.props.params.search != "") {
this.props.searchMovies({
key: this.props.params.search
});
}
}
componentWillUpdate(nextProps, nextState) {
if (!nextProps.params || nextProps.params.search === "") {
return
}
if (this.props.params.search === nextProps.params.search) {
return
}
this.props.searchMovies({
key: nextProps.params.search
});
} }
render() { render() {
const movies = this.props.movieStore.movies; const movies = this.props.movieStore.movies;
@ -63,6 +81,12 @@ export default class MovieList extends React.Component {
index = 0; index = 0;
} }
const selectedMovie = movies[index]; const selectedMovie = movies[index];
// Loading
if (this.props.movieStore.loading) {
return (<Loader />);
}
return ( return (
<div className="row" id="container"> <div className="row" id="container">
<ListPosters <ListPosters

View File

@ -1,15 +1,37 @@
import React from 'react' import React from 'react'
import { Link } from 'react-router'
import { store } from '../store' import { store } from '../store'
import { isUserLoggedIn } from '../actions/actionCreators' import { isUserLoggedIn } from '../actions/actionCreators'
import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap' import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'
import { LinkContainer } from 'react-router-bootstrap' import { LinkContainer } from 'react-router-bootstrap'
import { Control, Form } from 'react-redux-form';
export default class NavBar extends React.Component { export default class NavBar extends React.Component {
constructor(props) {
super(props);
this.handleMovieSearch = this.handleMovieSearch.bind(this);
this.handleShowSearch = this.handleShowSearch.bind(this);
}
handleMovieSearch() {
this.props.router.push(`/movies/search/${encodeURI(this.props.movieStore.search)}`)
}
handleShowSearch() {
this.props.router.push(`/shows/search/${encodeURI(this.props.showStore.search)}`)
}
render() { render() {
const username = this.props.userStore.username; const username = this.props.userStore.username;
const isLoggedIn = username !== "" ? true : false; const isLoggedIn = username !== "" ? true : false;
const location = this.props.router.getCurrentLocation().pathname;
let displayMovieSearch = false;
let displayShowSearch = false;
if (isLoggedIn && location.indexOf("movies") > -1)
{
displayMovieSearch = true;
}
if (isLoggedIn && location.indexOf("shows") > -1)
{
displayShowSearch = true;
}
return ( return (
<div> <div>
<Navbar fluid fixedTop collapseOnSelect> <Navbar fluid fixedTop collapseOnSelect>
@ -53,6 +75,30 @@ export default class NavBar extends React.Component {
</NavDropdown> </NavDropdown>
} }
</Nav> </Nav>
{displayMovieSearch &&
<Navbar.Form pullRight>
<Form model="movieStore" className="input-group" onSubmit={() => this.handleMovieSearch()}>
<Control.text
model="movieStore.search"
className="form-control"
placeholder="Search movies"
updateOn="change"
/>
</Form>
</Navbar.Form>
}
{displayShowSearch &&
<Navbar.Form pullRight>
<Form model="showStore" className="input-group" onSubmit={() => this.handleShowSearch()}>
<Control.text
model="showStore.search"
className="form-control"
placeholder="Search shows"
updateOn="change"
/>
</Form>
</Navbar.Form>
}
</Navbar.Collapse> </Navbar.Collapse>
</Navbar> </Navbar>
</div> </div>

View File

@ -1,10 +1,15 @@
import React from 'react' import React from 'react'
import Loader from '../loader/loader'
export default class ShowDetails extends React.Component { export default class ShowDetails extends React.Component {
componentWillMount() { componentWillMount() {
this.props.fetchShowDetails(this.props.params.imdbId); this.props.fetchShowDetails(this.props.params.imdbId);
} }
render() { render() {
// Loading
if (this.props.showStore.loading) {
return (<Loader />);
}
return ( return (
<div className="row" id="container"> <div className="row" id="container">
<Header data={this.props.showStore.show} /> <Header data={this.props.showStore.show} />

View File

@ -3,6 +3,7 @@ import { Link } from 'react-router'
import ListDetails from '../list/details' import ListDetails from '../list/details'
import ListPosters from '../list/posters' import ListPosters from '../list/posters'
import Loader from '../loader/loader'
function ShowButtons(props) { function ShowButtons(props) {
const imdbLink = `http://www.imdb.com/title/${props.show.imdb_id}`; const imdbLink = `http://www.imdb.com/title/${props.show.imdb_id}`;
@ -20,7 +21,24 @@ function ShowButtons(props) {
export default class ShowList extends React.Component { export default class ShowList extends React.Component {
componentWillMount() { componentWillMount() {
if (this.props.showsUrl) {
this.props.fetchShows(this.props.showsUrl); this.props.fetchShows(this.props.showsUrl);
} else if (this.props.params && this.props.params.search != "") {
this.props.searchShows({
key: this.props.params.search
});
}
}
componentWillUpdate(nextProps, nextState) {
if (!nextProps.params || nextProps.params.search === "") {
return
}
if (this.props.params.search === nextProps.params.search) {
return
}
this.props.searchShows({
key: nextProps.params.search
});
} }
render() { render() {
const shows = this.props.showStore.shows; const shows = this.props.showStore.shows;
@ -30,6 +48,12 @@ export default class ShowList extends React.Component {
index = 0; index = 0;
} }
const selectedShow = shows[index]; const selectedShow = shows[index];
// Loading
if (this.props.showStore.loading) {
return (<Loader />);
}
return ( return (
<div className="row" id="container"> <div className="row" id="container">
<ListPosters <ListPosters

View File

@ -1,13 +1,19 @@
const defaultState = { const defaultState = {
loading: false,
movies: [], movies: [],
filter: "", filter: "",
perPage: 30, perPage: 30,
selectedImdbId: "", selectedImdbId: "",
fetchingDetails: false, fetchingDetails: false,
search: "",
}; };
export default function movieStore(state = defaultState, action) { export default function movieStore(state = defaultState, action) {
switch (action.type) { switch (action.type) {
case 'MOVIE_LIST_FETCH_PENDING':
return Object.assign({}, state, {
loading: true,
})
case 'MOVIE_LIST_FETCH_FULFILLED': case 'MOVIE_LIST_FETCH_FULFILLED':
let selectedImdbId = ""; let selectedImdbId = "";
// Select the first movie // Select the first movie
@ -17,6 +23,16 @@ export default function movieStore(state = defaultState, action) {
return Object.assign({}, state, { return Object.assign({}, state, {
movies: action.payload.data, movies: action.payload.data,
selectedImdbId: selectedImdbId, selectedImdbId: selectedImdbId,
loading: false,
})
case 'SEARCH_MOVIES_PENDING':
return Object.assign({}, state, {
loading: true,
})
case 'SEARCH_MOVIES_FULFILLED':
return Object.assign({}, state, {
movies: action.payload.data,
loading: false,
}) })
case 'MOVIE_GET_DETAILS_PENDING': case 'MOVIE_GET_DETAILS_PENDING':
return Object.assign({}, state, { return Object.assign({}, state, {

View File

@ -1,4 +1,5 @@
const defaultState = { const defaultState = {
loading: false,
shows: [], shows: [],
filter: "", filter: "",
perPage: 30, perPage: 30,
@ -6,10 +7,15 @@ const defaultState = {
show: { show: {
seasons: [], seasons: [],
}, },
search: "",
}; };
export default function showStore(state = defaultState, action) { export default function showStore(state = defaultState, action) {
switch (action.type) { switch (action.type) {
case 'SHOW_LIST_FETCH_PENDING':
return Object.assign({}, state, {
loading: true,
})
case 'SHOW_LIST_FETCH_FULFILLED': case 'SHOW_LIST_FETCH_FULFILLED':
let selectedImdbId = ""; let selectedImdbId = "";
// Select the first show // Select the first show
@ -19,12 +25,26 @@ export default function showStore(state = defaultState, action) {
return Object.assign({}, state, { return Object.assign({}, state, {
shows: action.payload.data, shows: action.payload.data,
selectedImdbId: selectedImdbId, selectedImdbId: selectedImdbId,
loading: false,
})
case 'SHOW_FETCH_DETAILS_PENDING':
return Object.assign({}, state, {
loading: true,
}) })
case 'SHOW_FETCH_DETAILS_FULFILLED': case 'SHOW_FETCH_DETAILS_FULFILLED':
return Object.assign({}, state, { return Object.assign({}, state, {
show: sortEpisodes(action.payload.data), show: sortEpisodes(action.payload.data),
loading: false,
})
case 'SEARCH_SHOWS_PENDING':
return Object.assign({}, state, {
loading: true,
})
case 'SEARCH_SHOWS_FULFILLED':
return Object.assign({}, state, {
shows: action.payload.data,
loading: false,
}) })
return state;
case 'SELECT_SHOW': case 'SELECT_SHOW':
// Don't select the show if we're fetching another show's details // Don't select the show if we're fetching another show's details
if (state.fetchingDetails) { if (state.fetchingDetails) {

View File

@ -3081,6 +3081,10 @@ react-dom@^15.3.2:
version "15.3.2" version "15.3.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.3.2.tgz#c46b0aa5380d7b838e7a59c4a7beff2ed315531f" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.3.2.tgz#c46b0aa5380d7b838e7a59c4a7beff2ed315531f"
react-loading:
version "0.0.9"
resolved "https://registry.yarnpkg.com/react-loading/-/react-loading-0.0.9.tgz#e9fba6948915ba7742a508193828b6c73eb04956"
react-overlays@^0.6.10: react-overlays@^0.6.10:
version "0.6.10" version "0.6.10"
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.6.10.tgz#e7e52dad47f00a0fc784eb044428c3a9e874bfa3" resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.6.10.tgz#e7e52dad47f00a0fc784eb044428c3a9e874bfa3"