fix a ton of eslint errors
This commit is contained in:
parent
77cc7b2a8c
commit
3d42da18a8
51 changed files with 1026 additions and 937 deletions
30
.eslintrc
30
.eslintrc
|
@ -12,6 +12,34 @@
|
||||||
"classes": true
|
"classes": true
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"react/no-multi-comp": 0,
|
||||||
|
"import/default": 0,
|
||||||
|
"import/no-duplicates": 0,
|
||||||
|
"import/named": 0,
|
||||||
|
"import/namespace": 0,
|
||||||
|
"import/no-unresolved": 0,
|
||||||
|
"import/no-named-as-default": 2,
|
||||||
|
"comma-dangle": 0, // not sure why airbnb turned this on. gross!
|
||||||
|
"indent": [2, 2, {"SwitchCase": 1}],
|
||||||
|
"no-console": 0,
|
||||||
|
"no-alert": 0,
|
||||||
|
"no-underscore-dangle": 0,
|
||||||
|
"max-len": [1, 120, 4],
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"react", "import"
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"import/parser": "babel-eslint",
|
||||||
|
"import/resolve": {
|
||||||
|
"moduleDirectory": ["node_modules"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"globals": {
|
||||||
|
"__DEVELOPMENT__": true,
|
||||||
|
"__CLIENT__": true,
|
||||||
|
"__SERVER__": true,
|
||||||
|
"__DISABLE_SSR__": true,
|
||||||
|
"__DEVTOOLS__": true
|
||||||
}
|
}
|
||||||
}
|
}
|
37
client/components/Nav.js
Normal file
37
client/components/Nav.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
|
class Nav extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<nav className="nav">
|
||||||
|
<ul className="nav__items-left">
|
||||||
|
<li className="nav__item">
|
||||||
|
<p
|
||||||
|
className="nav__new"
|
||||||
|
onClick={this.props.createProject}
|
||||||
|
>
|
||||||
|
New
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li className="nav__item">
|
||||||
|
<p
|
||||||
|
className="nav__save"
|
||||||
|
onClick={this.props.saveProject}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul className="nav__items-right">
|
||||||
|
<li className="nav__item">
|
||||||
|
{this.props.user.authenticated && <p>Hello, {this.props.user.username}!</p>}
|
||||||
|
{!this.props.user.authenticated && <p><Link to='/login'>Login</Link> or <Link to='/signup'>Sign Up</Link></p>}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Nav;
|
|
@ -1,33 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { Link } from 'react-router'
|
|
||||||
|
|
||||||
class Nav extends React.Component {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<nav className="nav">
|
|
||||||
<ul className="nav__items-left">
|
|
||||||
<li className="nav__item">
|
|
||||||
<p className="nav__new"
|
|
||||||
onClick={this.props.createProject}>
|
|
||||||
New
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li className="nav__item">
|
|
||||||
<p className="nav__save"
|
|
||||||
onClick={this.props.saveProject}>
|
|
||||||
Save
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<ul className="nav__items-right">
|
|
||||||
<li className="nav__item">
|
|
||||||
{this.props.user.authenticated && <p>Hello, {this.props.user.username}!</p>}
|
|
||||||
{!this.props.user.authenticated && <p><Link to={`/login`}>Login</Link> or <Link to={`/signup`}>Sign Up</Link></p>}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Nav;
|
|
|
@ -22,5 +22,5 @@ export const NEW_PROJECT = 'NEW_PROJECT';
|
||||||
|
|
||||||
export const SET_PROJECT = 'SET_PROJECT';
|
export const SET_PROJECT = 'SET_PROJECT';
|
||||||
|
|
||||||
//eventually, handle errors more specifically and better
|
// eventually, handle errors more specifically and better
|
||||||
export const ERROR = 'ERROR';
|
export const ERROR = 'ERROR';
|
||||||
|
|
|
@ -5,19 +5,18 @@ import DevTools from './components/DevTools';
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
this.state = {isMounted: false};
|
this.state = { isMounted: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.setState({isMounted: true});
|
this.setState({ isMounted: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
debugger;
|
|
||||||
return (
|
return (
|
||||||
<div className="app">
|
<div className="app">
|
||||||
{this.state.isMounted && !window.devToolsExtension && process.env.NODE_ENV === 'development' && <DevTools />}
|
{this.state.isMounted && !window.devToolsExtension && process.env.NODE_ENV === 'development' && <DevTools />}
|
||||||
{ this.props.children }
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
export function updateFile(name, content) {
|
export function updateFile(name, content) {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.CHANGE_SELECTED_FILE,
|
type: ActionTypes.CHANGE_SELECTED_FILE,
|
||||||
name: name,
|
name,
|
||||||
content: content
|
content
|
||||||
}
|
};
|
||||||
}
|
}
|
|
@ -1,19 +1,19 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
export function toggleSketch() {
|
export function toggleSketch() {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.TOGGLE_SKETCH
|
type: ActionTypes.TOGGLE_SKETCH
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function startSketch() {
|
export function startSketch() {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.START_SKETCH
|
type: ActionTypes.START_SKETCH
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stopSketch() {
|
export function stopSketch() {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.STOP_SKETCH
|
type: ActionTypes.STOP_SKETCH
|
||||||
}
|
};
|
||||||
}
|
}
|
|
@ -1,25 +1,25 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
export function openPreferences() {
|
export function openPreferences() {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.OPEN_PREFERENCES
|
type: ActionTypes.OPEN_PREFERENCES
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function closePreferences() {
|
export function closePreferences() {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.CLOSE_PREFERENCES
|
type: ActionTypes.CLOSE_PREFERENCES
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function increaseFont() {
|
export function increaseFont() {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.INCREASE_FONTSIZE
|
type: ActionTypes.INCREASE_FONTSIZE
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decreaseFont() {
|
export function decreaseFont() {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.DECREASE_FONTSIZE
|
type: ActionTypes.DECREASE_FONTSIZE
|
||||||
}
|
};
|
||||||
}
|
}
|
|
@ -1,89 +1,91 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
import { browserHistory } from 'react-router'
|
import { browserHistory } from 'react-router';
|
||||||
import axios from 'axios'
|
import axios from 'axios';
|
||||||
|
|
||||||
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
||||||
|
|
||||||
export function getProject(id) {
|
export function getProject(id) {
|
||||||
return function(dispatch) {
|
return (dispatch) => {
|
||||||
axios.get(`${ROOT_URL}/projects/${id}`, {withCredentials: true})
|
axios.get(`${ROOT_URL}/projects/${id}`, { withCredentials: true })
|
||||||
.then(response => {
|
.then(response => {
|
||||||
browserHistory.push(`/projects/${id}`);
|
browserHistory.push(`/projects/${id}`);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.SET_PROJECT_NAME,
|
type: ActionTypes.SET_PROJECT_NAME,
|
||||||
project: response.data
|
project: response.data
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.catch(response => dispatch({
|
.catch(response => dispatch({
|
||||||
type: ActionTypes.ERROR
|
type: ActionTypes.ERROR,
|
||||||
}));
|
error: response.data
|
||||||
}
|
}));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setProjectName(event) {
|
export function setProjectName(event) {
|
||||||
var name = event.target.textContent;
|
const name = event.target.textContent;
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.SET_PROJECT_NAME,
|
type: ActionTypes.SET_PROJECT_NAME,
|
||||||
name: name
|
name
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveProject() {
|
export function saveProject() {
|
||||||
return function(dispatch, getState) {
|
return (dispatch, getState) => {
|
||||||
var state = getState();
|
const state = getState();
|
||||||
var formParams = Object.assign({}, state.project);
|
const formParams = Object.assign({}, state.project);
|
||||||
formParams.file = state.file;
|
formParams.file = state.file;
|
||||||
debugger;
|
if (state.id) {
|
||||||
if (state.id) {
|
axios.put(`${ROOT_URL}/projects/${state.id}`, formParams, { withCredentials: true })
|
||||||
axios.put(`${ROOT_URL}/projects/${state.id}`, formParams, {withCredentials: true})
|
.then(() => {
|
||||||
.then(response => {
|
dispatch({
|
||||||
dispatch({
|
type: ActionTypes.PROJECT_SAVE_SUCCESS
|
||||||
type: ActionTypes.PROJECT_SAVE_SUCCESS
|
})
|
||||||
})
|
.catch((response) => dispatch({
|
||||||
.catch(response => dispatch({
|
type: ActionTypes.PROJECT_SAVE_FAIL,
|
||||||
type: ActionTypes.PROJECT_SAVE_FAIL
|
error: response.data
|
||||||
}));
|
}));
|
||||||
})
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
axios.post(`${ROOT_URL}/projects`, formParams, { withCredentials: true })
|
||||||
axios.post(`${ROOT_URL}/projects`, formParams, {withCredentials: true})
|
.then(response => {
|
||||||
.then(response => {
|
browserHistory.push(`/projects/${response.data.id}`);
|
||||||
browserHistory.push('/projects/' + response.data.id);
|
dispatch({
|
||||||
dispatch({
|
type: ActionTypes.NEW_PROJECT,
|
||||||
type: ActionTypes.NEW_PROJECT,
|
name: response.data.name,
|
||||||
name: response.data.name,
|
id: response.data.id,
|
||||||
id: response.data.id,
|
file: {
|
||||||
file: {
|
name: response.data.file.name,
|
||||||
name: response.data.file.name,
|
content: response.data.file.content
|
||||||
content: response.data.file.content
|
}
|
||||||
}
|
});
|
||||||
});
|
})
|
||||||
})
|
.catch(response => dispatch({
|
||||||
.catch(response => dispatch({
|
type: ActionTypes.PROJECT_SAVE_FAIL,
|
||||||
type: ActionTypes.PROJECT_SAVE_FAIL
|
error: response.data
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function createProject() {
|
export function createProject() {
|
||||||
return function(dispatch) {
|
return (dispatch) => {
|
||||||
axios.post(`${ROOT_URL}/projects`, {}, {withCredentials: true})
|
axios.post(`${ROOT_URL}/projects`, {}, { withCredentials: true })
|
||||||
.then(response => {
|
.then(response => {
|
||||||
browserHistory.push('/projects/' + response.data.id);
|
browserHistory.push(`/projects/${response.data.id}`);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.NEW_PROJECT,
|
type: ActionTypes.NEW_PROJECT,
|
||||||
name: response.data.name,
|
name: response.data.name,
|
||||||
id: response.data.id,
|
id: response.data.id,
|
||||||
file: {
|
file: {
|
||||||
name: response.data.file.name,
|
name: response.data.file.name,
|
||||||
content: response.data.file.content
|
content: response.data.file.content
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(response => dispatch({
|
.catch(response => dispatch({
|
||||||
type: ActionTypes.PROJECT_SAVE_FAIL
|
type: ActionTypes.PROJECT_SAVE_FAIL,
|
||||||
}));
|
error: response.data
|
||||||
}
|
}));
|
||||||
|
};
|
||||||
}
|
}
|
43
client/modules/IDE/components/Editor.js
Normal file
43
client/modules/IDE/components/Editor.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import React from 'react';
|
||||||
|
import CodeMirror from 'codemirror';
|
||||||
|
import 'codemirror/mode/javascript/javascript';
|
||||||
|
import 'codemirror/addon/selection/active-line';
|
||||||
|
|
||||||
|
class Editor extends React.Component {
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this._cm = CodeMirror(this.refs.container, { // eslint-disable-line
|
||||||
|
theme: 'p5-widget',
|
||||||
|
value: this.props.content,
|
||||||
|
lineNumbers: true,
|
||||||
|
styleActiveLine: true,
|
||||||
|
mode: 'javascript'
|
||||||
|
});
|
||||||
|
this._cm.on('change', () => { // eslint-disable-line
|
||||||
|
this.props.updateFile('sketch.js', this._cm.getValue());
|
||||||
|
});
|
||||||
|
this._cm.getWrapperElement().style['font-size'] = `${this.props.fontSize}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (this.props.content !== prevProps.content &&
|
||||||
|
this.props.content !== this._cm.getValue()) {
|
||||||
|
this._cm.setValue(this.props.content); // eslint-disable-line no-underscore-dangle
|
||||||
|
}
|
||||||
|
if (this.props.fontSize !== prevProps.fontSize) {
|
||||||
|
this._cm.getWrapperElement().style['font-size'] = `${this.props.fontSize}px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._cm = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cm: CodeMirror.Editor
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <div ref="container" className="editor-holder"></div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Editor;
|
|
@ -1,42 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import CodeMirror from 'codemirror';
|
|
||||||
import 'codemirror/mode/javascript/javascript';
|
|
||||||
import 'codemirror/addon/selection/active-line'
|
|
||||||
|
|
||||||
class Editor extends React.Component {
|
|
||||||
_cm: CodeMirror.Editor
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this._cm = CodeMirror(this.refs.container, {
|
|
||||||
theme: 'p5-widget',
|
|
||||||
value: this.props.content,
|
|
||||||
lineNumbers: true,
|
|
||||||
styleActiveLine: true,
|
|
||||||
mode: 'javascript'
|
|
||||||
});
|
|
||||||
this._cm.on('change', () => {
|
|
||||||
this.props.updateFile("sketch.js", this._cm.getValue());
|
|
||||||
});
|
|
||||||
this._cm.getWrapperElement().style['font-size'] = this.props.fontSize+'px';
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
if (this.props.content !== prevProps.content &&
|
|
||||||
this.props.content !== this._cm.getValue()) {
|
|
||||||
this._cm.setValue(this.props.content);
|
|
||||||
}
|
|
||||||
if (this.props.fontSize !== prevProps.fontSize) {
|
|
||||||
this._cm.getWrapperElement().style['font-size'] = this.props.fontSize+'px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this._cm = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <div ref="container" className="editor-holder"></div>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Editor;
|
|
38
client/modules/IDE/components/Preferences.js
Normal file
38
client/modules/IDE/components/Preferences.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Isvg = require('react-inlinesvg');
|
||||||
|
const exitUrl = require('../../../images/exit.svg');
|
||||||
|
const plusUrl = require('../../../images/plus.svg');
|
||||||
|
const minusUrl = require('../../../images/minus.svg');
|
||||||
|
const classNames = require('classnames');
|
||||||
|
|
||||||
|
class Preferences extends React.Component {
|
||||||
|
render() {
|
||||||
|
const preferencesContainerClass = classNames({
|
||||||
|
preferences: true,
|
||||||
|
'preferences--selected': this.props.isVisible
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div className={preferencesContainerClass} tabIndex="0">
|
||||||
|
<div className="preferences__heading">
|
||||||
|
<h2 className="preferences__title">Preferences</h2>
|
||||||
|
<button className="preferences__exit-button" onClick={this.props.closePreferences}>
|
||||||
|
<Isvg src={exitUrl} alt="Exit Preferences" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="preference">
|
||||||
|
<h3 className="preference__title">Text Size</h3>
|
||||||
|
<button className="preference__plus-button" onClick={this.props.decreaseFont}>
|
||||||
|
<Isvg src={minusUrl} alt="Decrease Font Size" />
|
||||||
|
</button>
|
||||||
|
<p className="preference__value">{this.props.fontSize}</p>
|
||||||
|
<button className="preference__minus-button" onClick={this.props.increaseFont}>
|
||||||
|
<Isvg src={plusUrl} alt="Increase Font Size" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Preferences;
|
|
@ -1,38 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
var Isvg = require('react-inlinesvg');
|
|
||||||
var exitUrl = require('../../../images/exit.svg');
|
|
||||||
var plusUrl = require('../../../images/plus.svg');
|
|
||||||
var minusUrl = require('../../../images/minus.svg');
|
|
||||||
var classNames = require('classnames');
|
|
||||||
|
|
||||||
class Preferences extends React.Component {
|
|
||||||
render() {
|
|
||||||
let preferencesContainerClass = classNames({
|
|
||||||
"preferences": true,
|
|
||||||
"preferences--selected": this.props.isVisible
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<div className={preferencesContainerClass} tabindex="0">
|
|
||||||
<div className="preferences__heading">
|
|
||||||
<h2 className="preferences__title">Preferences</h2>
|
|
||||||
<button className="preferences__exit-button" onClick={this.props.closePreferences}>
|
|
||||||
<Isvg src={exitUrl} alt="Exit Preferences" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="preference">
|
|
||||||
<h3 className="preference__title">Text Size</h3>
|
|
||||||
<button className="preference__plus-button" onClick={this.props.decreaseFont}>
|
|
||||||
<Isvg src={minusUrl} alt="Decrease Font Size" />
|
|
||||||
</button>
|
|
||||||
<p className="preference__value">{this.props.fontSize}</p>
|
|
||||||
<button className="preference__minus-button" onClick={this.props.increaseFont}>
|
|
||||||
<Isvg src={plusUrl} alt="Increase Font Size" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Preferences;
|
|
20
client/modules/IDE/components/Preview.js
Normal file
20
client/modules/IDE/components/Preview.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class Preview extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.0/p5.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
{this.props.content}
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Preview;
|
|
@ -1,21 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
|
|
||||||
class Preview extends React.Component {
|
|
||||||
componentDidMount() {
|
|
||||||
console.log(ReactDOM.findDOMNode(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.0/p5.min.js"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
{this.props.content}
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Preview;
|
|
67
client/modules/IDE/components/PreviewFrame.js
Normal file
67
client/modules/IDE/components/PreviewFrame.js
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
class PreviewFrame extends React.Component {
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.isPlaying) {
|
||||||
|
this.renderFrameContents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearPreview() {
|
||||||
|
const doc = ReactDOM.findDOMNode(this).contentDocument;
|
||||||
|
doc.write('');
|
||||||
|
doc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderFrameContents() {
|
||||||
|
const doc = ReactDOM.findDOMNode(this).contentDocument;
|
||||||
|
if (doc.readyState === 'complete') {
|
||||||
|
renderSketch();
|
||||||
|
} else {
|
||||||
|
setTimeout(this.renderFrameContents, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSketch() {
|
||||||
|
const doc = ReactDOM.findDOMNode(this).contentDocument;
|
||||||
|
this.clearPreview();
|
||||||
|
ReactDOM.render(this.props.head, doc.head);
|
||||||
|
const p5Script = doc.createElement('script');
|
||||||
|
p5Script.setAttribute('src', 'https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.0/p5.min.js');
|
||||||
|
doc.body.appendChild(p5Script);
|
||||||
|
|
||||||
|
const sketchScript = doc.createElement('script');
|
||||||
|
sketchScript.textContent = this.props.content;
|
||||||
|
doc.body.appendChild(sketchScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps, prevState) {
|
||||||
|
if (this.props.isPlaying !== prevProps.isPlaying) {
|
||||||
|
if (this.props.isPlaying) {
|
||||||
|
this.renderSketch();
|
||||||
|
} else {
|
||||||
|
this.clearPreview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.isPlaying && this.props.content !== prevProps.content) {
|
||||||
|
this.renderSketch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).contentDocument.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <iframe
|
||||||
|
className="preview-frame"
|
||||||
|
frameBorder="0"
|
||||||
|
sandbox="allow-scripts allow-pointer-lock allow-same-origin allow-popups allow-modals allow-forms"
|
||||||
|
title="sketch output"></iframe>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PreviewFrame;
|
|
@ -1,64 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
|
|
||||||
class PreviewFrame extends React.Component {
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (this.props.isPlaying) {
|
|
||||||
this.renderFrameContents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderFrameContents() {
|
|
||||||
let doc = ReactDOM.findDOMNode(this).contentDocument;
|
|
||||||
if(doc.readyState === 'complete') {
|
|
||||||
renderSketch();
|
|
||||||
} else {
|
|
||||||
setTimeout(this.renderFrameContents, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSketch() {
|
|
||||||
let doc = ReactDOM.findDOMNode(this).contentDocument;
|
|
||||||
this.clearPreview();
|
|
||||||
ReactDOM.render(this.props.head, doc.head);
|
|
||||||
let p5Script = doc.createElement('script');
|
|
||||||
p5Script.setAttribute('src', 'https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.0/p5.min.js');
|
|
||||||
doc.body.appendChild(p5Script);
|
|
||||||
|
|
||||||
let sketchScript = doc.createElement('script');
|
|
||||||
sketchScript.textContent = this.props.content;
|
|
||||||
doc.body.appendChild(sketchScript);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearPreview() {
|
|
||||||
let doc = ReactDOM.findDOMNode(this).contentDocument;
|
|
||||||
doc.write('');
|
|
||||||
doc.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
|
||||||
if (this.props.isPlaying != prevProps.isPlaying) {
|
|
||||||
if (this.props.isPlaying) {
|
|
||||||
this.renderSketch();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.clearPreview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.isPlaying && this.props.content != prevProps.content) {
|
|
||||||
this.renderSketch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).contentDocument.body);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <iframe className="preview-frame" frameBorder="0" sandbox="allow-scripts allow-pointer-lock allow-same-origin allow-popups allow-modals allow-forms" title="sketch output"></iframe>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PreviewFrame;
|
|
52
client/modules/IDE/components/Toolbar.js
Normal file
52
client/modules/IDE/components/Toolbar.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Isvg = require('react-inlinesvg');
|
||||||
|
const playUrl = require('../../../images/play.svg');
|
||||||
|
const logoUrl = require('../../../images/p5js-logo.svg');
|
||||||
|
const stopUrl = require('../../../images/stop.svg');
|
||||||
|
const preferencesUrl = require('../../../images/preferences.svg');
|
||||||
|
const classNames = require('classnames');
|
||||||
|
|
||||||
|
class Toolbar extends React.Component {
|
||||||
|
render() {
|
||||||
|
let playButtonClass = classNames({
|
||||||
|
'toolbar__play-button': true,
|
||||||
|
'toolbar__play-button--selected': this.props.isPlaying
|
||||||
|
});
|
||||||
|
let stopButtonClass = classNames({
|
||||||
|
'toolbar__stop-button': true,
|
||||||
|
'toolbar__stop-button--selected': !this.props.isPlaying
|
||||||
|
});
|
||||||
|
let preferencesButtonClass = classNames({
|
||||||
|
'toolbar__preferences-button': true,
|
||||||
|
'toolbar__preferences-button--selected': this.props.isPreferencesVisible
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="toolbar">
|
||||||
|
<img className="toolbar__logo" src={logoUrl} alt="p5js Logo" />
|
||||||
|
<button className={playButtonClass} onClick={this.props.startSketch}>
|
||||||
|
<Isvg src={playUrl} alt="Play Sketch" />
|
||||||
|
</button>
|
||||||
|
<button className={stopButtonClass} onClick={this.props.stopSketch}>
|
||||||
|
<Isvg src={stopUrl} alt="Stop Sketch" />
|
||||||
|
</button>
|
||||||
|
<div className="toolbar__project-name-container">
|
||||||
|
<span
|
||||||
|
className="toolbar__project-name"
|
||||||
|
onBlur={this.props.setProjectName.bind(this)}
|
||||||
|
contentEditable
|
||||||
|
suppressContentEditableWarning
|
||||||
|
>
|
||||||
|
{this.props.projectName}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button className={preferencesButtonClass} onClick={this.props.openPreferences}>
|
||||||
|
<Isvg src={preferencesUrl} alt="Show Preferences" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Toolbar;
|
|
@ -1,50 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
var Isvg = require('react-inlinesvg');
|
|
||||||
var playUrl = require('../../../images/play.svg');
|
|
||||||
var logoUrl = require('../../../images/p5js-logo.svg');
|
|
||||||
var stopUrl = require('../../../images/stop.svg');
|
|
||||||
var preferencesUrl = require('../../../images/preferences.svg');
|
|
||||||
var classNames = require('classnames');
|
|
||||||
|
|
||||||
class Toolbar extends React.Component {
|
|
||||||
render() {
|
|
||||||
let playButtonClass = classNames({
|
|
||||||
"toolbar__play-button": true,
|
|
||||||
"toolbar__play-button--selected": this.props.isPlaying
|
|
||||||
});
|
|
||||||
let stopButtonClass = classNames({
|
|
||||||
"toolbar__stop-button": true,
|
|
||||||
"toolbar__stop-button--selected": !this.props.isPlaying
|
|
||||||
});
|
|
||||||
let preferencesButtonClass = classNames({
|
|
||||||
"toolbar__preferences-button": true,
|
|
||||||
"toolbar__preferences-button--selected": this.props.isPreferencesVisible
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="toolbar">
|
|
||||||
<img className="toolbar__logo" src={logoUrl} alt="p5js Logo"/>
|
|
||||||
<button className={playButtonClass} onClick={this.props.startSketch}>
|
|
||||||
<Isvg src={playUrl} alt="Play Sketch" />
|
|
||||||
</button>
|
|
||||||
<button className={stopButtonClass} onClick={this.props.stopSketch}>
|
|
||||||
<Isvg src={stopUrl} alt="Stop Sketch" />
|
|
||||||
</button>
|
|
||||||
<div className="toolbar__project-name-container">
|
|
||||||
<span className="toolbar__project-name"
|
|
||||||
onBlur={this.props.setProjectName.bind(this)}
|
|
||||||
contentEditable={true}
|
|
||||||
suppressContentEditableWarning={true}>
|
|
||||||
{this.props.projectName}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<button className={preferencesButtonClass} onClick={this.props.openPreferences}>
|
|
||||||
<Isvg src={preferencesUrl} alt="Show Preferences" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Toolbar;
|
|
83
client/modules/IDE/pages/IDEView.js
Normal file
83
client/modules/IDE/pages/IDEView.js
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Editor from '../components/Editor';
|
||||||
|
import PreviewFrame from '../components/PreviewFrame';
|
||||||
|
import Toolbar from '../components/Toolbar';
|
||||||
|
import Preferences from '../components/Preferences';
|
||||||
|
import Nav from '../../../components/Nav';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import * as FileActions from '../actions/files';
|
||||||
|
import * as IDEActions from '../actions/ide';
|
||||||
|
import * as PreferencesActions from '../actions/preferences';
|
||||||
|
import * as ProjectActions from '../actions/project';
|
||||||
|
|
||||||
|
class IDEView extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.params.project_id) {
|
||||||
|
const id = this.props.params.project_id;
|
||||||
|
this.props.getProject(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="ide">
|
||||||
|
<Nav
|
||||||
|
user={this.props.user}
|
||||||
|
createProject={this.props.createProject}
|
||||||
|
saveProject={this.props.saveProject}
|
||||||
|
/>
|
||||||
|
<Toolbar
|
||||||
|
className="Toolbar"
|
||||||
|
isPlaying={this.props.ide.isPlaying}
|
||||||
|
startSketch={this.props.startSketch}
|
||||||
|
stopSketch={this.props.stopSketch}
|
||||||
|
projectName={this.props.project.name}
|
||||||
|
setProjectName={this.props.setProjectName}
|
||||||
|
openPreferences={this.props.openPreferences}
|
||||||
|
isPreferencesVisible={this.props.preferences.isVisible}
|
||||||
|
/>
|
||||||
|
<Preferences
|
||||||
|
isVisible={this.props.preferences.isVisible}
|
||||||
|
closePreferences={this.props.closePreferences}
|
||||||
|
increaseFont={this.props.increaseFont}
|
||||||
|
decreaseFont={this.props.decreaseFont}
|
||||||
|
fontSize={this.props.preferences.fontSize}
|
||||||
|
/>
|
||||||
|
<Editor
|
||||||
|
content={this.props.file.content}
|
||||||
|
updateFile={this.props.updateFile}
|
||||||
|
fontSize={this.props.preferences.fontSize}
|
||||||
|
/>
|
||||||
|
<PreviewFrame
|
||||||
|
content={this.props.file.content}
|
||||||
|
head={
|
||||||
|
<link type="text/css" rel="stylesheet" href="/preview-styles.css" />
|
||||||
|
}
|
||||||
|
isPlaying={this.props.ide.isPlaying}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
file: state.file,
|
||||||
|
ide: state.ide,
|
||||||
|
preferences: state.preferences,
|
||||||
|
user: state.user,
|
||||||
|
project: state.project
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return bindActionCreators(Object.assign({},
|
||||||
|
FileActions,
|
||||||
|
ProjectActions,
|
||||||
|
IDEActions,
|
||||||
|
PreferencesActions),
|
||||||
|
dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(IDEView);
|
|
@ -1,72 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import Editor from '../components/Editor'
|
|
||||||
import PreviewFrame from '../components/PreviewFrame'
|
|
||||||
import Toolbar from '../components/Toolbar'
|
|
||||||
import Preferences from '../components/Preferences'
|
|
||||||
import Nav from '../../../components/Nav'
|
|
||||||
import { bindActionCreators } from 'redux'
|
|
||||||
import { connect } from 'react-redux'
|
|
||||||
import * as FileActions from '../actions/files'
|
|
||||||
import * as IDEActions from '../actions/ide'
|
|
||||||
import * as PreferencesActions from '../actions/preferences'
|
|
||||||
import * as ProjectActions from '../actions/project'
|
|
||||||
|
|
||||||
class IDEView extends React.Component {
|
|
||||||
componentDidMount() {
|
|
||||||
if (this.props.params.project_id) {
|
|
||||||
const id = this.props.params.project_id
|
|
||||||
this.props.getProject(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="ide">
|
|
||||||
<Nav user={this.props.user}
|
|
||||||
createProject={this.props.createProject}
|
|
||||||
saveProject={this.props.saveProject}/>
|
|
||||||
<Toolbar
|
|
||||||
className="Toolbar"
|
|
||||||
isPlaying={this.props.ide.isPlaying}
|
|
||||||
startSketch={this.props.startSketch}
|
|
||||||
stopSketch={this.props.stopSketch}
|
|
||||||
projectName={this.props.project.name}
|
|
||||||
setProjectName={this.props.setProjectName}
|
|
||||||
openPreferences={this.props.openPreferences}
|
|
||||||
isPreferencesVisible={this.props.preferences.isVisible}/>
|
|
||||||
<Preferences
|
|
||||||
isVisible={this.props.preferences.isVisible}
|
|
||||||
closePreferences={this.props.closePreferences}
|
|
||||||
increaseFont={this.props.increaseFont}
|
|
||||||
decreaseFont={this.props.decreaseFont}
|
|
||||||
fontSize={this.props.preferences.fontSize}/>
|
|
||||||
<Editor
|
|
||||||
content={this.props.file.content}
|
|
||||||
updateFile={this.props.updateFile}
|
|
||||||
fontSize={this.props.preferences.fontSize} />
|
|
||||||
<PreviewFrame
|
|
||||||
content={this.props.file.content}
|
|
||||||
head={
|
|
||||||
<link type='text/css' rel='stylesheet' href='/preview-styles.css' />
|
|
||||||
}
|
|
||||||
isPlaying={this.props.ide.isPlaying}/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
file: state.file,
|
|
||||||
ide: state.ide,
|
|
||||||
preferences: state.preferences,
|
|
||||||
user: state.user,
|
|
||||||
project: state.project
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
|
||||||
return bindActionCreators(Object.assign({}, FileActions, ProjectActions, IDEActions, PreferencesActions), dispatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(IDEView);
|
|
|
@ -1,45 +1,45 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
name: "sketch.js",
|
name: 'sketch.js',
|
||||||
content: `function setup() {
|
content: `function setup() {
|
||||||
createCanvas(400, 400);
|
createCanvas(400, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
background(220);
|
background(220);
|
||||||
}`
|
}`
|
||||||
}
|
};
|
||||||
|
|
||||||
const file = (state = initialState, action) => {
|
const file = (state = initialState, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.CHANGE_SELECTED_FILE:
|
case ActionTypes.CHANGE_SELECTED_FILE:
|
||||||
return {
|
return {
|
||||||
name: action.name,
|
name: action.name,
|
||||||
content: action.content
|
content: action.content
|
||||||
}
|
};
|
||||||
case ActionTypes.NEW_PROJECT:
|
case ActionTypes.NEW_PROJECT:
|
||||||
return {
|
return {
|
||||||
name: action.file.name,
|
name: action.file.name,
|
||||||
content: action.file.conent
|
content: action.file.conent
|
||||||
}
|
};
|
||||||
default:
|
default:
|
||||||
return state
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export default file;
|
export default file;
|
||||||
|
|
||||||
//i'll add this in when there are multiple files
|
// i'll add this in when there are multiple files
|
||||||
// const files = (state = [], action) => {
|
// const files = (state = [], action) => {
|
||||||
// switch (action.type) {
|
// switch (action.type) {
|
||||||
// case ActionTypes.CHANGE_SELECTED_FILE:
|
// case ActionTypes.CHANGE_SELECTED_FILE:
|
||||||
// //find the file with the name
|
// //find the file with the name
|
||||||
// //update it
|
// //update it
|
||||||
// //put in into the new array of files
|
// //put in into the new array of files
|
||||||
// default:
|
// default:
|
||||||
// return state
|
// return state
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// export default files
|
// export default files
|
|
@ -1,26 +1,26 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
isPlaying: false
|
isPlaying: false
|
||||||
}
|
};
|
||||||
|
|
||||||
const ide = (state = initialState, action) => {
|
const ide = (state = initialState, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.TOGGLE_SKETCH:
|
case ActionTypes.TOGGLE_SKETCH:
|
||||||
return {
|
return {
|
||||||
isPlaying: !state.isPlaying
|
isPlaying: !state.isPlaying
|
||||||
}
|
};
|
||||||
case ActionTypes.START_SKETCH:
|
case ActionTypes.START_SKETCH:
|
||||||
return {
|
return {
|
||||||
isPlaying: true
|
isPlaying: true
|
||||||
}
|
};
|
||||||
case ActionTypes.STOP_SKETCH:
|
case ActionTypes.STOP_SKETCH:
|
||||||
return {
|
return {
|
||||||
isPlaying: false
|
isPlaying: false
|
||||||
}
|
};
|
||||||
default:
|
default:
|
||||||
return state
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ide;
|
export default ide;
|
|
@ -1,35 +1,35 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
isVisible: false,
|
isVisible: false,
|
||||||
fontSize: 18
|
fontSize: 18
|
||||||
}
|
};
|
||||||
|
|
||||||
const preferences = (state = initialState, action) => {
|
const preferences = (state = initialState, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.OPEN_PREFERENCES:
|
case ActionTypes.OPEN_PREFERENCES:
|
||||||
return {
|
return {
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
fontSize: state.fontSize
|
fontSize: state.fontSize
|
||||||
}
|
};
|
||||||
case ActionTypes.CLOSE_PREFERENCES:
|
case ActionTypes.CLOSE_PREFERENCES:
|
||||||
return {
|
return {
|
||||||
isVisible: false,
|
isVisible: false,
|
||||||
fontSize: state.fontSize
|
fontSize: state.fontSize
|
||||||
}
|
};
|
||||||
case ActionTypes.INCREASE_FONTSIZE:
|
case ActionTypes.INCREASE_FONTSIZE:
|
||||||
return {
|
return {
|
||||||
isVisible: state.isVisible,
|
isVisible: state.isVisible,
|
||||||
fontSize: state.fontSize+2
|
fontSize: state.fontSize + 2
|
||||||
}
|
};
|
||||||
case ActionTypes.DECREASE_FONTSIZE:
|
case ActionTypes.DECREASE_FONTSIZE:
|
||||||
return {
|
return {
|
||||||
isVisible: state.isVisible,
|
isVisible: state.isVisible,
|
||||||
fontSize: state.fontSize-2
|
fontSize: state.fontSize - 2
|
||||||
}
|
};
|
||||||
default:
|
default:
|
||||||
return state
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export default preferences;
|
export default preferences;
|
|
@ -1,32 +1,32 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
name: "Hello p5.js"
|
name: 'Hello p5.js'
|
||||||
}
|
};
|
||||||
|
|
||||||
const project = (state = initialState, action) => {
|
const project = (state = initialState, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.SET_PROJECT_NAME:
|
case ActionTypes.SET_PROJECT_NAME:
|
||||||
return {
|
return {
|
||||||
name: action.name
|
name: action.name
|
||||||
}
|
};
|
||||||
case ActionTypes.NEW_PROJECT:
|
case ActionTypes.NEW_PROJECT:
|
||||||
return {
|
return {
|
||||||
id: action.id,
|
id: action.id,
|
||||||
name: action.name
|
name: action.name
|
||||||
}
|
};
|
||||||
case ActionTypes.SET_PROJECT:
|
case ActionTypes.SET_PROJECT:
|
||||||
return {
|
return {
|
||||||
id: action.project.id,
|
id: action.project.id,
|
||||||
name: action.project.name,
|
name: action.project.name,
|
||||||
file: {
|
file: {
|
||||||
name: action.project.file.name,
|
name: action.project.file.name,
|
||||||
content: action.project.file.content
|
content: action.project.file.content
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export default project;
|
export default project;
|
|
@ -1,51 +1,52 @@
|
||||||
import * as ActionTypes from '../../constants'
|
import * as ActionTypes from '../../constants';
|
||||||
import { browserHistory } from 'react-router'
|
import { browserHistory } from 'react-router';
|
||||||
import axios from 'axios'
|
import axios from 'axios';
|
||||||
|
|
||||||
|
|
||||||
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
||||||
|
|
||||||
export function signUpUser(formValues) {
|
|
||||||
return function(dispatch) {
|
|
||||||
axios.post(`${ROOT_URL}/signup`, formValues, {withCredentials: true})
|
|
||||||
.then(response => {
|
|
||||||
dispatch({ type: ActionTypes.AUTH_USER,
|
|
||||||
user: response.data
|
|
||||||
});
|
|
||||||
browserHistory.push('/');
|
|
||||||
})
|
|
||||||
.catch(response => dispatch(authError(response.data.error)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loginUser(formValues) {
|
|
||||||
return function(dispatch) {
|
|
||||||
axios.post(`${ROOT_URL}/login`, formValues, {withCredentials: true})
|
|
||||||
.then(response => {
|
|
||||||
dispatch({ type: ActionTypes.AUTH_USER,
|
|
||||||
user: response.data
|
|
||||||
});
|
|
||||||
browserHistory.push('/');
|
|
||||||
})
|
|
||||||
.catch(response => dispatch(authError(response.data.error)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getUser() {
|
|
||||||
return function(dispatch) {
|
|
||||||
axios.get(`${ROOT_URL}/session`, {withCredentials: true})
|
|
||||||
.then(response => {
|
|
||||||
dispatch({type: ActionTypes.AUTH_USER,
|
|
||||||
user: response.data
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(response => dispatch(authError(response.data.error)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function authError(error) {
|
export function authError(error) {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.AUTH_ERROR,
|
type: ActionTypes.AUTH_ERROR,
|
||||||
payload: error
|
payload: error
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function signUpUser(formValues) {
|
||||||
|
return (dispatch) => {
|
||||||
|
axios.post(`${ROOT_URL}/signup`, formValues, { withCredentials: true })
|
||||||
|
.then(response => {
|
||||||
|
dispatch({ type: ActionTypes.AUTH_USER,
|
||||||
|
user: response.data
|
||||||
|
});
|
||||||
|
browserHistory.push('/');
|
||||||
|
})
|
||||||
|
.catch(response => dispatch(authError(response.data.error)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loginUser(formValues) {
|
||||||
|
return (dispatch) => {
|
||||||
|
axios.post(`${ROOT_URL}/login`, formValues, { withCredentials: true })
|
||||||
|
.then(response => {
|
||||||
|
dispatch({ type: ActionTypes.AUTH_USER,
|
||||||
|
user: response.data
|
||||||
|
});
|
||||||
|
browserHistory.push('/');
|
||||||
|
})
|
||||||
|
.catch(response => dispatch(authError(response.data.error)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUser() {
|
||||||
|
return (dispatch) => {
|
||||||
|
axios.get(`${ROOT_URL}/session`, { withCredentials: true })
|
||||||
|
.then(response => {
|
||||||
|
dispatch({
|
||||||
|
type: ActionTypes.AUTH_USER,
|
||||||
|
user: response.data
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(response => dispatch(authError(response.data.error)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
34
client/modules/User/components/LoginForm.js
Normal file
34
client/modules/User/components/LoginForm.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class LoginForm extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { fields: { email, password }, handleSubmit } = this.props;
|
||||||
|
return (
|
||||||
|
<form className="login-form" onSubmit={handleSubmit(this.props.loginUser.bind(this))}>
|
||||||
|
<p className="login-form__field">
|
||||||
|
<label className="login-form__email-label" htmlFor="email">Email:</label>
|
||||||
|
<input
|
||||||
|
className="login-form__email-input"
|
||||||
|
id="email"
|
||||||
|
type="text"
|
||||||
|
placeholder="Email"
|
||||||
|
{...email}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p className="login-form__field">
|
||||||
|
<label className="signup-form__password-label" htmlFor="password">Password:</label>
|
||||||
|
<input
|
||||||
|
className="signup-form__password-input"
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
placeholder="Password"
|
||||||
|
{...password}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<input type="submit" value="Login" />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoginForm;
|
|
@ -1,22 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
class LoginForm extends React.Component {
|
|
||||||
render() {
|
|
||||||
const {fields: {email, password}, handleSubmit } = this.props;
|
|
||||||
return (
|
|
||||||
<form className="login-form" onSubmit={handleSubmit(this.props.loginUser.bind(this))}>
|
|
||||||
<p className="login-form__field">
|
|
||||||
<label className="login-form__email-label" for="email">Email:</label>
|
|
||||||
<input className="login-form__email-input" id="email" type="text" placeholder="Email" {...email}/>
|
|
||||||
</p>
|
|
||||||
<p className="login-form__field">
|
|
||||||
<label className="signup-form__password-label" for="password">Password:</label>
|
|
||||||
<input className="signup-form__password-input" id="password" type="password" placeholder="Password" {...password}/>
|
|
||||||
</p>
|
|
||||||
<input type="submit" value="Login" />
|
|
||||||
</form>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LoginForm;
|
|
58
client/modules/User/components/SignupForm.js
Normal file
58
client/modules/User/components/SignupForm.js
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class SignupForm extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { fields: { username, email, password, confirmPassword }, handleSubmit } = this.props;
|
||||||
|
return (
|
||||||
|
<form className="signup-form" onSubmit={handleSubmit(this.props.signUpUser.bind(this))}>
|
||||||
|
<p className="signup-form__field">
|
||||||
|
<label className="signup-form__username-label" htmlFor="username">Username:</label>
|
||||||
|
<input
|
||||||
|
className="signup-form__username-input"
|
||||||
|
id="username"
|
||||||
|
type="text"
|
||||||
|
placeholder="Username"
|
||||||
|
{...username}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p className="signup-form__field">
|
||||||
|
<label className="signup-form__email-label" htmlFor="email">Email:</label>
|
||||||
|
<input
|
||||||
|
className="signup-form__email-input"
|
||||||
|
id="email"
|
||||||
|
type="text"
|
||||||
|
placeholder="Email"
|
||||||
|
{...email}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p className="signup-form__field">
|
||||||
|
<label className="signup-form__password-label" htmlFor="password">Password:</label>
|
||||||
|
<input
|
||||||
|
className="signup-form__password-input"
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
placeholder="Password"
|
||||||
|
{...password}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p className="signup-form__field">
|
||||||
|
<label
|
||||||
|
className="signup-form__confirm-password-label"
|
||||||
|
htmlFor="confirm-password">
|
||||||
|
Confirm Password:
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
className="signup-form__confirm-password-input"
|
||||||
|
id="confirm-password"
|
||||||
|
type="password"
|
||||||
|
placeholder="Confirm Password"
|
||||||
|
{...confirmPassword}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<input type="submit" value="Sign Up" />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SignupForm;
|
|
@ -1,30 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
class SignupForm extends React.Component {
|
|
||||||
render() {
|
|
||||||
const {fields: { username, email, password, confirmPassword }, handleSubmit} = this.props;
|
|
||||||
return (
|
|
||||||
<form className="signup-form" onSubmit={handleSubmit(this.props.signUpUser.bind(this))}>
|
|
||||||
<p className="signup-form__field">
|
|
||||||
<label className="signup-form__username-label" for="username">Username:</label>
|
|
||||||
<input className="signup-form__username-input" id="username" type="text" placeholder="Username" {...username}/>
|
|
||||||
</p>
|
|
||||||
<p className="signup-form__field">
|
|
||||||
<label className="signup-form__email-label" for="email">Email:</label>
|
|
||||||
<input className="signup-form__email-input" id="email" type="text" placeholder="Email" {...email}/>
|
|
||||||
</p>
|
|
||||||
<p className="signup-form__field">
|
|
||||||
<label className="signup-form__password-label" for="password">Password:</label>
|
|
||||||
<input className="signup-form__password-input" id="password" type="password" placeholder="Password" {...password}/>
|
|
||||||
</p>
|
|
||||||
<p className="signup-form__field">
|
|
||||||
<label className="signup-form__confirm-password-label" for="confirm-password">Confirm Password:</label>
|
|
||||||
<input className="signup-form__confirm-password-input" id="confirm-password" type="password" placeholder="Confirm Password" {...confirmPassword}/>
|
|
||||||
</p>
|
|
||||||
<input type="submit" value="Sign Up" />
|
|
||||||
</form>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SignupForm;
|
|
37
client/modules/User/pages/LoginView.js
Normal file
37
client/modules/User/pages/LoginView.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import { reduxForm } from 'redux-form';
|
||||||
|
import * as UserActions from '../actions';
|
||||||
|
import LoginForm from '../components/LoginForm';
|
||||||
|
|
||||||
|
class LoginView extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="login">
|
||||||
|
<h1>Login</h1>
|
||||||
|
<LoginForm {...this.props} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
user: state.user
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return bindActionCreators(UserActions, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate(formProps) {
|
||||||
|
const errors = {};
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default reduxForm({
|
||||||
|
form: 'login',
|
||||||
|
fields: ['email', 'password'],
|
||||||
|
validate
|
||||||
|
}, mapStateToProps, mapDispatchToProps)(LoginView);
|
|
@ -1,37 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { bindActionCreators } from 'redux'
|
|
||||||
import {reduxForm} from 'redux-form'
|
|
||||||
import * as UserActions from '../actions'
|
|
||||||
import LoginForm from '../components/LoginForm'
|
|
||||||
|
|
||||||
class LoginView extends React.Component {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="login">
|
|
||||||
<h1>Login</h1>
|
|
||||||
<LoginForm {...this.props} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
user: state.user
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
|
||||||
return bindActionCreators(UserActions, dispatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
function validate(formProps) {
|
|
||||||
const errors = {};
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default reduxForm({
|
|
||||||
form: 'login',
|
|
||||||
fields: ['email', 'password'],
|
|
||||||
validate
|
|
||||||
}, mapStateToProps, mapDispatchToProps)(LoginView);
|
|
38
client/modules/User/pages/SignupView.js
Normal file
38
client/modules/User/pages/SignupView.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import * as UserActions from '../actions';
|
||||||
|
import { reduxForm } from 'redux-form';
|
||||||
|
import SignupForm from '../components/SignupForm';
|
||||||
|
|
||||||
|
class SignupView extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="signup">
|
||||||
|
<h1>Sign Up</h1>
|
||||||
|
<SignupForm {...this.props} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
user: state.user
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return bindActionCreators(UserActions, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate(formProps) {
|
||||||
|
const errors = {};
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// export default connect(mapStateToProps, mapDispatchToProps)(SignupView);
|
||||||
|
export default reduxForm({
|
||||||
|
form: 'signup',
|
||||||
|
fields: ['username', 'email', 'password', 'passwordConfirm'],
|
||||||
|
validate
|
||||||
|
}, mapStateToProps, mapDispatchToProps)(SignupView);
|
|
@ -1,39 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { bindActionCreators } from 'redux'
|
|
||||||
import { connect } from 'react-redux'
|
|
||||||
import * as UserActions from '../actions'
|
|
||||||
import { reduxForm } from 'redux-form'
|
|
||||||
import SignupForm from '../components/SignupForm'
|
|
||||||
|
|
||||||
class SignupView extends React.Component {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="signup">
|
|
||||||
<h1>Sign Up</h1>
|
|
||||||
<SignupForm {...this.props} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
user: state.user
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
|
||||||
return bindActionCreators(UserActions, dispatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
function validate(formProps) {
|
|
||||||
const errors = {};
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
// export default connect(mapStateToProps, mapDispatchToProps)(SignupView);
|
|
||||||
export default reduxForm({
|
|
||||||
form: 'signup',
|
|
||||||
fields: ['username', 'email', 'password', 'passwordConfirm'],
|
|
||||||
validate
|
|
||||||
}, mapStateToProps, mapDispatchToProps)(SignupView);
|
|
|
@ -1,17 +1,17 @@
|
||||||
import * as ActionTypes from '../../constants'
|
import * as ActionTypes from '../../constants';
|
||||||
|
|
||||||
const user = (state = {authenticated: false}, action) => {
|
const user = (state = { authenticated: false }, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.AUTH_USER:
|
case ActionTypes.AUTH_USER:
|
||||||
return { ...action.user,
|
return { ...action.user,
|
||||||
authenticated: true };
|
authenticated: true };
|
||||||
case ActionTypes.AUTH_ERROR:
|
case ActionTypes.AUTH_ERROR:
|
||||||
return {
|
return {
|
||||||
authenticated: false
|
authenticated: false
|
||||||
}
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export default user;
|
export default user;
|
|
@ -1,18 +1,18 @@
|
||||||
import { combineReducers } from 'redux'
|
import { combineReducers } from 'redux';
|
||||||
import file from './modules/IDE/reducers/files'
|
import file from './modules/IDE/reducers/files';
|
||||||
import ide from './modules/IDE/reducers/ide'
|
import ide from './modules/IDE/reducers/ide';
|
||||||
import preferences from './modules/IDE/reducers/preferences'
|
import preferences from './modules/IDE/reducers/preferences';
|
||||||
import project from './modules/IDE/reducers/project'
|
import project from './modules/IDE/reducers/project';
|
||||||
import user from './modules/User/reducers'
|
import user from './modules/User/reducers';
|
||||||
import { reducer as form } from 'redux-form'
|
import { reducer as form } from 'redux-form';
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
form,
|
form,
|
||||||
ide,
|
ide,
|
||||||
file,
|
file,
|
||||||
preferences,
|
preferences,
|
||||||
user,
|
user,
|
||||||
project
|
project
|
||||||
})
|
});
|
||||||
|
|
||||||
export default rootReducer
|
export default rootReducer;
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { Route, IndexRoute } from 'react-router'
|
import { Route, IndexRoute } from 'react-router';
|
||||||
import React from 'react'
|
import React from 'react';
|
||||||
import App from './modules/App/App'
|
import App from './modules/App/App';
|
||||||
import IDEView from './modules/IDE/pages/IDEView'
|
import IDEView from './modules/IDE/pages/IDEView';
|
||||||
import LoginView from './modules/User/pages/LoginView'
|
import LoginView from './modules/User/pages/LoginView';
|
||||||
import SignupView from './modules/User/pages/SignupView'
|
import SignupView from './modules/User/pages/SignupView';
|
||||||
import { getUser } from './modules/User/actions'
|
import { getUser } from './modules/User/actions';
|
||||||
|
|
||||||
const routes = (store) => {
|
|
||||||
return (
|
|
||||||
<Route path="/" component={App}>
|
|
||||||
<IndexRoute component={IDEView} onEnter={checkAuth(store)}/>
|
|
||||||
<Route path="/login" component={LoginView}/>
|
|
||||||
<Route path="/signup" component={SignupView}/>
|
|
||||||
<Route path="/projects/:project_id" component={IDEView}/>
|
|
||||||
</Route>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkAuth = (store) => {
|
const checkAuth = (store) => {
|
||||||
store.dispatch(getUser());
|
store.dispatch(getUser());
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const routes = (store) => {
|
||||||
|
return (
|
||||||
|
<Route path="/" component={App}>
|
||||||
|
<IndexRoute component={IDEView} onEnter={checkAuth(store)} />
|
||||||
|
<Route path="/login" component={LoginView} />
|
||||||
|
<Route path="/signup" component={SignupView} />
|
||||||
|
<Route path="/projects/:project_id" component={IDEView} />
|
||||||
|
</Route>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default routes;
|
export default routes;
|
|
@ -1,10 +1,9 @@
|
||||||
import { createStore, applyMiddleware, compose } from 'redux'
|
import { createStore, applyMiddleware, compose } from 'redux';
|
||||||
import thunk from 'redux-thunk'
|
import thunk from 'redux-thunk';
|
||||||
import DevTools from './modules/App/components/DevTools'
|
import DevTools from './modules/App/components/DevTools';
|
||||||
import rootReducer from './reducers'
|
import rootReducer from './reducers';
|
||||||
|
|
||||||
export default function configureStore(initialState) {
|
export default function configureStore(initialState) {
|
||||||
|
|
||||||
const enhancers = [
|
const enhancers = [
|
||||||
applyMiddleware(thunk),
|
applyMiddleware(thunk),
|
||||||
];
|
];
|
||||||
|
@ -18,15 +17,16 @@ export default function configureStore(initialState) {
|
||||||
rootReducer,
|
rootReducer,
|
||||||
initialState,
|
initialState,
|
||||||
compose(...enhancers)
|
compose(...enhancers)
|
||||||
)
|
);
|
||||||
|
|
||||||
if (module.hot) {
|
if (module.hot) {
|
||||||
// Enable Webpack hot module replacement for reducers
|
// Enable Webpack hot module replacement for reducers
|
||||||
module.hot.accept('./reducers', () => {
|
module.hot.accept('./reducers', () => {
|
||||||
const nextRootReducer = require('./reducers').default
|
const nextRootReducer = require('./reducers').default; // eslint-disable-line global-require
|
||||||
store.replaceReducer(nextRootReducer)
|
store.replaceReducer(nextRootReducer);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return store
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/catarak/p5.js-web-editor"
|
"url": "git+https://github.com/catarak/p5.js-web-editor.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^6.1.0",
|
"babel-eslint": "^6.1.0",
|
||||||
|
@ -56,6 +56,7 @@
|
||||||
"connect-mongo": "^1.2.0",
|
"connect-mongo": "^1.2.0",
|
||||||
"cookie-parser": "^1.4.1",
|
"cookie-parser": "^1.4.1",
|
||||||
"dotenv": "^2.0.0",
|
"dotenv": "^2.0.0",
|
||||||
|
"eslint-loader": "^1.3.0",
|
||||||
"express": "^4.13.4",
|
"express": "^4.13.4",
|
||||||
"express-session": "^1.13.0",
|
"express-session": "^1.13.0",
|
||||||
"mongoose": "^4.4.16",
|
"mongoose": "^4.4.16",
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
const passport = require('passport');
|
const passport = require('passport');
|
||||||
const GitHubStrategy = require('passport-github').Strategy;
|
// const GitHubStrategy = require('passport-github').Strategy;
|
||||||
const LocalStrategy = require('passport-local').Strategy;
|
const LocalStrategy = require('passport-local').Strategy;
|
||||||
|
|
||||||
import User from '../models/user'
|
import User from '../models/user';
|
||||||
|
|
||||||
passport.serializeUser((user, done) => {
|
passport.serializeUser((user, done) => {
|
||||||
done(null, user.id);
|
done(null, user.id);
|
||||||
|
@ -18,23 +18,27 @@ passport.deserializeUser((id, done) => {
|
||||||
* Sign in using Email and Password.
|
* Sign in using Email and Password.
|
||||||
*/
|
*/
|
||||||
passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
|
passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
|
||||||
User.findOne({ email: email.toLowerCase() }, (err, user) => {
|
User.findOne({ email: email.toLowerCase() },
|
||||||
if (!user) {
|
(err, user) => { // eslint-disable-line consistent-return
|
||||||
return done(null, false, { msg: `Email ${email} not found.` });
|
if (!user) {
|
||||||
}
|
return done(null, false, { msg: `Email ${email} not found.` });
|
||||||
user.comparePassword(password, (err, isMatch) => {
|
|
||||||
if (isMatch) {
|
|
||||||
return done(null, user);
|
|
||||||
}
|
}
|
||||||
return done(null, false, { msg: 'Invalid email or password.' });
|
user.comparePassword(password, (innerErr, isMatch) => {
|
||||||
|
if (innerErr) {
|
||||||
|
return done(innerErr);
|
||||||
|
}
|
||||||
|
if (isMatch) {
|
||||||
|
return done(null, user);
|
||||||
|
}
|
||||||
|
return done(null, false, { msg: 'Invalid email or password.' });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign in with GitHub.
|
* Sign in with GitHub.
|
||||||
*/
|
*/
|
||||||
//TODO add dotenv so I can add github login
|
// TODO add dotenv so I can add github login
|
||||||
// passport.use(new GitHubStrategy({
|
// passport.use(new GitHubStrategy({
|
||||||
// clientID: process.env.GITHUB_ID,
|
// clientID: process.env.GITHUB_ID,
|
||||||
// clientSecret: process.env.GITHUB_SECRET,
|
// clientSecret: process.env.GITHUB_SECRET,
|
||||||
|
@ -44,7 +48,8 @@ passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, don
|
||||||
// if (req.user) {
|
// if (req.user) {
|
||||||
// User.findOne({ github: profile.id }, (err, existingUser) => {
|
// User.findOne({ github: profile.id }, (err, existingUser) => {
|
||||||
// if (existingUser) {
|
// if (existingUser) {
|
||||||
// req.flash('errors', { msg: 'There is already a GitHub account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
|
// req.flash('errors', { msg: 'There is already a GitHub account that belongs to you. '
|
||||||
|
// + 'Sign in with that account or delete it, then link it with your current account.' });
|
||||||
// done(err);
|
// done(err);
|
||||||
// } else {
|
// } else {
|
||||||
// User.findById(req.user.id, (err, user) => {
|
// User.findById(req.user.id, (err, user) => {
|
||||||
|
@ -68,7 +73,8 @@ passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, don
|
||||||
// }
|
// }
|
||||||
// User.findOne({ email: profile._json.email }, (err, existingEmailUser) => {
|
// User.findOne({ email: profile._json.email }, (err, existingEmailUser) => {
|
||||||
// if (existingEmailUser) {
|
// if (existingEmailUser) {
|
||||||
// req.flash('errors', { msg: 'There is already an account using this email address. Sign in to that account and link it with GitHub manually from Account Settings.' });
|
// req.flash('errors', { msg: 'There is already an account using this email address. Sign'
|
||||||
|
// + ' in to that account and link it with GitHub manually from Account Settings.' });
|
||||||
// done(err);
|
// done(err);
|
||||||
// } else {
|
// } else {
|
||||||
// const user = new User();
|
// const user = new User();
|
||||||
|
|
|
@ -1,56 +1,56 @@
|
||||||
import Project from '../models/project'
|
import Project from '../models/project';
|
||||||
|
|
||||||
export function createProject(req, res) {
|
export function createProject(req, res) {
|
||||||
let projectValues = {
|
const projectValues = {
|
||||||
user: req.user ? req.user._id : undefined,
|
user: req.user ? req.user._id : undefined, // eslint-disable-line no-underscore-dangle
|
||||||
file: {}
|
file: {}
|
||||||
}
|
};
|
||||||
|
|
||||||
Object.assign(projectValues, req.body);
|
Object.assign(projectValues, req.body);
|
||||||
|
|
||||||
Project.create(projectValues, function(err, newProject) {
|
Project.create(projectValues, (err, newProject) => {
|
||||||
if (err) { return res.json({success: false}); }
|
if (err) { return res.json({ success: false }); }
|
||||||
return res.json({
|
return res.json({
|
||||||
id: newProject._id,
|
id: newProject._id, // eslint-disable-line no-underscore-dangle
|
||||||
name: newProject.name,
|
name: newProject.name,
|
||||||
file: {
|
file: {
|
||||||
name: newProject.file.name,
|
name: newProject.file.name,
|
||||||
content: newProject.file.content
|
content: newProject.file.content
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateProject(req, res) {
|
export function updateProject(req, res) {
|
||||||
Project.update({_id: req.params.project_id},
|
Project.update({ _id: req.params.project_id },
|
||||||
{
|
{
|
||||||
$set: req.body
|
$set: req.body
|
||||||
}, function(err, updatedProject) {
|
}, (err, updatedProject) => {
|
||||||
if (err) { return res.json({success: false}) }
|
if (err) { return res.json({ success: false }); }
|
||||||
return res.json({
|
return res.json({
|
||||||
id: updatedProject._id,
|
id: updatedProject._id, // eslint-disable-line no-underscore-dangle
|
||||||
name: updatedProject.name,
|
name: updatedProject.name,
|
||||||
file: {
|
file: {
|
||||||
name: updatedProject.file.name,
|
name: updatedProject.file.name,
|
||||||
content: updatedProject.file.content
|
content: updatedProject.file.content
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProject(req, res) {
|
export function getProject(req, res) {
|
||||||
Project.findById(req.params.project_id, function(err, project) {
|
Project.findById(req.params.project_id, (err, project) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(404).send({message: 'Project with that id does not exist'});
|
return res.status(404).send({ message: 'Project with that id does not exist' });
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
id: project._id,
|
id: project._id, // eslint-disable-line no-underscore-dangle
|
||||||
name: project.name,
|
name: project.name,
|
||||||
file: {
|
file: {
|
||||||
name: project.file.name,
|
name: project.file.name,
|
||||||
content: project.file.conent
|
content: project.file.conent
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
|
@ -1,35 +1,28 @@
|
||||||
import User from '../models/user'
|
import passport from 'passport';
|
||||||
import passport from 'passport'
|
|
||||||
import path from 'path'
|
|
||||||
|
|
||||||
|
|
||||||
export function destroySession(req, res) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createSession(req, res, next) {
|
export function createSession(req, res, next) {
|
||||||
passport.authenticate('local', (err, user, info) => {
|
passport.authenticate('local', (err, user) => { // eslint-disable-line consistent-return
|
||||||
if (err) { return next(err); }
|
if (err) { return next(err); }
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return res.status(401).send({ error: 'Invalid username or password' });
|
return res.status(401).send({ error: 'Invalid username or password' });
|
||||||
}
|
}
|
||||||
|
|
||||||
req.logIn(user, (err) => {
|
req.logIn(user, (innerErr) => {
|
||||||
if (err) { return next(err); }
|
if (innerErr) { return next(innerErr); }
|
||||||
res.json({
|
return res.json({
|
||||||
email: req.user.email,
|
email: req.user.email,
|
||||||
username: req.user.username
|
username: req.user.username
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})(req, res, next);
|
})(req, res, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSession(req, res, next) {
|
export function getSession(req, res) {
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
return res.json({
|
return res.json({
|
||||||
email: req.user.email,
|
email: req.user.email,
|
||||||
username: req.user.username
|
username: req.user.username
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
res.status(404).send({message: 'Session does not exist'});
|
return res.status(404).send({ message: 'Session does not exist' });
|
||||||
}
|
}
|
|
@ -1,30 +1,30 @@
|
||||||
import User from '../models/user'
|
import User from '../models/user';
|
||||||
import passport from 'passport'
|
|
||||||
import path from 'path'
|
|
||||||
|
|
||||||
export function createUser(req, res, next) {
|
export function createUser(req, res, next) {
|
||||||
const user = new User({
|
const user = new User({
|
||||||
username: req.body.username,
|
username: req.body.username,
|
||||||
email: req.body.email,
|
email: req.body.email,
|
||||||
password: req.body.password
|
password: req.body.password
|
||||||
});
|
});
|
||||||
|
|
||||||
User.findOne({email: req.body.email}, (err, existingUser) => {
|
User.findOne({ email: req.body.email },
|
||||||
if (existingUser) {
|
(err, existingUser) => { // eslint-disable-line consistent-return
|
||||||
return res.status(422).send({ error: 'Email is in use' });
|
if (err) { res.status(404).send({ error: err }); }
|
||||||
}
|
|
||||||
user.save((err) => {
|
|
||||||
if (err) { return next(err); }
|
|
||||||
req.logIn(user, (err) => {
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
res.json({
|
|
||||||
email: req.user.email,
|
|
||||||
username: req.user.username
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
if (existingUser) {
|
||||||
|
return res.status(422).send({ error: 'Email is in use' });
|
||||||
|
}
|
||||||
|
user.save((saveErr) => { // eslint-disable-line consistent-return
|
||||||
|
if (saveErr) { return next(saveErr); }
|
||||||
|
req.logIn(user, (loginErr) => { // eslint-disable-line consistent-return
|
||||||
|
if (loginErr) {
|
||||||
|
return next(loginErr);
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
email: req.user.email,
|
||||||
|
username: req.user.username
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -3,15 +3,15 @@ const Schema = mongoose.Schema;
|
||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
|
|
||||||
const fileSchema = new Schema({
|
const fileSchema = new Schema({
|
||||||
name: {type: String, default: 'sketch.js'},
|
name: { type: String, default: 'sketch.js' },
|
||||||
content: {type: String}
|
content: { type: String }
|
||||||
}, {timestamps: true});
|
}, { timestamps: true });
|
||||||
|
|
||||||
const projectSchema = new Schema({
|
const projectSchema = new Schema({
|
||||||
name: {type: String, default: "Hello p5.js, it's the server"},
|
name: { type: String, default: "Hello p5.js, it's the server" },
|
||||||
user: {type: Schema.Types.ObjectId, ref: 'User'},
|
user: { type: Schema.Types.ObjectId, ref: 'User' },
|
||||||
file: {type: fileSchema},
|
file: { type: fileSchema },
|
||||||
_id: {type: String, default: shortid.generate}
|
_id: { type: String, default: shortid.generate }
|
||||||
}, {timestamps: true});
|
}, { timestamps: true });
|
||||||
|
|
||||||
export default mongoose.model('Project', projectSchema);
|
export default mongoose.model('Project', projectSchema);
|
|
@ -3,27 +3,27 @@ const Schema = mongoose.Schema;
|
||||||
const bcrypt = require('bcrypt-nodejs');
|
const bcrypt = require('bcrypt-nodejs');
|
||||||
|
|
||||||
const userSchema = new Schema({
|
const userSchema = new Schema({
|
||||||
name: { type: String, default: '' },
|
name: { type: String, default: '' },
|
||||||
username: { type: String, required: true, unique: true},
|
username: { type: String, required: true, unique: true },
|
||||||
password: { type: String },
|
password: { type: String },
|
||||||
github: { type: String },
|
github: { type: String },
|
||||||
email: { type: String, unique: true },
|
email: { type: String, unique: true },
|
||||||
tokens: Array,
|
tokens: Array,
|
||||||
admin: { type: Boolean, default: false }
|
admin: { type: Boolean, default: false }
|
||||||
}, {timestamps: true});
|
}, { timestamps: true });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password hash middleware.
|
* Password hash middleware.
|
||||||
*/
|
*/
|
||||||
userSchema.pre('save', function (next) {
|
userSchema.pre('save', (next) => { // eslint-disable-line consistent-return
|
||||||
const user = this;
|
const user = this;
|
||||||
if (!user.isModified('password')) { return next(); }
|
if (!user.isModified('password')) { return next(); }
|
||||||
bcrypt.genSalt(10, (err, salt) => {
|
bcrypt.genSalt(10, (err, salt) => { // eslint-disable-line consistent-return
|
||||||
if (err) { return next(err); }
|
if (err) { return next(err); }
|
||||||
bcrypt.hash(user.password, salt, null, (err, hash) => {
|
bcrypt.hash(user.password, salt, null, (innerErr, hash) => {
|
||||||
if (err) { return next(err); }
|
if (innerErr) { return next(innerErr); }
|
||||||
user.password = hash;
|
user.password = hash;
|
||||||
next();
|
return next();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -31,7 +31,7 @@ userSchema.pre('save', function (next) {
|
||||||
/**
|
/**
|
||||||
* Helper method for validating user's password.
|
* Helper method for validating user's password.
|
||||||
*/
|
*/
|
||||||
userSchema.methods.comparePassword = function (candidatePassword, cb) {
|
userSchema.methods.comparePassword = (candidatePassword, cb) => {
|
||||||
bcrypt.compare(candidatePassword, this.password, (err, isMatch) => {
|
bcrypt.compare(candidatePassword, this.password, (err, isMatch) => {
|
||||||
cb(err, isMatch);
|
cb(err, isMatch);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import {Router} from 'express'
|
import { Router } from 'express';
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
import path from 'path'
|
import path from 'path';
|
||||||
|
|
||||||
// this is intended to be a temporary file
|
// this is intended to be a temporary file
|
||||||
// until i figure out isomorphic rendering
|
// until i figure out isomorphic rendering
|
||||||
|
|
||||||
router.route('/').get(function(req, res) {
|
router.route('/').get((req, res) => {
|
||||||
res.sendFile(path.resolve(__dirname + '/../../index.html'));
|
res.sendFile(path.resolve(`${__dirname}/../../index.html`));
|
||||||
});
|
});
|
||||||
|
|
||||||
router.route('/signup').get(function(req, res) {
|
router.route('/signup').get((req, res) => {
|
||||||
res.sendFile(path.resolve(__dirname + '/../../index.html'));
|
res.sendFile(path.resolve(`${__dirname}/../../index.html`));
|
||||||
});
|
});
|
||||||
|
|
||||||
router.route('/projects/:project_id').get(function(req, res) {
|
router.route('/projects/:project_id').get((req, res) => {
|
||||||
res.sendFile(path.resolve(__dirname + '/../../index.html'));
|
res.sendFile(path.resolve(`${__dirname}/../../index.html`));
|
||||||
});
|
});
|
||||||
|
|
||||||
router.route('/login').get(function(req, res) {
|
router.route('/login').get((req, res) => {
|
||||||
res.sendFile(path.resolve(__dirname + '/../../index.html'));
|
res.sendFile(path.resolve(`${__dirname}/../../index.html`));
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
|
@ -1,15 +1,12 @@
|
||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import * as SessionController from '../controllers/session.controller';
|
import * as SessionController from '../controllers/session.controller';
|
||||||
import passport from 'passport';
|
|
||||||
|
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
|
|
||||||
router.route('/login').post(SessionController.createSession);
|
router.route('/login').post(SessionController.createSession);
|
||||||
|
|
||||||
router.route('/logout').get(SessionController.destroySession);
|
|
||||||
|
|
||||||
router.route('/session').get(SessionController.getSession);
|
router.route('/session').get(SessionController.getSession);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
||||||
//TODO add github authentication stuff
|
// TODO add github authentication stuff
|
||||||
|
|
|
@ -7,7 +7,7 @@ const MongoStore = require('connect-mongo')(session);
|
||||||
import passport from 'passport';
|
import passport from 'passport';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
//Webpack Requirements
|
// Webpack Requirements
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import config from '../webpack.config';
|
import config from '../webpack.config';
|
||||||
import webpackDevMiddleware from 'webpack-dev-middleware';
|
import webpackDevMiddleware from 'webpack-dev-middleware';
|
||||||
|
@ -15,22 +15,22 @@ import webpackHotMiddleware from 'webpack-hot-middleware';
|
||||||
|
|
||||||
const app = new Express();
|
const app = new Express();
|
||||||
|
|
||||||
//add check if production environment here
|
// add check if production environment here
|
||||||
const compiler = webpack(config);
|
const compiler = webpack(config);
|
||||||
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }));
|
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }));
|
||||||
app.use(webpackHotMiddleware(compiler));
|
app.use(webpackHotMiddleware(compiler));
|
||||||
|
|
||||||
//Import all required modules
|
// Import all required modules
|
||||||
import serverConfig from './config';
|
import serverConfig from './config';
|
||||||
import users from './routes/user.routes';
|
import users from './routes/user.routes';
|
||||||
import sessions from './routes/session.routes';
|
import sessions from './routes/session.routes';
|
||||||
import projects from './routes/project.routes';
|
import projects from './routes/project.routes';
|
||||||
import serverRoutes from './routes/server.routes';
|
import serverRoutes from './routes/server.routes';
|
||||||
|
|
||||||
//Body parser, cookie parser, sessions, serve public assets
|
// Body parser, cookie parser, sessions, serve public assets
|
||||||
|
|
||||||
app.use(Express.static(path.resolve(__dirname, '../static')));
|
app.use(Express.static(path.resolve(__dirname, '../static')));
|
||||||
app.use(bodyParser.urlencoded({extended: true}));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(session({
|
app.use(session({
|
||||||
|
@ -53,13 +53,15 @@ app.use(passport.session());
|
||||||
app.use('/api', users);
|
app.use('/api', users);
|
||||||
app.use('/api', sessions);
|
app.use('/api', sessions);
|
||||||
app.use('/api', projects);
|
app.use('/api', projects);
|
||||||
//this is supposed to be TEMPORARY -- until i figure out
|
// this is supposed to be TEMPORARY -- until i figure out
|
||||||
// isomorphic rendering
|
// isomorphic rendering
|
||||||
app.use('/', serverRoutes);
|
app.use('/', serverRoutes);
|
||||||
|
|
||||||
const passportConfig = require('./config/passport');
|
// configure passport
|
||||||
|
// const passportConfig = require('./config/passport');
|
||||||
|
require('./config/passport');
|
||||||
|
|
||||||
//Connect to MongoDB
|
// Connect to MongoDB
|
||||||
// mongoose.connect(process.env.MONGODB_URI || process.env.MONGOLAB_URI);
|
// mongoose.connect(process.env.MONGODB_URI || process.env.MONGOLAB_URI);
|
||||||
mongoose.connect(serverConfig.mongoURL);
|
mongoose.connect(serverConfig.mongoURL);
|
||||||
mongoose.connection.on('error', () => {
|
mongoose.connection.on('error', () => {
|
||||||
|
@ -67,9 +69,9 @@ mongoose.connection.on('error', () => {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/", function(req, res) {
|
app.get('/', (req, res) => {
|
||||||
res.sendFile(path.resolve(__dirname + '/../index.html'));
|
res.sendFile(path.resolve(`${__dirname}/../index.html`));
|
||||||
})
|
});
|
||||||
|
|
||||||
// start app
|
// start app
|
||||||
app.listen(serverConfig.port, (error) => {
|
app.listen(serverConfig.port, (error) => {
|
||||||
|
@ -79,3 +81,4 @@ app.listen(serverConfig.port, (error) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue