mirror of
https://github.com/mjrode/WhatToWatch.git
synced 2025-12-30 10:09:44 -06:00
Add modal and plex token form
This commit is contained in:
82
client/package-lock.json
generated
82
client/package-lock.json
generated
@@ -2657,7 +2657,8 @@
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
@@ -2675,11 +2676,13 @@
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -2692,15 +2695,18 @@
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -2803,7 +2809,8 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -2813,6 +2820,7 @@
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -2825,17 +2833,20 @@
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -2852,6 +2863,7 @@
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -2924,7 +2936,8 @@
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -2934,6 +2947,7 @@
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -3009,7 +3023,8 @@
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@@ -3039,6 +3054,7 @@
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@@ -3056,6 +3072,7 @@
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
@@ -3094,11 +3111,13 @@
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5720,7 +5739,8 @@
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
@@ -5738,11 +5758,13 @@
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -5755,15 +5777,18 @@
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -5866,7 +5891,8 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -5876,6 +5902,7 @@
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -5888,17 +5915,20 @@
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -5915,6 +5945,7 @@
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -5987,7 +6018,8 @@
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -5997,6 +6029,7 @@
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -6072,7 +6105,8 @@
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@@ -6102,6 +6136,7 @@
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@@ -6119,6 +6154,7 @@
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
@@ -6157,11 +6193,13 @@
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
BIN
client/public/favicon.ico
Normal file → Executable file
BIN
client/public/favicon.ico
Normal file → Executable file
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 15 KiB |
@@ -32,7 +32,7 @@
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<title>PlexRex</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import axios from 'axios';
|
||||
import {FETCH_USER, FETCH_PLEX_TOKEN} from './types';
|
||||
|
||||
// Action Creators
|
||||
export const fetchUser = () => async dispatch => {
|
||||
const res = await axios.get('/auth/current_user');
|
||||
const res = await axios.get('/api/auth/current_user');
|
||||
dispatch({type: FETCH_USER, payload: res.data});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,27 +1,19 @@
|
||||
import React, {Component} from 'react';
|
||||
import {BrowserRouter, Route} from 'react-router-dom';
|
||||
import {connect} from 'react-redux';
|
||||
import axios from 'axios';
|
||||
import * as actions from '../actions';
|
||||
|
||||
import Header from './Header';
|
||||
import Landing from './Landing';
|
||||
import Dashboard from './Dashboard';
|
||||
import Hero from './Hero';
|
||||
import CreateAccount from './CreateAccount';
|
||||
import PlexForm from './plex/PlexForm';
|
||||
// const Dashboard = () => <h2>Dashboard</h2>;
|
||||
// const SurveyNew = () => <h2>SurveyNew</h2>;
|
||||
|
||||
class App extends Component {
|
||||
state = {user: {}};
|
||||
componentDidMount() {
|
||||
this.fetchUser();
|
||||
this.props.fetchUser();
|
||||
}
|
||||
|
||||
fetchUser = async () => {
|
||||
const res = await axios.get('/auth/current_user');
|
||||
this.setState({user: res.data});
|
||||
console.log(res.data);
|
||||
return res;
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@@ -29,13 +21,10 @@ class App extends Component {
|
||||
<BrowserRouter>
|
||||
<div className="container">
|
||||
<Header />
|
||||
<Route exact path="/" component={Landing} />
|
||||
<Route exact path="/surveys" component={Dashboard} />
|
||||
<Route exact path="/" component={Hero} />
|
||||
|
||||
<Route
|
||||
path="/app/plex"
|
||||
render={props => <PlexForm user={this.state.user} />}
|
||||
/>
|
||||
<Route path="/create-account" component={CreateAccount} />
|
||||
<Route path="/form" component={PlexForm} />
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
@@ -44,4 +33,7 @@ class App extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default connect(
|
||||
null,
|
||||
actions,
|
||||
)(App);
|
||||
|
||||
7
client/src/components/CreateAccount.css
Normal file
7
client/src/components/CreateAccount.css
Normal file
@@ -0,0 +1,7 @@
|
||||
.no-bottom-margin {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.margin-spacing {
|
||||
margin: 3em 0;
|
||||
}
|
||||
116
client/src/components/CreateAccount.js
Normal file
116
client/src/components/CreateAccount.js
Normal file
@@ -0,0 +1,116 @@
|
||||
import React from 'react';
|
||||
import axios from 'axios';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import {connect} from 'react-redux';
|
||||
import {withStyles} from '@material-ui/core/styles';
|
||||
import './CreateAccount.css';
|
||||
import Modal from './Modal';
|
||||
import styles from './css';
|
||||
|
||||
class CreateAccount extends React.Component {
|
||||
state = {email: '', password: '', section_data: ''};
|
||||
|
||||
onFormSubmit = event => {
|
||||
event.preventDefault();
|
||||
this.getPlexToken(this.state);
|
||||
};
|
||||
|
||||
getPlexToken = async params => {
|
||||
const res = await axios.get('/plex/auth', {params});
|
||||
return res;
|
||||
};
|
||||
|
||||
fetchSections = async params => {
|
||||
const res = await axios.get('/plex/library/sections');
|
||||
console.log(res);
|
||||
this.setState({section_data: res.data});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {classes} = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<CssBaseline />
|
||||
<div className={classes.heroUnit}>
|
||||
<div className={classes.heroContentSmall}>
|
||||
<div className="section center-align">
|
||||
<h3 className={classes.shrinkTopMargin}>Fetch Plex Token</h3>
|
||||
<div className="center">
|
||||
<Modal />
|
||||
</div>
|
||||
</div>
|
||||
<div className="section center-align">
|
||||
<div className="row">
|
||||
<form onSubmit={this.onFormSubmit} className="col s12">
|
||||
<div className="row no-bottom-margin">
|
||||
<div className="input-field col m8 offset-m2 s12">
|
||||
<p>Plex Email</p>
|
||||
<input
|
||||
id="email"
|
||||
type="text"
|
||||
className="validate center-align"
|
||||
value={this.state.email}
|
||||
onChange={e => this.setState({email: e.target.value})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row no-bottom-margin">
|
||||
<div className="input-field col m8 offset-m2 s12">
|
||||
<p>Plex Server URL</p>
|
||||
<input
|
||||
id="email"
|
||||
type="text"
|
||||
className="validate center-align"
|
||||
value={this.state.email}
|
||||
onChange={e => this.setState({email: e.target.value})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row no-bottom-margin">
|
||||
<div className="input-field col m8 offset-m2 s12">
|
||||
<p>Plex Password</p>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
className="validate center-align"
|
||||
value={this.state.password}
|
||||
onChange={e =>
|
||||
this.setState({password: e.target.value})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col s12">
|
||||
<div className="center-align">
|
||||
<button
|
||||
className="btn-large waves-effect waves-light center-align"
|
||||
type="submit"
|
||||
name="action"
|
||||
>
|
||||
Submit
|
||||
<i className="material-icons right">send</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CreateAccount.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
function mapStateToProps({auth}) {
|
||||
return {auth};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(withStyles(styles)(CreateAccount));
|
||||
@@ -1,8 +0,0 @@
|
||||
import React from 'react';
|
||||
// import {Link} from 'react-router-dom';
|
||||
|
||||
const Dashboard = () => {
|
||||
return <div>Dashboard</div>;
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
@@ -4,28 +4,20 @@ import {Link} from 'react-router-dom';
|
||||
|
||||
class Header extends Component {
|
||||
renderContent() {
|
||||
console.log('this.props.auth', this.props.auth);
|
||||
switch (this.props.auth) {
|
||||
case null:
|
||||
return;
|
||||
case false:
|
||||
return (
|
||||
<li>
|
||||
<a href="/auth/google">Login With Google</a>
|
||||
<a href="/api/auth/google">Login With Google</a>
|
||||
</li>
|
||||
);
|
||||
default:
|
||||
if (!this.props.auth.plexToken) {
|
||||
return (
|
||||
<li key="3" style={{margin: '0 10px'}}>
|
||||
<Link to="/app/plex" className="waves-effect waves-light btn">
|
||||
<i className="material-icons left">live_tv</i>Import Plex
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<li key="2" style={{margin: '0 10px'}}>
|
||||
<a href="/auth/logout">Logout</a>
|
||||
<a href="/api/auth/logout">Logout</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
@@ -35,7 +27,7 @@ class Header extends Component {
|
||||
<nav>
|
||||
<div className="nav-wrapper" style={{margin: '0 10px'}}>
|
||||
<Link to={this.props.auth ? '/' : '/'} className="left brand-logo">
|
||||
PlexRec
|
||||
PlexRex
|
||||
</Link>
|
||||
<ul className="right">{this.renderContent()}</ul>
|
||||
</div>
|
||||
|
||||
102
client/src/components/Hero.js
Normal file
102
client/src/components/Hero.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {withStyles} from '@material-ui/core/styles';
|
||||
import {Link} from 'react-router-dom';
|
||||
import {connect} from 'react-redux';
|
||||
import styles from './css';
|
||||
|
||||
class Hero extends Component {
|
||||
render() {
|
||||
const {classes} = this.props;
|
||||
if (this.props.auth) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<CssBaseline />
|
||||
<main>
|
||||
<div className={classes.heroUnit}>
|
||||
<div className={classes.heroContent}>
|
||||
<Typography
|
||||
component="h1"
|
||||
variant="h2"
|
||||
align="center"
|
||||
color="textPrimary"
|
||||
gutterBottom
|
||||
>
|
||||
PlexRex
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h6"
|
||||
align="center"
|
||||
color="textSecondary"
|
||||
paragraph
|
||||
>
|
||||
Media recommendations based on your most watched Plex TV and
|
||||
Movies.
|
||||
</Typography>
|
||||
<div className="center-align">
|
||||
<Link
|
||||
to="/app/plex"
|
||||
className="waves-effect waves-light btn-large"
|
||||
>
|
||||
<i className="material-icons left">live_tv</i>Sign In
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<CssBaseline />
|
||||
<main>
|
||||
<div className={classes.heroUnit}>
|
||||
<div className={classes.heroContent}>
|
||||
<Typography
|
||||
component="h1"
|
||||
variant="h2"
|
||||
align="center"
|
||||
color="textPrimary"
|
||||
gutterBottom
|
||||
>
|
||||
PlexRex
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h6"
|
||||
align="center"
|
||||
color="textSecondary"
|
||||
paragraph
|
||||
>
|
||||
Media recommendations based on your most watched Plex TV and
|
||||
Movies.
|
||||
</Typography>
|
||||
<div className="center-align">
|
||||
<a
|
||||
href="/api/auth/google"
|
||||
className="waves-effect waves-light btn-large"
|
||||
>
|
||||
<i className="material-icons left">live_tv</i> Login with
|
||||
Google
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Hero.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
function mapStateToProps({auth}) {
|
||||
return {auth};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(withStyles(styles)(Hero));
|
||||
@@ -1,12 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const Landing = () => {
|
||||
return (
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<h1>Emaily!</h1>
|
||||
Collect feedback from your users
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Landing;
|
||||
111
client/src/components/Modal.js
Normal file
111
client/src/components/Modal.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import React from 'react';
|
||||
import {withStyles} from '@material-ui/core/styles';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import MuiDialogTitle from '@material-ui/core/DialogTitle';
|
||||
import MuiDialogContent from '@material-ui/core/DialogContent';
|
||||
import MuiDialogActions from '@material-ui/core/DialogActions';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
const DialogTitle = withStyles(theme => ({
|
||||
root: {
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
margin: 0,
|
||||
padding: theme.spacing.unit * 2,
|
||||
},
|
||||
closeButton: {
|
||||
position: 'absolute',
|
||||
right: theme.spacing.unit,
|
||||
top: theme.spacing.unit,
|
||||
color: theme.palette.grey[500],
|
||||
},
|
||||
}))(props => {
|
||||
const {children, classes, onClose} = props;
|
||||
return (
|
||||
<MuiDialogTitle disableTypography className={classes.root}>
|
||||
<Typography variant="h6">{children}</Typography>
|
||||
{onClose ? (
|
||||
<IconButton
|
||||
aria-label="Close"
|
||||
className={classes.closeButton}
|
||||
onClick={onClose}
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
) : null}
|
||||
</MuiDialogTitle>
|
||||
);
|
||||
});
|
||||
|
||||
const DialogContent = withStyles(theme => ({
|
||||
root: {
|
||||
margin: 0,
|
||||
padding: theme.spacing.unit * 2,
|
||||
},
|
||||
}))(MuiDialogContent);
|
||||
|
||||
const DialogActions = withStyles(theme => ({
|
||||
root: {
|
||||
borderTop: `1px solid ${theme.palette.divider}`,
|
||||
margin: 0,
|
||||
padding: theme.spacing.unit,
|
||||
},
|
||||
}))(MuiDialogActions);
|
||||
|
||||
class CustomizedDialogDemo extends React.Component {
|
||||
state = {
|
||||
open: false,
|
||||
};
|
||||
|
||||
handleClickOpen = () => {
|
||||
this.setState({
|
||||
open: true,
|
||||
});
|
||||
};
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({open: false});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<button
|
||||
className="btn-small waves-effect waves-light center-align"
|
||||
onClick={this.handleClickOpen}
|
||||
name="action"
|
||||
>
|
||||
<i className="material-icons right">info</i>
|
||||
Info
|
||||
</button>
|
||||
<Dialog
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby="customized-dialog-title"
|
||||
open={this.state.open}
|
||||
>
|
||||
<DialogTitle id="customized-dialog-title" onClose={this.handleClose}>
|
||||
What do we do with this info?
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography gutterBottom>
|
||||
We need to make a request to fetch a token which will allow us to
|
||||
get a list of your most watched media. We will never store you
|
||||
Plex password or make any changes to your plex server. This is an
|
||||
open source project and you can view the code
|
||||
<a href="https://github.com/mjrode/recommend"> here.</a>
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="primary">
|
||||
Ok
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CustomizedDialogDemo;
|
||||
60
client/src/components/css.js
Normal file
60
client/src/components/css.js
Normal file
@@ -0,0 +1,60 @@
|
||||
const styles = theme => ({
|
||||
appBar: {
|
||||
position: 'relative',
|
||||
},
|
||||
|
||||
icon: {
|
||||
marginRight: theme.spacing.unit * 2,
|
||||
},
|
||||
heroUnit: {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
heroContent: {
|
||||
maxWidth: 600,
|
||||
margin: '0 auto',
|
||||
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`,
|
||||
},
|
||||
heroContentSmall: {
|
||||
maxWidth: 600,
|
||||
margin: '0 auto',
|
||||
padding: `${theme.spacing.unit * 2}px 0 ${theme.spacing.unit * 1}px`,
|
||||
},
|
||||
heroButtons: {
|
||||
marginTop: theme.spacing.unit * 4,
|
||||
},
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 1100,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
cardGrid: {
|
||||
padding: `${theme.spacing.unit * 8}px 0`,
|
||||
},
|
||||
card: {
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
cardMedia: {
|
||||
paddingTop: '56.25%', // 16:9
|
||||
},
|
||||
cardContent: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
footer: {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
padding: theme.spacing.unit * 6,
|
||||
},
|
||||
shrinkTopMargin: {
|
||||
margin: `${theme.spacing.unit}px ${theme.spacing.unit}px ${
|
||||
theme.spacing.unit
|
||||
}px ${theme.spacing.unit}px`,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import axios from 'axios';
|
||||
|
||||
class PlexForm extends React.Component {
|
||||
state = {username: '', password: '', section_data: ''};
|
||||
|
||||
@@ -21,8 +21,8 @@ class PlexForm extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
console.log(this.props.user);
|
||||
if (this.props.user.plexToken) {
|
||||
console.log(this.props.auth);
|
||||
if (this.props.auth.plexToken) {
|
||||
return (
|
||||
<div className="input-field col s6">
|
||||
<button
|
||||
@@ -39,46 +39,52 @@ class PlexForm extends React.Component {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="row">
|
||||
<form onSubmit={this.onFormSubmit} className="col s12">
|
||||
<div className="row">
|
||||
<div className="input-field col s6">
|
||||
<i className="material-icons prefix">account_circle</i>
|
||||
<input
|
||||
id="username"
|
||||
type="text"
|
||||
className="validate"
|
||||
value={this.state.username}
|
||||
onChange={e => this.setState({username: e.target.value})}
|
||||
/>
|
||||
<label htmlFor="username">Plex Username</label>
|
||||
<div className="section">
|
||||
<div className="row">
|
||||
<form onSubmit={this.onFormSubmit} className="col s12">
|
||||
<div className="row">
|
||||
<div className="input-field col s6">
|
||||
<i className="material-icons prefix">account_circle</i>
|
||||
<input
|
||||
id="username"
|
||||
type="text"
|
||||
className="validate"
|
||||
value={this.state.username}
|
||||
onChange={e => this.setState({username: e.target.value})}
|
||||
/>
|
||||
<label htmlFor="username">Plex Username</label>
|
||||
</div>
|
||||
<div className="input-field col s6">
|
||||
<i className="material-icons prefix">lock_open</i>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
className="validate"
|
||||
value={this.state.password}
|
||||
onChange={e => this.setState({password: e.target.value})}
|
||||
/>
|
||||
<label htmlFor="password">password</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="input-field col s6">
|
||||
<i className="material-icons prefix">lock_open</i>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
className="validate"
|
||||
value={this.state.password}
|
||||
onChange={e => this.setState({password: e.target.value})}
|
||||
/>
|
||||
<label htmlFor="password">password</label>
|
||||
<button
|
||||
className="btn waves-effect waves-light"
|
||||
type="submit"
|
||||
name="action"
|
||||
>
|
||||
Submit
|
||||
<i className="material-icons right">send</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="input-field col s6">
|
||||
<button
|
||||
className="btn waves-effect waves-light"
|
||||
type="submit"
|
||||
name="action"
|
||||
>
|
||||
Submit
|
||||
<i className="material-icons right">send</i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PlexForm;
|
||||
function mapStateToProps({auth}) {
|
||||
return {auth};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(PlexForm);
|
||||
|
||||
@@ -10,7 +10,11 @@ class PlexNew extends Component {
|
||||
render() {
|
||||
console.log(this.props.auth);
|
||||
if (!this.props.auth.plexToken) {
|
||||
return <PlexForm onSubmit={this.submit} />;
|
||||
return (
|
||||
<div class="valign-wrapper">
|
||||
<PlexForm onSubmit={this.submit} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <PlexActions />;
|
||||
|
||||
@@ -6,6 +6,7 @@ import {createStore, applyMiddleware} from 'redux';
|
||||
import reduxThunk from 'redux-thunk';
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
import App from './components/App';
|
||||
import reducers from './reducers';
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ export default () => {
|
||||
// Set up routes
|
||||
server.use('/api/plex', plex);
|
||||
server.use('/api/tdaw', tdaw);
|
||||
server.use('/auth', auth);
|
||||
server.use('/api/auth', auth);
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
|
||||
@@ -19,7 +19,7 @@ passport.use(
|
||||
{
|
||||
clientID: keys.server.googleClientID,
|
||||
clientSecret: keys.server.googleClientSecret,
|
||||
callbackURL: '/auth/google/callback',
|
||||
callbackURL: '/api/auth/google/callback',
|
||||
proxy: true,
|
||||
},
|
||||
async (accessToken, refreshToken, profile, done) => {
|
||||
|
||||
Reference in New Issue
Block a user