Merge pull request #18 from KevinMidboe/app_style_update

App style update
This commit is contained in:
2017-09-02 21:13:43 +02:00
committed by GitHub
7 changed files with 298 additions and 198 deletions

View File

@@ -8,28 +8,17 @@ import FetchData from './FetchData.js';
import ListStrays from './ListStrays.jsx' import ListStrays from './ListStrays.jsx'
import SearchRequest from './SearchRequest.jsx'; import SearchRequest from './SearchRequest.jsx';
import WebFont from 'webfontloader';
WebFont.load({
google: {
families: ['Titillium Web:300,400,700', 'sans-serif']
}
});
var background = {
backgroundColor: '#fafafa'
}
export default class App extends React.Component { export default class App extends React.Component {
// <div>
// <h1>Welcome to Seasoned</h1>
// </div>
// <ListStrays />
// <FetchData />
render() { render() {
return ( return (
<div style={background}>
<div> <div>
<h1>Welcome to Seasoned</h1>
</div>
<ListStrays />
<FetchData />
<SearchRequest /> <SearchRequest />
</div> </div>

View File

@@ -1,6 +1,8 @@
import React from 'react'; import React from 'react';
import glamorous from 'glamorous';
require('../app.scss'); // StyleComponents
import mediaResultItem from './styledComponents/mediaResultItem.jsx';
class MovieObject { class MovieObject {
constructor(object) { constructor(object) {
@@ -18,48 +20,127 @@ class MovieObject {
} }
requestMovie(id) { requestMovie(id) {
fetch('http://localhost:31459/api/v1/plex/request/' + id, { fetch('https://apollo.kevinmidboe.com/api/v1/plex/request/' + id, {
method: 'POST' method: 'POST'
}); });
} }
getElement() { getElement() {
var movie_wrapper = { // TODO move this to separate files.
display: 'flex', var resultItem = {
alignContent: 'center', maxWidth: '95%',
width: '30%', margin: '0 auto',
backgroundColor: '#ffffff', minHeight: '230px'
height: '231px',
margin: '20px',
boxShadow: '0px 0px 5px 1px rgba(0,0,0,0.15)'
} }
var movie_content = { var movie_content = {
marginLeft: '15px' marginLeft: '15px'
} }
var movie_header = { var resultTitle = {
fontSize: '1.6' + 'em' color: 'black',
fontSize: '2em',
} }
var resultPoster = {
float: 'left',
zIndex: '3',
position: 'relative',
marginRight: '30px'
}
var posterPath = 'https://image.tmdb.org/t/p/w154' + this.poster; var resultPosterImg = {
var buttonState; border: '2px none',
if (this.matchedInPlex) { borderRadius: '2px',
buttonState = <button onClick={() => {this.requestExisting(this)}}>Request anyway</button>; width: '150px'
}
var buttons = {
paddingTop: '20px'
}
var requestButton = {
color: '#e9a131',
marginRight: '10px',
background: 'white',
border: '#e9a131 2px solid',
borderRadius: '4px',
textAlign: 'center',
padding: '10px',
minWidth: '100px',
float: 'left',
fontSize: '13px',
fontWeight: '800',
cursor: 'pointer'
}
var tmdbButton = {
color: '#00d17c',
marginRight: '10px',
background: 'white',
border: '#00d17c 2px solid',
borderRadius: '4px',
textAlign: 'center',
padding: '10px',
minWidth: '100px',
float: 'left',
fontSize: '13px',
fontWeight: '800',
cursor: 'pointer'
}
var row = {
width: '100%'
}
var itemDivider = {
width: '90%',
borderBottom: '1px solid grey',
margin: '2rem auto'
}
// TODO set the poster image async by updating the dom after this is returned
if (this.poster == null || this.poster == undefined) {
var posterPath = 'https://openclipart.org/image/2400px/svg_to_png/211479/Simple-Image-Not-Found-Icon.png'
} else { } else {
buttonState = <button onClick={() => {this.requestMovie(this.id)}}>Request</button>; var posterPath = 'https://image.tmdb.org/t/p/w154' + this.poster;
} }
var foundInPlex;
if (this.matchedInPlex) {
foundInPlex = <button onClick={() => {this.requestExisting(this)}}
style={requestButton}><span>Request Anyway</span></button>;
} else {
foundInPlex = <button onClick={() => {this.requestMovie(this.id)}}
style={requestButton}><span>&#x0002B; Request</span></button>;
}
var themoviedbLink = 'https://www.themoviedb.org/movie/' + this.id
return ( return (
<div key={this.id} style={movie_wrapper}> <div>
<img src={posterPath}></img> <div style={resultItem} key={this.id}>
<div style={movie_content}> <div style={resultPoster}>
<span style={movie_header}>{this.title} ({this.year})</span> <img style={resultPosterImg} id='poster' src={posterPath}></img>
<br></br> </div>
{buttonState} <div>
<span style={resultTitle}>{this.title} ({this.year})</span>
<br></br> <br></br>
<span>{this.overview}</span> <span>{this.overview}</span>
<br></br>
<span className='imdbLogo'>
</span>
<div style={buttons}>
{foundInPlex}
<a href={themoviedbLink}><button style={tmdbButton}><span>Info</span></button></a>
</div>
</div>
</div>
<div style={row}>
<div style={itemDivider}></div>
</div> </div>
</div>) </div>)
} }
} }

View File

@@ -10,7 +10,9 @@ class SearchRequest extends React.Component {
// Constructor with states holding the search query and the element of reponse. // Constructor with states holding the search query and the element of reponse.
this.state = { this.state = {
searchQuery: '', searchQuery: '',
responseMovieList: null responseMovieList: null,
movieFilter: true,
tvshowFilter: false
} }
this.URLs = { this.URLs = {
@@ -19,6 +21,7 @@ class SearchRequest extends React.Component {
} }
} }
componentDidMount(){ componentDidMount(){
var that = this; var that = this;
this.setState({responseMovieList: null}) this.setState({responseMovieList: null})
@@ -34,6 +37,9 @@ class SearchRequest extends React.Component {
fetchQuery() { fetchQuery() {
let url = this.URLs.request + this.state.searchQuery let url = this.URLs.request + this.state.searchQuery
if (this.state.tvshowFilter) {
url = url + '&type=tv'
}
fetch(url) fetch(url)
// Check if the response is ok // Check if the response is ok
@@ -80,33 +86,186 @@ class SearchRequest extends React.Component {
return movie.getElement(); return movie.getElement();
} }
toggleFilter(filterType) {
if (filterType == 'movies') {
this.setState({
movieFilter: !this.state.movieFilter
})
console.log(this.state.movieFilter);
}
else if (filterType == 'tvshows') {
this.setState({
tvshowFilter: !this.state.tvshowFilter
})
console.log(this.state.tvshowFilter);
}
}
render(){ render(){
var body = { var body = {
fontFamily: "'Roboto', 'Open Sans', sans-serif", fontFamily: "'Open Sans', sans-serif",
display: 'inline-block' backgroundColor: '#f7f7f7',
margin: 0,
padding: 0,
minHeight: '100%',
position: 'relative'
} }
var requestMovieList = {
var backgroundHeader = {
width: '100%',
minHeight: '400px',
backgroundColor: '#011c23',
zIndex: 1,
position: 'absolute'
}
var requestWrapper = {
top: '300px',
width: '90%',
maxWidth: '1200px',
margin: 'auto',
paddingTop: '20px',
backgroundColor: 'white',
position: 'relative',
zIndex: '10',
boxShadow: '0 2px 10px grey'
}
var pageTitle = {
display: 'flex', display: 'flex',
flexWrap: 'wrap', alignItems: 'center',
justifyContent: 'center' justifyContent: 'center'
} }
var pageTitleSpan = {
color: 'white',
fontSize: '3em',
marginTop: '4vh',
marginBottom: '6vh'
}
var box = {
width: '90%',
height: '50px',
maxWidth: '1200px',
margin: '0 auto'
}
var container = {
verticalAlign: 'middle',
whiteSpace: 'nowrap',
position: 'relative',
display: 'flex',
justifyContent: 'center'
}
var searchIcon = {
position: 'absolute',
marginLeft: '17px',
marginTop: '17px',
zIndex: '1',
color: '#4f5b66'
}
var searchBar = {
width: '60%',
minWidth: '120px',
height: '50px',
background: '#ffffff',
border: 'none',
fontSize: '10pt',
float: 'left',
color: '#63717f',
paddingLeft: '45px',
borderRadius: '5px',
marginRight: '15px'
}
var searchFilter = {
color: 'white',
fontSize: '1em',
paddingTop: '12px',
marginBottom: '12px',
marginLeft: '10px',
cursor: 'pointer'
}
var hvrUnderlineFromCenter = {
color: 'white',
fontSize: '1em',
paddingTop: '12px',
marginBottom: '12px',
marginLeft: '10px',
cursor: 'pointer',
display: 'inline-block',
verticalAlign: 'middle',
WebkitTransform: 'perspective(1px) translateZ(0)',
transform: 'perspective(1px) translateZ(0)',
boxShadow: '0 0 1px transparent',
position: 'relative',
overflow: 'hidden',
':before': {
content: "",
position: 'absolute',
zIndex: '-1',
left: '50%',
right: '50%',
bottom: '0',
background: '#00d17c',
height: '2px',
WebkitTransitionProperty: 'left, right',
transitionProperty: 'left, right',
WebkitTransitionDuration: '0.3s',
transitionDuration: '0.3s',
WebkitTransitionTimingFunction: 'ease-out',
transitionTimingFunction: 'ease-out'
},
':hover:before': {
left: 0,
right: 0
},
'focus:before': {
left: 0,
right: 0
},
'active:before': {
left: 0,
right: 0
}
}
return( return(
<div style={body}> <div style={body}>
<input <div className='backgroundHeader' style={backgroundHeader}>
type="text" <div className='pageTitle' style={pageTitle}>
<span style={pageTitleSpan}>Request new movies or tv shows</span>
</div>
<div className='box' style={box}>
<div style={container}>
<span style={searchIcon}><i className="fa fa-search"></i></span>
<input style={searchBar} type="text" id="search" placeholder="Search for new content..."
onKeyPress={(event) => this._handleQueryKeyPress(event)} onKeyPress={(event) => this._handleQueryKeyPress(event)}
onChange={event => this.updateQueryState(event)} onChange={event => this.updateQueryState(event)}
value={this.state.searchQuery} value={this.state.searchQuery}/>
/>
<button onClick={() => this.fetchQuery()}>Search</button>
<br></br>
<br></br> <span style={searchFilter}
<div id='requestMovieList' ref='requestMovieList' style={requestMovieList}> className="search_category hvrUnderlineFromCenter"
onClick={() => {this.toggleFilter('movies')}}
id="category_active">Movies</span>
<span style={searchFilter}
className="search_category hvrUnderlineFromCenter"
onClick={() => {this.toggleFilter('tvshows')}}
id="category_inactive">TV Shows</span>
</div>
</div>
</div>
<div id='requestMovieList' ref='requestMovieList' style={requestWrapper}>
{this.state.responseMovieList} {this.state.responseMovieList}
</div> </div>
</div> </div>

View File

@@ -2,9 +2,11 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
<title>seasoned Shows</title> <title>seasoned Shows</title>
</head> </head>
<body> <body style='margin: 0'>
<div id="root"> <div id="root">
</div> </div>

View File

@@ -12,16 +12,16 @@
"css-loader": "^0.28.4", "css-loader": "^0.28.4",
"html-webpack-plugin": "^2.28.0", "html-webpack-plugin": "^2.28.0",
"path": "^0.12.7", "path": "^0.12.7",
"react": "^15.5.4", "react": "^15.6.1",
"react-dom": "^15.5.4", "react-dom": "^15.5.4",
"webfontloader": "^1.6.28", "webfontloader": "^1.6.28",
"webpack": "^3.3.0", "webpack": "^3.5.5",
"webpack-dev-server": "^2.4.5" "webpack-dev-server": "^2.4.5"
}, },
"devDependencies": { "devDependencies": {
"babel-core": "^6.24.1", "babel-core": "^6.26.0",
"babel-loader": "^7.0.0", "babel-loader": "^7.1.2",
"babel-preset-env": "^1.5.1", "babel-preset-env": "^1.6.0",
"babel-preset-es2015": "^6.24.1", "babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1" "babel-preset-react": "^6.24.1"
} }

View File

@@ -2,7 +2,7 @@
* @Author: KevinMidboe * @Author: KevinMidboe
* @Date: 2017-06-01 19:09:16 * @Date: 2017-06-01 19:09:16
* @Last Modified by: KevinMidboe * @Last Modified by: KevinMidboe
* @Last Modified time: 2017-06-02 19:38:45 * @Last Modified time: 2017-09-02 15:51:52
*/ */
const path = require('path'); const path = require('path');
@@ -27,14 +27,6 @@ module.exports = {
loaders: [ loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.scss$/, loader: 'css-loader', exclude: /node_modules/ },
{ test: /\.css$/, loader: 'style-loader!css!scss', exclude: /node_modules/ }
// { test: /\.css$/, loader: 'style-loader!css-loader!', exclude: /node_modules/ },
// query: {
// presets: ['es2015']
// }
// { test: /\.css-loader$/, loader: 'style-loader!css-loader', exclude: /node_modules/ }
] ]
}, },
plugins: [HtmlWebpackPluginConfig] plugins: [HtmlWebpackPluginConfig]

View File

@@ -1,123 +0,0 @@
const assert = require('assert');
const PlexRepository = require('src/plex/plexRepository');
const plexRepository = new PlexRepository();
const convertPlexToMovie = require('src/plex/convertPlexToMovie');
const configuration = require('src/config/configuration').getInstance();
const TMDB = require('src/tmdb/tmdb');
const tmdb = new TMDB(configuration.get('tmdb', 'apiKey'));
var Promise = require('bluebird');
var rp = require('request-promise');
const MailTemplate = require('src/plex/mailTemplate')
var pythonShell = require('python-shell');
const nodemailer = require('nodemailer');
class RequestRepository {
searchRequest(query, page, type) {
return Promise.resolve()
.then(() => tmdb.search(query, page, type))
.then((tmdbMovies) => {
return Promise.resolve()
.then(() => plexRepository.searchMedia(query))
.then((plexMedia) => {
return Promise.each(tmdbMovies, function(tmdbMovie) {
return Promise.each(plexMedia, function(plexMovie) {
if (tmdbMovie.title == plexMovie.title && tmdbMovie.year == plexMovie.year) {
tmdbMovie.matchedInPlex = true;
console.log(tmdbMovie.title + ' : ' + tmdbMovie.year);
}
return tmdbMovie;
})
})
})
})
.catch((error) => {
return error;
});
}
lookup(identifier, type = 'movie') {
if (type === 'movie') { type = 'movieInfo'}
else if (type === 'tv') { type = 'tvInfo'}
return Promise.resolve()
.then(() => tmdb.lookup(identifier, type))
.then((tmdbMovie) => {
return Promise.resolve(plexRepository.searchMedia(tmdbMovie.title))
.then((plexMovies) => {
for (var i = 0; i < plexMovies.length; i++) {
if (tmdbMovie.title === plexMovies[i].title && tmdbMovie.year === plexMovies[i].year) {
tmdbMovie.matchedInPlex = true;
return tmdbMovie;
}
}
})
.catch((error) => {
return error;
});
return tmdbMovie;
});
}
sendRequest(identifier) {
// TODO try a cache hit on the movie item
tmdb.lookup(identifier).then(movie => {
console.log(movie.title)
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: configuration.get('mail', 'host'),
port: 26,
ignoreTLS: true,
tls :{rejectUnauthorized: false},
secure: false, // secure:true for port 465, secure:false for port 587
auth: {
user: configuration.get('mail', 'user'),
pass: configuration.get('mail', 'password')
}
});
const mailTemplate = new MailTemplate(movie)
// setup email data with unicode symbols
let mailOptions = {
// TODO get the mail adr from global location (easy to add)
from: 'MovieRequester <support@kevinmidboe.com>', // sender address
to: 'kevin.midboe@gmail.com', // list of receivers
subject: 'Download request', // Subject line
text: mailTemplate.toText(),
html: mailTemplate.toHTML()
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message %s sent: %s', info.messageId, info.response);
});
// var options = {
// args: [movie.title, movie.year, movie.poster]
// }
// pythonShell.run('sendRequest.py', options, function (err, results) {
// if (err) throw err;
// // TODO Add error handling!! RequestRepository.ERROR
// // results is an array consisting of messages collected during execution
// console.log('results: %j', results)
// })
})
return Promise.resolve();
}
}
module.exports = RequestRepository;