Merge branch 'wishlist' into 'master'

Wishlist

See merge request !36
This commit is contained in:
Lucas 2017-01-24 21:57:13 +00:00
commit f62413d5dc
8 changed files with 255 additions and 75 deletions

View File

@ -124,6 +124,38 @@ export function deleteMovie(imdbId) {
)
}
export function addMovieToWishlist(imdbId) {
return request(
'MOVIE_ADD_TO_WISHLIST',
configureAxios().post(`/wishlist/movies/${imdbId}`),
[
addAlertOk("Movie added to the wishlist"),
updateMovieWishlistStore(imdbId, true),
],
)
}
export function deleteMovieFromWishlist(imdbId) {
return request(
'MOVIE_DELETE_FROM_WISHLIST',
configureAxios().delete(`/wishlist/movies/${imdbId}`),
[
addAlertOk("Movie deleted from the wishlist"),
updateMovieWishlistStore(imdbId, false),
],
)
}
export function updateMovieWishlistStore(imdbId, wishlisted) {
return {
type: 'MOVIE_UPDATE_STORE_WISHLIST',
payload: {
imdbId,
wishlisted,
}
}
}
export function fetchMovies(url) {
return request(
'MOVIE_LIST_FETCH',
@ -156,6 +188,43 @@ export function fetchShowDetails(imdbId) {
)
}
export function addShowToWishlist(imdbId, season = null, episode = null) {
return request(
'SHOW_ADD_TO_WISHLIST',
configureAxios().post(`/wishlist/shows/${imdbId}`, {
season: season,
episode: episode,
}),
[
addAlertOk("Show added to the wishlist"),
updateShowWishlistStore(imdbId, true, season, episode),
],
)
}
export function deleteShowFromWishlist(imdbId) {
return request(
'SHOW_DELETE_FROM_WISHLIST',
configureAxios().delete(`/wishlist/shows/${imdbId}`),
[
addAlertOk("Show deleted from the wishlist"),
updateShowWishlistStore(imdbId, false),
],
)
}
export function updateShowWishlistStore(imdbId, wishlisted, season = null, episode = null) {
return {
type: 'SHOW_UPDATE_STORE_WISHLIST',
payload: {
wishlisted: wishlisted,
imdbId,
season,
episode,
}
}
}
export function selectShow(imdbId) {
return {
type: 'SELECT_SHOW',

View File

@ -0,0 +1,87 @@
import React from 'react'
import { MenuItem } from 'react-bootstrap'
export class WishlistButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
e.preventDefault();
if (this.props.wishlisted) {
this.props.deleteFromWishlist(this.props.resourceId);
} else {
this.props.addToWishlist(this.props.resourceId);
}
}
render() {
if (this.props.wishlisted) {
return (
<MenuItem onClick={this.handleClick}>
<span>
<i className="fa fa-bookmark"></i> Delete from wishlist
</span>
</MenuItem>
);
} else {
return (
<MenuItem onClick={this.handleClick}>
<span>
<i className="fa fa-bookmark-o"></i> Add to wishlist
</span>
</MenuItem>
);
}
}
}
export class DeleteButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
e.preventDefault();
this.props.deleteFunc(this.props.resourceId);
}
render() {
return (
<MenuItem onClick={this.handleClick}>
<span>
<i className="fa fa-trash"></i> Delete
</span>
</MenuItem>
);
}
}
export class RefreshButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
e.preventDefault();
if (this.props.fetching) {
return
}
this.props.getDetails(this.props.resourceId);
}
render() {
return (
<MenuItem onClick={this.handleClick}>
{this.props.fetching ||
<span>
<i className="fa fa-refresh"></i> Refresh
</span>
}
{this.props.fetching &&
<span>
<i className="fa fa-spin fa-refresh"></i> Refreshing
</span>
}
</MenuItem>
);
}
}

View File

@ -1,72 +1,29 @@
import React from 'react'
import { DropdownButton, MenuItem } from 'react-bootstrap'
import { WishlistButton, DeleteButton, RefreshButton } from '../buttons/actions'
import { DropdownButton } from 'react-bootstrap'
export default function ActionsButton(props) {
return (
<DropdownButton className="btn btn-default btn-sm" title="Actions" id="actions-button" dropup>
<RefreshButton
fetching={props.fetching}
movieId={props.movieId}
resourceId={props.movieId}
getDetails={props.getDetails}
/>
{(props.isUserAdmin && props.hasMovie) &&
<DeleteButton
movieId={props.movieId}
deleteMovie={props.deleteMovie}
resourceId={props.movieId}
deleteFunc={props.deleteMovie}
isUserAdmin={props.isUserAdmin}
/>
}
<WishlistButton
resourceId={props.movieId}
wishlisted={props.wishlisted}
addToWishlist={props.addToWishlist}
deleteFromWishlist={props.deleteFromWishlist}
/>
</DropdownButton>
);
}
class RefreshButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
e.preventDefault();
if (this.props.fetching) {
return
}
this.props.getDetails(this.props.movieId);
}
render() {
return (
<MenuItem onClick={this.handleClick}>
{this.props.fetching ||
<span>
<i className="fa fa-refresh"></i> Refresh
</span>
}
{this.props.fetching &&
<span>
<i className="fa fa-spin fa-refresh"></i> Refreshing
</span>
}
</MenuItem>
);
}
}
class DeleteButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
e.preventDefault();
this.props.deleteMovie(this.props.movieId);
}
render() {
return (
<MenuItem onClick={this.handleClick}>
<span>
<i className="fa fa-trash"></i> Delete
</span>
</MenuItem>
);
}
}

