From 421605bb382a096b0fd36751f37d1bbabeaac87c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?=
Date: Sat, 17 Dec 2016 19:26:20 +0100
Subject: [PATCH] Add a detailed view of the seasons/episodes of a show
---
src/public/js/actions/actionCreators.js | 7 ++
src/public/js/app.js | 6 +
src/public/js/components/list/details.js | 2 +-
src/public/js/components/shows/details.js | 145 ++++++++++++++++++++++
src/public/js/components/shows/list.js | 8 +-
src/public/js/reducers/shows.js | 52 ++++++++
src/public/less/app.less | 14 ++-
7 files changed, 230 insertions(+), 4 deletions(-)
create mode 100644 src/public/js/components/shows/details.js
diff --git a/src/public/js/actions/actionCreators.js b/src/public/js/actions/actionCreators.js
index 3603633..e0c1665 100644
--- a/src/public/js/actions/actionCreators.js
+++ b/src/public/js/actions/actionCreators.js
@@ -105,6 +105,13 @@ export function fetchShows(url) {
)
}
+export function fetchShowDetails(imdbId) {
+ return request(
+ 'SHOW_FETCH_DETAILS',
+ configureAxios().get(`/shows/${imdbId}`)
+ )
+}
+
export function selectShow(imdbId) {
return {
type: 'SELECT_SHOW',
diff --git a/src/public/js/app.js b/src/public/js/app.js
index c82d250..b75f21e 100644
--- a/src/public/js/app.js
+++ b/src/public/js/app.js
@@ -30,6 +30,7 @@ import NavBar from './components/navbar'
import Error from './components/errors'
import MovieList from './components/movies/list'
import ShowList from './components/shows/list'
+import ShowDetails from './components/shows/details'
import UserLoginForm from './components/users/login'
import UserEdit from './components/users/edit'
import UserSignUp from './components/users/signup'
@@ -87,6 +88,10 @@ const ShowListPopular = (props) => (
)
+const ShowDetailsView = (props) => (
+
+)
+
ReactDOM.render((
@@ -98,6 +103,7 @@ ReactDOM.render((
+
diff --git a/src/public/js/components/list/details.js b/src/public/js/components/list/details.js
index ef5945a..12ca5e8 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) {
{props.data.rating} ({props.data.votes} counts)
- {props.data.plot}
+ {props.data.plot}
{props.children}
diff --git a/src/public/js/components/shows/details.js b/src/public/js/components/shows/details.js
new file mode 100644
index 0000000..9f33991
--- /dev/null
+++ b/src/public/js/components/shows/details.js
@@ -0,0 +1,145 @@
+import React from 'react'
+
+export default class ShowDetails extends React.Component {
+ componentWillMount() {
+ this.props.fetchShowDetails(this.props.params.imdbId);
+ }
+ render() {
+ return (
+
+
+
+
+ );
+ }
+}
+
+function Header(props){
+ return (
+
+ );
+}
+
+function HeaderThumbnail(props){
+ return (
+
+

+
+ );
+}
+
+function HeaderDetails(props){
+ const imdbLink = `http://www.imdb.com/title/${props.data.imdb_id}`;
+ return (
+
+
+ - Title
+ - {props.data.title}
+ - Plot
+ - {props.data.plot}
+ - IMDB
+ -
+
+ Open in IMDB
+
+
+ - Year
+ - {props.data.year}
+ - Rating
+ - {props.data.rating}
+
+
+ );
+}
+
+function SeasonsList(props){
+ return (
+
+ {props.data.seasons.length > 0 && props.data.seasons.map(function(season, index) {
+ return (
+
+
+
+ )
+ })}
+
+ )
+}
+
+class Season extends React.Component {
+ constructor(props) {
+ super(props);
+ this.handleClick = this.handleClick.bind(this);
+ this.state = { colapsed: true };
+ }
+ handleClick(e) {
+ e.preventDefault();
+ this.setState({ colapsed: !this.state.colapsed });
+ }
+ render() {
+ return (
+
+
this.handleClick(e)}>
+ Season {this.props.data.season}
+ — ({this.props.data.episodes.length} episodes)
+
+ {this.state.colapsed ||
+
+ }
+ {this.state.colapsed &&
+
+ }
+
+
+ {this.state.colapsed ||
+
+
+ {this.props.data.episodes.map(function(episode, index) {
+ let key = `${episode.season}-${episode.episode}`;
+ return (
+
+ )
+ })}
+
+
+ }
+
+ )
+ }
+}
+
+function Episode(props) {
+ return (
+
+ {props.data.episode} |
+ {props.data.title} |
+
+
+ {props.data.torrents && props.data.torrents.map(function(torrent, index) {
+ let key = `${props.data.season}-${props.data.episode}-${torrent.source}-${torrent.quality}`;
+ return (
+
+ )
+ })}
+
+ |
+
+ )
+}
+
+function Torrent(props) {
+ return (
+
+
+ {props.data.quality}
+
+
+ )
+}
diff --git a/src/public/js/components/shows/list.js b/src/public/js/components/shows/list.js
index fb1ef4d..1d83f0c 100644
--- a/src/public/js/components/shows/list.js
+++ b/src/public/js/components/shows/list.js
@@ -1,15 +1,19 @@
import React from 'react'
+import { Link } from 'react-router'
import ListDetails from '../list/details'
import ListPosters from '../list/posters'
function ShowButtons(props) {
- const imdb_link = `http://www.imdb.com/title/${props.show.imdb_id}`;
+ const imdbLink = `http://www.imdb.com/title/${props.show.imdb_id}`;
return (
);
}
diff --git a/src/public/js/reducers/shows.js b/src/public/js/reducers/shows.js
index de3f99d..43ed2af 100644
--- a/src/public/js/reducers/shows.js
+++ b/src/public/js/reducers/shows.js
@@ -3,6 +3,9 @@ const defaultState = {
filter: "",
perPage: 30,
selectedImdbId: "",
+ show: {
+ seasons: [],
+ },
};
export default function showStore(state = defaultState, action) {
@@ -17,6 +20,11 @@ export default function showStore(state = defaultState, action) {
shows: action.payload.data,
selectedImdbId: selectedImdbId,
})
+ case 'SHOW_FETCH_DETAILS_FULFILLED':
+ return Object.assign({}, state, {
+ show: sortEpisodes(action.payload.data),
+ })
+ return state;
case 'SELECT_SHOW':
// Don't select the show if we're fetching another show's details
if (state.fetchingDetails) {
@@ -30,3 +38,47 @@ export default function showStore(state = defaultState, action) {
return state
}
}
+
+function sortEpisodes(show) {
+ let episodes = show.episodes;
+ delete show["episodes"];
+
+ if (episodes.length == 0) {
+ return show;
+ }
+
+ // Extract the seasons
+ let seasons = {};
+ for (let ep of episodes) {
+ if (!seasons[ep.season]) {
+ seasons[ep.season] = { episodes: [] };
+ }
+ seasons[ep.season].episodes.push(ep);
+ }
+
+ if (seasons.length === 0) {
+ return show;
+ }
+
+ // Put all the season in an array
+ let sortedSeasons = [];
+ for (let season of Object.keys(seasons)) {
+ let seasonEpisodes = seasons[season].episodes;
+ // Order the episodes in each season
+ seasonEpisodes.sort((a,b) => (a.episode - b.episode))
+ // Add the season in the list
+ sortedSeasons.push({
+ season: season,
+ episodes: seasonEpisodes,
+ })
+ }
+
+ // Order the seasons
+ for (let i=0; i (a.season - b.season))
+ }
+
+ show.seasons = sortedSeasons;
+
+ return show;
+}
diff --git a/src/public/less/app.less b/src/public/less/app.less
index 638753c..121e568 100644
--- a/src/public/less/app.less
+++ b/src/public/less/app.less
@@ -12,7 +12,11 @@ body {
background-color: @brand-primary;
}
-.list-plot {
+.clickable {
+ cursor: pointer;
+}
+
+.plot {
.text-justify;
margin-right: 5%;
}
@@ -27,6 +31,14 @@ body {
padding-bottom: 10px;
}
+.show-thumbnail {
+ max-height: 300px;
+}
+
+.episode-button {
+ padding-right: 5px;
+}
+
.navbar {
opacity: 0.95;
}