View File

@ -31,6 +31,9 @@ function MovieButtons(props) {
deleteMovie={props.deleteMovie}
isUserAdmin={props.isUserAdmin}
hasMovie={hasMovie}
wishlisted={props.movie.wishlisted}
addToWishlist={props.addToWishlist}
deleteFromWishlist={props.deleteFromWishlist}
/>
<a type="button" className="btn btn-warning btn-sm" href={imdb_link}>
@ -97,6 +100,8 @@ export default class MovieList extends React.Component {
addTorrent={this.props.addTorrent}
deleteMovie={this.props.deleteMovie}
isUserAdmin={this.props.userStore.isAdmin}
addToWishlist={this.props.addMovieToWishlist}
deleteFromWishlist={this.props.deleteMovieFromWishlist}
/>
</ListDetails>
}

View File

@ -1,23 +1,9 @@
import React from 'react'
import { Link } from 'react-router'
import ListDetails from '../list/details'
import ListPosters from '../list/posters'
import Loader from '../loader/loader'
function ShowButtons(props) {
const imdbLink = `http://www.imdb.com/title/${props.show.imdb_id}`;
return (
<div className="list-details-buttons btn-toolbar">
<a type="button" className="btn btn-warning btn-sm" href={imdbLink}>
<i className="fa fa-external-link"></i> IMDB
</a>
<Link type="button" className="btn btn-primary btn-sm" to={"/shows/details/" + props.show.imdb_id}>
<i className="fa fa-external-link"></i> Details
</Link>
</div>
);
}
import ShowButtons from './listButtons'
export default class ShowList extends React.Component {
componentWillMount() {
@ -68,7 +54,11 @@ export default class ShowList extends React.Component {
/>
{selectedShow &&
<ListDetails data={selectedShow} >
<ShowButtons show={selectedShow} />
<ShowButtons
show={selectedShow}
deleteFromWishlist={this.props.deleteShowFromWishlist}
addToWishlist={this.props.addShowToWishlist}
/>
</ListDetails>
}
</div>

View File

@ -0,0 +1,39 @@
import React from 'react'
import { Link } from 'react-router'
import { DropdownButton } from 'react-bootstrap'
import { WishlistButton } from '../buttons/actions'
export default function ShowButtons(props) {
const imdbLink = `http://www.imdb.com/title/${props.show.imdb_id}`;
return (
<div className="list-details-buttons btn-toolbar">
<ActionsButton
show={props.show}
addToWishlist={props.addToWishlist}
deleteFromWishlist={props.deleteFromWishlist}
/>
<a type="button" className="btn btn-warning btn-sm" href={imdbLink}>
<i className="fa fa-external-link"></i> IMDB
</a>
<Link type="button" className="btn btn-primary btn-sm" to={"/shows/details/" + props.show.imdb_id}>
<i className="fa fa-external-link"></i> Details
</Link>
</div>
);
}
function ActionsButton(props) {
let wishlisted = (props.show.tracked_season !== null && props.show.tracked_episode !== null);
return (
<DropdownButton className="btn btn-default btn-sm" title="Actions" id="actions-button" dropup>
<WishlistButton
resourceId={props.show.imdb_id}
wishlisted={wishlisted}
addToWishlist={props.addToWishlist}
deleteFromWishlist={props.deleteFromWishlist}
/>
</DropdownButton>
);
}

View File

@ -39,17 +39,17 @@ export default function movieStore(state = defaultState, action) {
fetchingDetails: true,
})
case 'MOVIE_GET_DETAILS_FULFILLED':
let movies = state.movies.slice();
let index = movies.map((el) => el.imdb_id).indexOf(action.payload.data.imdb_id);
movies[index] = action.payload.data;
return Object.assign({}, state, {
movies: movies,
movies: updateMovieDetails(state.movies.slice(), action.payload.data.imdb_id, action.payload.data),
fetchingDetails: false,
})
case 'MOVIE_UPDATE_STORE_WISHLIST':
return Object.assign({}, state, {
movies: updateStoreWishlist(state.movies.slice(), action.payload.imdbId, action.payload.wishlisted),
})
case 'DELETE_MOVIE':
return Object.assign({}, state, {
movies: state.movies.filter((e) => (e.imdb_id !== action.imdbId)),
fetchingDetails: false,
})
case 'SELECT_MOVIE':
// Don't select the movie if we're fetching another movie's details
@ -64,3 +64,15 @@ export default function movieStore(state = defaultState, action) {
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
}

View File

@ -45,6 +45,10 @@ export default function showStore(state = defaultState, action) {
shows: action.payload.data,
loading: false,
})
case 'SHOW_UPDATE_STORE_WISHLIST':
return Object.assign({}, state, {
shows: updateStoreWishlist(state.shows.slice(), action.payload),
})
case 'SELECT_SHOW':
// Don't select the show if we're fetching another show's details
if (state.fetchingDetails) {
@ -102,3 +106,20 @@ function sortEpisodes(show) {
return show;
}
function updateStoreWishlist(shows, payload) {
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
}