Merged in code-clean-ups (pull request #4)

[Front-End] - Code clean ups
This commit is contained in:
Ivan Diaz 2016-01-27 13:40:57 -03:00
commit 10a1bb08e9
76 changed files with 195 additions and 900 deletions

4
.gitignore vendored
View File

@ -21,11 +21,11 @@ build/Release
# Dependency directories # Dependency directories
node_modules node_modules
bower_components bower_components
server/vendor api/vendor
# Build files # Build files
build build
server/composer.lock api/composer.lock
.idea .idea
.jshintrc .jshintrc

View File

@ -13,23 +13,20 @@ OpenSupports v4.0
3. Install npm `sudo apt-get install npm` 3. Install npm `sudo apt-get install npm`
4. Install gulp `sudo npm install -g gulp` 4. Install gulp `sudo npm install -g gulp`
5. Go to repo `cd os4-react` 5. Go to repo `cd os4-react`
6. Install dependences `sudo npm install` 6. Install dependences `npm install`
7. Rebuild node-sass `sudo npm rebuild node-sass` 7. Rebuild node-sass `npm rebuild node-sass`
8. Run `gulp dev` 8. Run `gulp dev`
9. Go to the main app: `http://localhost:3000/app` or the component demo `http://localhost:3000/demo` 9. Go to the main app: `http://localhost:3000/app` or the component demo `http://localhost:3000/demo`
10. Your browser will automatically be opened and directed to the browser-sync proxy address
### Getting up and running
1. [Create MySQL Database](#markdown-header-create-mysql-database)
2. Clone this repo
3. Run `npm install` from the root directory
4. Create a mysql database
5. Run `gulp dev` (may require installing Gulp globally `npm install gulp -g`)
6. Your browser will automatically be opened and directed to the browser-sync proxy address
7. To prepare assets for production, run the `gulp prod` task (Note: the production task does not fire up the express server, and won't provide you with browser-sync's live reloading. Simply use `gulp dev` during development. More information below)
Now that `gulp dev` is running, the server is up as well and serving files from the `/build` directory. Any changes in the `/src` directory will be automatically processed by Gulp and the changes will be injected to any open browsers pointed at the proxy address. Now that `gulp dev` is running, the server is up as well and serving files from the `/build` directory. Any changes in the `/src` directory will be automatically processed by Gulp and the changes will be injected to any open browsers pointed at the proxy address.
### Getting up and running BACK-END
1. Clone this repo
2. [Create MySQL Database](#markdown-header-create-mysql-database)
TODO
### Create MySQL Database ### Create MySQL Database
1. Install mysql-server 1. Install mysql-server

View File

@ -1,20 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<title>App Name</title>
<link rel="stylesheet" href="/css/main.css">
</head>
<body>
<div id="app"></div>
<script src="/js/main.js"></script>
</body>
</html>

View File

@ -1,57 +0,0 @@
'use strict';
import React from 'react/addons';
import {ListenerMixin} from 'reflux';
import {RouteHandler} from 'react-router';
import CurrentUserActions from './actions/CurrentUserActions';
import CurrentUserStore from './stores/CurrentUserStore';
import Header from './components-app/Header';
import Footer from './components-app/Footer';
var App = React.createClass({
mixins: [ListenerMixin],
getInitialState() {
return {
currentUser: {}
};
},
_onUserChange(err, user) {
if ( err ) {
this.setState({ error: err });
} else {
this.setState({ currentUser: user || {}, error: null });
}
},
componentWillMount() {
console.log('About to mount App');
},
componentDidMount() {
this.listenTo(CurrentUserStore, this._onUserChange);
CurrentUserActions.checkLoginStatus();
},
render() {
return (
<div>
<Header />
<RouteHandler params={this.props.params}
query={this.props.query}
currentUser={this.state.currentUser} />
<Footer />
</div>
);
}
});
export default App;

View File

@ -1,23 +0,0 @@
'use strict';
import React from 'react/addons';
import {Route, NotFoundRoute, DefaultRoute} from 'react-router';
import App from './App';
import HomePage from './pages/HomePage';
import SearchPage from './pages/SearchPage';
import NotFoundPage from './pages/NotFoundPage';
import DemoPage from './pages/component-demo-page';
export default (
<Route handler={App} path='/'>
<DefaultRoute handler={HomePage} />
<Route name='Home' path='/' handler={HomePage} />
<Route name='Demo' path='/demo' handler={DemoPage} />
<NotFoundRoute handler={NotFoundPage} />
</Route>
);

View File

@ -1,13 +0,0 @@
'use strict';
import Reflux from 'reflux';
var CurrentUserActions = Reflux.createActions([
'checkLoginStatus',
'login',
'logout'
]);
export default CurrentUserActions;

View File

@ -1,16 +0,0 @@
'use strict';
import React from 'react/addons';
var Footer = React.createClass({
render() {
return (
<footer>
</footer>
);
}
});
export default Footer;

View File

@ -1,16 +0,0 @@
'use strict';
import React from 'react/addons';
var Header = React.createClass({
render() {
return (
<header>
</header>
);
}
});
export default Header;

View File

@ -1,35 +0,0 @@
/**
* Created by ivan on 16/08/15.
*/
jest.dontMock('../button.js');
import React from 'react/addons';
import Button from '../button.js';
var TestUtils = React.addons.TestUtils;
describe('Button', () => {
it('should render children', () => {
var button = TestUtils.renderIntoDocument(
<Button>
testcontent
</Button>
);
expect(button.getDOMNode().textContent).toEqual('testcontent');
});
it('should add passed types to class', () => {
var types = [
'primary'
];
types.forEach((type) => {
var button = TestUtils.renderIntoDocument(
<Button type={type}>
testcontent
</Button>
);
expect(button.getDOMNode().getAttribute('class')).toContain('button-' + type);
});
});
});

View File

@ -1,44 +0,0 @@
/**
* Created by ivan on 16/08/15.
*/
'use strict';
import React from 'react/addons';
import classNames from 'classnames';
var Button = React.createClass({
propTypes: {
children: React.PropTypes.node,
type: React.PropTypes.oneOf([
'primary'
])
},
getDefaultProps() {
return {
type: 'primary'
}
},
render() {
return (
<button className={this.getClass()}>
{this.props.children}
</button>
);
},
getClass() {
var classes = {
'button': true
};
classes['button-' + this.props.type] = (this.props.type);
classes[this.props.className] = (this.props.className);
return classNames(classes);
}
});
export default Button;

View File

@ -1,28 +0,0 @@
import React from 'react/addons';
import classNames from 'classnames';
var Widget = React.createClass({
propTypes: {
children: React.PropTypes.node.isRequired
},
render() {
return (
<div className={this.getClass()}>
{this.props.children}
</div>
);
},
getClass() {
var classes = {
'widget': true
};
classes[this.props.className] = (this.props.className);
return classNames(classes);
}
});
export default Widget;

View File

@ -1,15 +0,0 @@
'use strict';
import React from 'react/addons';
import Router from 'react-router';
import routes from './Routes';
if ( process.env.NODE_ENV !== 'production' ) {
// Enable React devtools
window.React = React;
}
Router.run(routes, Router.HistoryLocation, (Handler, state) => {
React.render(<Handler params={state.params} query={state.query} />, document.getElementById('app'));
});

View File

View File

@ -1,28 +0,0 @@
'use strict';
import _ from 'lodash';
import {Navigation} from 'react-router';
import CurrentUserStore from '../stores/CurrentUserStore';
var AuthenticatedRouteMixin = {
mixins: [Navigation],
_checkIfRedirect() {
if ( _.isEmpty(CurrentUserStore.user) && CurrentUserStore.hasBeenChecked && this.isMounted() ) {
this.replaceWith('Home');
}
},
componentDidMount() {
this._checkIfRedirect();
},
componentDidUpdate() {
this._checkIfRedirect();
}
};
export default AuthenticatedRouteMixin;

View File

@ -1,33 +0,0 @@
'use strict';
import React from 'react/addons';
import {Link} from 'react-router';
import DocumentTitle from 'react-document-title';
var HomePage = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired
},
render() {
return (
<DocumentTitle title="Home">
<section className="home-page">
<div>
Home
</div>
<div>
<Link to="Search">Search</Link>
</div>
</section>
</DocumentTitle>
);
}
});
export default HomePage;

View File

@ -1,26 +0,0 @@
'use strict';
import React from 'react/addons';
import DocumentTitle from 'react-document-title';
var NotFoundPage = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired
},
render() {
return (
<DocumentTitle title="404: Not Found">
<section className="not-found-page">
Page Not Found
</section>
</DocumentTitle>
);
}
});
export default NotFoundPage;

View File

@ -1,33 +0,0 @@
'use strict';
import React from 'react/addons';
import {Link} from 'react-router';
import DocumentTitle from 'react-document-title';
var SearchPage = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired
},
render() {
return (
<DocumentTitle title="Search">
<section className="search-page">
<div>
Search
</div>
<div>
<Link to="Home">Back to Home</Link>
</div>
</section>
</DocumentTitle>
);
}
});
export default SearchPage;

View File

@ -1,61 +0,0 @@
'use strict';
import React from 'react/addons';
import {Link} from 'react-router';
import DocumentTitle from 'react-document-title';
import Button from '../components-core/button.js';
import Widget from '../components-core/widget.js';
var DemoPage = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired
},
elements: [
{
title: 'Primary Button',
render: (
<Button type="primary">Sign up</Button>
)
},
{
title: 'Widget',
render: (
<Widget>
<h2>Register here!</h2>
<Button type="primary">SIGN UP</Button>
</Widget>
)
}
],
render() {
return (
<DocumentTitle title="Demo Page">
<section className="home-page">
{this.renderElements()}
</section>
</DocumentTitle>
);
},
renderElements: function () {
return this.elements.map((element) => {
return (
<div className="demo-element">
<h4>
{element.title}
</h4>
<div class="demo-element--example">
{element.render}
</div>
</div>
);
});
}
});
export default DemoPage;

View File

@ -1,13 +0,0 @@
'use strict';
import React from 'react/addons';
import DocumentTitle from 'react-document-title';
var HomePage = React.createClass({
render() {
return (
null
);
}
});

View File

View File

@ -1,60 +0,0 @@
'use strict';
import Reflux from 'reflux';
import CurrentUserActions from '../actions/CurrentUserActions';
import AuthAPI from '../utils/AuthAPI';
var CurrentUserStore = Reflux.createStore({
init() {
this.user = null;
this.hasBeenChecked = false;
this.listenTo(CurrentUserActions.checkLoginStatus, this.checkLoginStatus);
this.listenTo(CurrentUserActions.login, this.loginUser);
this.listenTo(CurrentUserActions.logout, this.logoutUser);
},
setUser(user, cb = function(){}) {
this.user = user;
cb(null, this.user);
this.trigger(null, this.user);
},
throwError(err, cb) {
cb(err);
this.trigger(err);
},
checkLoginStatus(cb = function(){}) {
if ( this.user ) {
this.setUser(this.user, cb);
} else {
AuthAPI.checkLoginStatus().then(user => {
this.hasBeenChecked = true;
this.setUser(user, cb);
}).catch(err => {
this.hasBeenChecked = true;
this.throwError(err, cb);
});
}
},
loginUser(user, cb = function(){}) {
AuthAPI.login(user).then(user => {
this.setUser(user, cb);
}).catch(err => {
this.throwError(err, cb);
});
},
logoutUser(cb = function(){}) {
AuthAPI.logout(this.user).then(() => {
this.setUser(null, cb);
});
}
});
export default CurrentUserStore;

View File

View File

@ -1,87 +0,0 @@
'use strict';
import {camelizeKeys} from 'humps';
import request from 'superagent';
var APIUtils = {
root: '//localhost:3000/api/',
normalizeResponse(response) {
return camelizeKeys(response.body);
},
get(path) {
return new Promise((resolve, reject) => {
request.get(this.root + path)
.withCredentials()
.end((err, res) => {
if ( err || !res.ok ) {
reject(this.normalizeResponse(err || res));
} else {
resolve(this.normalizeResponse(res));
}
});
});
},
post(path, body) {
return new Promise((resolve, reject) => {
request.post(this.root + path, body)
.withCredentials()
.end((err, res) => {
console.log(err, res);
if ( err || !res.ok ) {
reject(this.normalizeResponse(err || res));
} else {
resolve(this.normalizeResponse(res));
}
});
});
},
patch(path, body) {
return new Promise((resolve, reject) => {
request.patch(this.root + path, body)
.withCredentials()
.end((err, res) => {
if ( err || !res.ok ) {
reject(this.normalizeResponse(err || res));
} else {
resolve(this.normalizeResponse(res));
}
});
});
},
put(path, body) {
return new Promise((resolve, reject) => {
request.put(this.root + path, body)
.withCredentials()
.end((err, res) => {
if ( err || !res.ok ) {
reject(this.normalizeResponse(err || res));
} else {
resolve(this.normalizeResponse(res));
}
});
});
},
del(path) {
return new Promise((resolve, reject) => {
request.del(this.root + path)
.withCredentials()
.end((err, res) => {
if ( err || !res.ok ) {
reject(this.normalizeResponse(err || res));
} else {
resolve(this.normalizeResponse(res));
}
});
});
}
};
export default APIUtils;

View File

@ -1,21 +0,0 @@
'use strict';
import APIUtils from './APIUtils';
var AuthAPI = {
checkLoginStatus() {
return APIUtils.get('auth/check');
},
login(user) {
return APIUtils.post('auth/login', user);
},
logout() {
return APIUtils.post('auth/logout');
}
};
export default AuthAPI;

View File

@ -17,7 +17,7 @@ gulp.task('server', function() {
server.use(express.static(config.buildDir)); server.use(express.static(config.buildDir));
// Proxy php server api // Proxy php server api
server.use('/server', proxy('http://localhost:8080/', { server.use('/api', proxy('http://localhost:8080/', {
forwardPath: function(req, res) { forwardPath: function(req, res) {
return require('url').parse(req.url).path; return require('url').parse(req.url).path;
} }

44
package.json Executable file → Normal file
View File

@ -1,19 +1,12 @@
{ {
"name": "react-rocket-boilerplate", "name": "os4-react",
"version": "0.2.0", "version": "4.0.0",
"author": "Jake Marsh <jakemmarsh@gmail.com>", "author": "Ivan Diaz <ivan@opensupports.com>",
"description": "Boilerplate using React, Browserify, SASS, and Gulp.", "description": "OpenSupports version 4 with reactjs",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/jakemmarsh/react-rocket-boilerplate.git" "url": "https://github.com/ivandiazwm/opensupports.git"
}, },
"keywords": [
"gulp",
"browserify",
"react",
"sass",
"boilerplate"
],
"private": true, "private": true,
"engines": { "engines": {
"node": "^0.12.x", "node": "^0.12.x",
@ -46,20 +39,25 @@
"gulp-util": "^3.0.6", "gulp-util": "^3.0.6",
"humps": "^0.6.0", "humps": "^0.6.0",
"jest-cli": "^0.5.10", "jest-cli": "^0.5.10",
"jquery": "^2.1.4",
"lodash": "^3.10.0",
"messageformat": "^0.2.2",
"morgan": "^1.6.1", "morgan": "^1.6.1",
"react": "^0.13.x",
"react-document-title": "^1.0.2",
"react-google-recaptcha": "^0.4.0",
"react-motion": "^0.3.0",
"react-router": "^0.13.x",
"reflux": "^0.2.9",
"run-sequence": "^1.1.1", "run-sequence": "^1.1.1",
"vinyl-source-stream": "^1.1.0", "vinyl-source-stream": "^1.1.0",
"watchify": "^3.2.x" "watchify": "^3.2.x"
}, },
"dependencies": {
"app-module-path": "^1.0.3",
"classnames": "^2.1.3",
"jquery": "^2.1.4",
"lodash": "^3.10.0",
"messageformat": "^0.2.2",
"react": "^0.14.6",
"react-document-title": "^1.0.2",
"react-dom": "^0.14.6",
"react-google-recaptcha": "^0.5.2",
"react-motion": "^0.3.0",
"react-router": "^2.0.0-rc5",
"reflux": "^0.2.9"
},
"jest": { "jest": {
"scriptPreprocessor": "./preprocessor.js", "scriptPreprocessor": "./preprocessor.js",
"testFileExtensions": [ "testFileExtensions": [
@ -74,9 +72,5 @@
"unmockedModulePathPatterns": [ "unmockedModulePathPatterns": [
"react" "react"
] ]
},
"dependencies": {
"app-module-path": "^1.0.3",
"classnames": "^2.1.3"
} }
} }

View File

@ -1,75 +0,0 @@
<?php
class Stub {
private $function;
private $timesCalled = 0;
private $lastArgs = null;
public function __construct($function = null) {
$this->function = ($function === null) ? function (){} : $function;
}
public function __invoke() {
$this->timesCalled++;
$this->lastArgs = func_get_args();
return call_user_func_array($this->function, func_get_args());
}
public function returns($arg) {
$this->function = function () use ($arg) {
return $arg;
};
return $this;
}
public function hasBeenCalled() {
return !!$this->timesCalled;
}
public function reset() {
$this->timesCalled = 0;
$this->lastArgs = null;
}
public function hasBeenCalledWithArgs() {
$argumentsMatchAssertion = serialize(func_get_args()) === serialize($this->lastArgs);
return $this->timesCalled && $argumentsMatchAssertion;
}
}
class Mock {
public static function stub() {
return new Stub;
}
public function __construct($arguments = array()) {
if (!empty($arguments)) {
foreach ($arguments as $property => $argument) {
if ($argument instanceOf Closure) {
$this->{$property} = self::stub($argument);
} else {
$this->{$property} = $argument;
}
}
}
}
public function __set($key, $value){
if ($value instanceOf Closure) {
$this->{$key} = self::stub($value);
} else {
$this->{$key} = $value;
}
}
public function __call($method, $arguments) {
if (isset($this->{$method}) && is_callable($this->{$method})) {
return call_user_func_array($this->{$method}, $arguments);
} else {
throw new Exception("Fatal error: Call to undefined method stdObject::{$method}()");
}
}
}

View File

@ -1,6 +1,6 @@
import Reflux from 'reflux'; import Reflux from 'reflux';
var CommonActions = Reflux.createActions([ let CommonActions = Reflux.createActions([
'changeLanguage' 'changeLanguage'
]); ]);

View File

@ -1,6 +1,6 @@
import Reflux from 'reflux'; import Reflux from 'reflux';
var UserActions = Reflux.createActions([ let UserActions = Reflux.createActions([
'checkLoginStatus', 'checkLoginStatus',
'login', 'login',
'logout' 'logout'

View File

@ -1,4 +1,4 @@
import React from 'react/addons'; import React from 'react';
import Reflux from 'reflux'; import Reflux from 'reflux';
import {ListenerMixin} from 'reflux'; import {ListenerMixin} from 'reflux';
import {RouteHandler} from 'react-router'; import {RouteHandler} from 'react-router';
@ -6,15 +6,14 @@ import {RouteHandler} from 'react-router';
import CommonActions from 'actions/common-actions'; import CommonActions from 'actions/common-actions';
import CommonStore from 'stores/common-store'; import CommonStore from 'stores/common-store';
var App = React.createClass({ let App = React.createClass({
mixins: [Reflux.listenTo(CommonStore, 'onCommonStoreChanged')], mixins: [Reflux.listenTo(CommonStore, 'onCommonStoreChanged')],
render() { render() {
return ( return (
<div> <div>
<RouteHandler params={this.props.params} {React.cloneElement(this.props.children, {})}
query={this.props.query} />
</div> </div>
); );
}, },
@ -24,7 +23,6 @@ var App = React.createClass({
this.forceUpdate(); this.forceUpdate();
} }
} }
}); });
export default App; export default App;

View File

@ -1,5 +1,5 @@
import React from 'react/addons'; import React from 'react';
import {Route, NotFoundRoute, DefaultRoute} from 'react-router'; import {Router, Route, IndexRoute, browserHistory} from 'react-router';
import App from 'app/App'; import App from 'app/App';
import DemoPage from 'app/demo/components-demo-page'; import DemoPage from 'app/demo/components-demo-page';
@ -10,14 +10,14 @@ import MainSignUpPage from 'app/main/main-signup/main-sign
export default ( export default (
<Route handler={App} path='/'> <Router history={browserHistory}>
<Route component={App} path='/'>
<Route name='main' path='/app' handler={MainLayout}> <Route path='/app' component={MainLayout}>
<DefaultRoute name='home' handler={MainHomePage} /> <IndexRoute component={MainHomePage} />
<Route name='signup' path='/app/signup' handler={MainSignUpPage}/> <Route path='signup' component={MainSignUpPage}/>
</Route> </Route>
<Route name='Demo' path='/demo' handler={DemoPage} /> <Route name='Demo' path='demo' component={DemoPage} />
</Route> </Route>
</Router>
); );

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import React from 'react/addons'; import React from 'react';
import {Link} from 'react-router'; import {Link} from 'react-router';
import DocumentTitle from 'react-document-title'; import DocumentTitle from 'react-document-title';
@ -10,9 +10,9 @@ import Checkbox from 'core-components/checkbox';
import Widget from 'core-components/widget'; import Widget from 'core-components/widget';
import DropDown from 'core-components/drop-down'; import DropDown from 'core-components/drop-down';
var dropDownItems = [{content: 'English'}, {content: 'Spanish'}, {content: 'German'}, {content: 'Portuguese'}, {content: 'Japanese'}]; let dropDownItems = [{content: 'English'}, {content: 'Spanish'}, {content: 'German'}, {content: 'Portuguese'}, {content: 'Japanese'}];
var DemoPage = React.createClass({ let DemoPage = React.createClass({
propTypes: { propTypes: {
currentUser: React.PropTypes.object.isRequired currentUser: React.PropTypes.object.isRequired

View File

@ -1,4 +1,5 @@
import React from 'react/addons'; import React from 'react';
import {render} from 'react-dom'
import Router from 'react-router'; import Router from 'react-router';
import routes from './Routes'; import routes from './Routes';
@ -8,6 +9,4 @@ if ( process.env.NODE_ENV !== 'production' ) {
window.React = React; window.React = React;
} }
Router.run(routes, Router.HistoryLocation, (Handler, state) => { render(routes, document.getElementById('app'));
React.render(<Handler params={state.params} query={state.query} />, document.getElementById('app'));
});

View File

@ -1,4 +1,4 @@
import React from 'react/addons'; import React from 'react';
import UserActions from 'actions/user-actions'; import UserActions from 'actions/user-actions';
import UserStore from 'stores/user-store'; import UserStore from 'stores/user-store';
@ -10,7 +10,7 @@ import Checkbox from 'core-components/checkbox';
import Widget from 'core-components/widget'; import Widget from 'core-components/widget';
import WidgetTransition from 'core-components/widget-transition'; import WidgetTransition from 'core-components/widget-transition';
var MainHomePageLoginWidget = React.createClass({ let MainHomePageLoginWidget = React.createClass({
getInitialState() { getInitialState() {
return { return {

View File

@ -1,10 +1,10 @@
import React from 'react/addons'; import React from 'react';
import {ListenerMixin} from 'reflux'; import {ListenerMixin} from 'reflux';
import {RouteHandler} from 'react-router'; import {RouteHandler} from 'react-router';
import MainHomePageLoginWidget from 'app/main/main-home/main-home-page-login-widget'; import MainHomePageLoginWidget from 'app/main/main-home/main-home-page-login-widget';
var MainHomePage = React.createClass({ let MainHomePage = React.createClass({
render() { render() {
return ( return (

View File

@ -1,6 +1,6 @@
import React from 'react/addons'; import React from 'react';
var MainLayoutFooter = React.createClass({ let MainLayoutFooter = React.createClass({
render() { render() {
return ( return (

View File

@ -1,4 +1,4 @@
import React from 'react/addons'; import React from 'react';
import i18n from 'lib/i18n'; import i18n from 'lib/i18n';
import CommonActions from 'actions/common-actions'; import CommonActions from 'actions/common-actions';
@ -7,8 +7,8 @@ import Button from 'core-components/button';
import DropDown from 'core-components/drop-down'; import DropDown from 'core-components/drop-down';
import Icon from 'core-components/icon'; import Icon from 'core-components/icon';
var languageList = ['English', 'Spanish', 'Portuguese', 'German', 'Turkish', 'Indian']; let languageList = ['English', 'Spanish', 'Portuguese', 'German', 'Turkish', 'Indian'];
var codeLanguages = { let codeLanguages = {
'English': 'us', 'English': 'us',
'Spanish': 'es', 'Spanish': 'es',
'Portuguese': 'pt', 'Portuguese': 'pt',
@ -17,14 +17,14 @@ var codeLanguages = {
'Indian': 'in' 'Indian': 'in'
}; };
var MainLayoutHeader = React.createClass({ let MainLayoutHeader = React.createClass({
render() { render() {
return ( return (
<div className="main-layout-header"> <div className="main-layout-header">
<div className="main-layout-header--login-links"> <div className="main-layout-header--login-links">
<Button type="clean" route={{to:'/app'}}>{i18n('LOG_IN')}</Button> <Button type="clean" route={{to:'/app'}}>{i18n('LOG_IN')}</Button>
<Button type="clean" route={{to:'/app/signup'}}>{i18n('SIGN_UP')}</Button> <Button type="clean" route={{to:'/app/signup'}}>Sign up</Button>
</div> </div>
<DropDown className="main-layout-header--languages" items={this.getLanguageList()} onChange={this.changeLanguage}/> <DropDown className="main-layout-header--languages" items={this.getLanguageList()} onChange={this.changeLanguage}/>
</div> </div>
@ -44,7 +44,7 @@ var MainLayoutHeader = React.createClass({
}, },
changeLanguage(event) { changeLanguage(event) {
var language = languageList[event.index]; let language = languageList[event.index];
CommonActions.changeLanguage(codeLanguages[language]); CommonActions.changeLanguage(codeLanguages[language]);
} }

View File

@ -1,10 +1,9 @@
import React from 'react/addons'; import React from 'react';
import {RouteHandler} from 'react-router';
import MainHeader from 'app/main/main-layout-header'; import MainHeader from 'app/main/main-layout-header';
import MainFooter from 'app/main/main-layout-footer'; import MainFooter from 'app/main/main-layout-footer';
var MainLayout = React.createClass({ let MainLayout = React.createClass({
render() { render() {
return ( return (
@ -13,8 +12,7 @@ var MainLayout = React.createClass({
<MainHeader /> <MainHeader />
<div className="main-layout--content"> <div className="main-layout--content">
<RouteHandler params={this.props.params} {this.props.children}
query={this.props.query} />
</div> </div>
<MainFooter /> <MainFooter />

View File

@ -1,4 +1,4 @@
import React from 'react/addons'; import React from 'react';
import {ListenerMixin} from 'reflux'; import {ListenerMixin} from 'reflux';
import ReCAPTCHA from 'react-google-recaptcha'; import ReCAPTCHA from 'react-google-recaptcha';
@ -11,7 +11,7 @@ import Input from 'core-components/input';
import Widget from 'core-components/widget'; import Widget from 'core-components/widget';
import WidgetTransition from 'core-components/widget-transition'; import WidgetTransition from 'core-components/widget-transition';
var MainSignUpPageWidget = React.createClass({ let MainSignUpPageWidget = React.createClass({
render() { render() {
return ( return (

View File

@ -1,13 +1,13 @@
jest.dontMock('../button.js'); jest.dontMock('../button.js');
import React from 'react/addons'; import React from 'react';
import Button from '../button.js'; import Button from '../button.js';
var TestUtils = React.addons.TestUtils; let TestUtils = React.addons.TestUtils;
describe('Button', () => { describe('Button', function () {
it('should render children', () => { it('should render children', function () {
var button = TestUtils.renderIntoDocument( let button = TestUtils.renderIntoDocument(
<Button> <Button>
testcontent testcontent
</Button> </Button>
@ -16,19 +16,20 @@ describe('Button', () => {
expect(button.getDOMNode().textContent).toEqual('testcontent'); expect(button.getDOMNode().textContent).toEqual('testcontent');
}); });
it('should add passed types to class', () => { it('should add passed types to class', function () {
var types = [ let types = [
'primary', 'primary',
'clean', 'clean',
'link' 'link'
]; ];
types.forEach((type) => { types.forEach(function (type) {
var button = TestUtils.renderIntoDocument( let button = TestUtils.renderIntoDocument(
<Button type={type}> <Button type={type}>
testcontent testcontent
</Button> </Button>
); );
expect(button.getDOMNode().getAttribute('class')).toContain('button-' + type); expect(button.getDOMNode().getAttribute('class')).toContain('button-' + type);
}); });
}); });

View File

@ -1,14 +1,14 @@
jest.dontMock('core-components/form.js'); jest.dontMock('core-components/form.js');
jest.dontMock('core-components/form.js'); jest.dontMock('core-components/form.js');
import React from 'react/addons'; import React from 'react';
import Form from 'core-components/form.js'; import Form from 'core-components/form.js';
import Input from 'core-components/input.js'; import Input from 'core-components/input.js';
var TestUtils = React.addons.TestUtils; let TestUtils = React.addons.TestUtils;
describe('Form', () => { describe('Form', function () {
var results = TestUtils.renderIntoDocument( let results = TestUtils.renderIntoDocument(
<Form onSubmit={jest.genMockFunction()}> <Form onSubmit={jest.genMockFunction()}>
<div> <div>
<Input name="first" value="value1"/> <Input name="first" value="value1"/>
@ -17,9 +17,9 @@ describe('Form', () => {
<Input name="third" value="value3" /> <Input name="third" value="value3" />
</Form> </Form>
); );
var inputs = TestUtils.scryRenderedComponentsWithType(results, Input); let inputs = TestUtils.scryRenderedComponentsWithType(results, Input);
it('should store input value in form state', () => { it('should store input value in form state', function () {
expect(results.state.form).toEqual({ expect(results.state.form).toEqual({
first: 'value1', first: 'value1',
second: 'value2', second: 'value2',
@ -27,7 +27,7 @@ describe('Form', () => {
}); });
}); });
it('should update form state if an input value changes', () => { it('should update form state if an input value changes', function () {
inputs[0].props.onChange({ target: {value: 'value4'}}); inputs[0].props.onChange({ target: {value: 'value4'}});
expect(results.state.form).toEqual({ expect(results.state.form).toEqual({
@ -37,7 +37,7 @@ describe('Form', () => {
}); });
}); });
it('should update input value if state value changes', () => { it('should update input value if state value changes', function () {
results.setState({ results.setState({
form: { form: {
first: 'value6', first: 'value6',
@ -51,7 +51,7 @@ describe('Form', () => {
expect(inputs[2].props.value).toEqual('value8'); expect(inputs[2].props.value).toEqual('value8');
}); });
it('should call onSubmit callback when form is submitted', () => { it('should call onSubmit callback when form is submitted', function () {
TestUtils.Simulate.submit(results.getDOMNode()); TestUtils.Simulate.submit(results.getDOMNode());
expect(results.props.onSubmit).toBeCalledWith(results.state.form); expect(results.props.onSubmit).toBeCalledWith(results.state.form);

View File

@ -1,12 +1,13 @@
import React from 'react/addons'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import {Navigation} from 'react-router'; import Router from 'react-router';
import callback from 'lib/callback'; import callback from 'lib/callback';
var Button = React.createClass({ let Button = React.createClass({
mixins: [Navigation], contextTypes: {
router: React.PropTypes.object
},
propTypes: { propTypes: {
children: React.PropTypes.node, children: React.PropTypes.node,
@ -37,7 +38,7 @@ var Button = React.createClass({
}, },
getClass() { getClass() {
var classes = { let classes = {
'button': true 'button': true
}; };
@ -49,7 +50,7 @@ var Button = React.createClass({
handleClick() { handleClick() {
if (this.props.route) { if (this.props.route) {
this.transitionTo(this.props.route.to, this.props.route.param, this.props.route.query); this.context.router.push(this.props.route.to);
} }
} }
}); });

View File

@ -5,7 +5,7 @@ import _ from 'lodash';
import callback from 'lib/callback'; import callback from 'lib/callback';
import getIcon from 'lib/get-icon'; import getIcon from 'lib/get-icon';
var CheckBox = React.createClass({ let CheckBox = React.createClass({
propTypes: { propTypes: {
alignment: React.PropTypes.string, alignment: React.PropTypes.string,
@ -38,7 +38,7 @@ var CheckBox = React.createClass({
}, },
getProps() { getProps() {
var props = _.clone(this.props); let props = _.clone(this.props);
props.type = 'checkbox'; props.type = 'checkbox';
@ -52,7 +52,7 @@ var CheckBox = React.createClass({
}, },
getClass() { getClass() {
var classes = { let classes = {
'checkbox': true, 'checkbox': true,
'checkbox_checked': this.state.checked, 'checkbox_checked': this.state.checked,

View File

@ -5,14 +5,14 @@ import {Motion, spring} from 'react-motion';
import callback from 'lib/callback'; import callback from 'lib/callback';
var DropDown = React.createClass({ let DropDown = React.createClass({
propTypes: { propTypes: {
defaultSelectedIndex: React.PropTypes.number, defaultSelectedIndex: React.PropTypes.number,
selectedIndex: React.PropTypes.number, selectedIndex: React.PropTypes.number,
items: React.PropTypes.arrayOf(React.PropTypes.shape({ items: React.PropTypes.arrayOf(React.PropTypes.shape({
content: React.PropTypes.string.isRequired, content: React.PropTypes.node.isRequired,
icon: React.PropTypes.string icon: React.PropTypes.string
})).isRequired })).isRequired
}, },
@ -31,11 +31,11 @@ var DropDown = React.createClass({
}, },
getAnimationStyles() { getAnimationStyles() {
var closedStyle = { let closedStyle = {
opacity: spring(0, [200, 20]), opacity: spring(0, [200, 20]),
translateY: spring(20, [200, 20]) translateY: spring(20, [200, 20])
}; };
var openedStyle = { let openedStyle = {
opacity: spring(1, [200, 20]), opacity: spring(1, [200, 20]),
translateY: spring(0, [200, 20]) translateY: spring(0, [200, 20])
}; };
@ -47,12 +47,12 @@ var DropDown = React.createClass({
}, },
render() { render() {
var animation = this.getAnimationStyles(); let animation = this.getAnimationStyles();
return ( return (
<div className={this.getClass()}> <div className={this.getClass()}>
<div className="drop-down--current" onBlur={this.handleBlur} onClick={this.handleClick} tabIndex="0" ref="current"> <div className="drop-down--current" onBlur={this.handleBlur} onClick={this.handleClick} tabIndex="0" ref="current">
{this.props.items[this.getSelectedIndex()]} {this.props.items[this.getSelectedIndex()].content}
</div> </div>
<Motion defaultStyle={animation.defaultStyle} style={animation.style}> <Motion defaultStyle={animation.defaultStyle} style={animation.style}>
{this.renderList} {this.renderList}
@ -62,7 +62,7 @@ var DropDown = React.createClass({
}, },
renderList({opacity, translateY}) { renderList({opacity, translateY}) {
var style = { opacity: opacity, transform: `translateY(${translateY}px)`}; let style = { opacity: opacity, transform: `translateY(${translateY}px)`};
return ( return (
<div className="drop-down--list-container" style={style}> <div className="drop-down--list-container" style={style}>
@ -75,14 +75,14 @@ var DropDown = React.createClass({
renderItem(item, index) { renderItem(item, index) {
return ( return (
<li className="drop-down--list-item" onClick={this.handleItemClick.bind(this, index)} onMouseDown={this.handleItemMouseDown}> <li {...this.getItemProps(index)}>
{item.content} {item.content}
</li> </li>
); );
}, },
getClass() { getClass() {
var classes = { let classes = {
'drop-down': true, 'drop-down': true,
[this.props.className]: (this.props.className) [this.props.className]: (this.props.className)
@ -91,6 +91,15 @@ var DropDown = React.createClass({
return classNames(classes); return classNames(classes);
}, },
getItemProps(index) {
return {
className: 'drop-down--list-item',
onClick: this.handleItemClick.bind(this, index),
onMouseDown: this.handleItemMouseDown,
key: index
};
},
handleBlur() { handleBlur() {
this.setState({ this.setState({
opened: false opened: false
@ -110,7 +119,9 @@ var DropDown = React.createClass({
}); });
if (this.props.onChange) { if (this.props.onChange) {
this.props.onChange(index); this.props.onChange({
index
});
} }
}, },

View File

@ -1,4 +1,4 @@
import React from 'react/addons'; import React from 'react';
import _ from 'lodash'; import _ from 'lodash';
import {reactDFS, renderChildrenWithProps} from 'lib/react-dfs'; import {reactDFS, renderChildrenWithProps} from 'lib/react-dfs';
@ -6,7 +6,7 @@ import {reactDFS, renderChildrenWithProps} from 'lib/react-dfs';
import Input from 'core-components/input'; import Input from 'core-components/input';
import Checkbox from 'core-components/checkbox'; import Checkbox from 'core-components/checkbox';
var Form = React.createClass({ let Form = React.createClass({
validations: {}, validations: {},
@ -17,7 +17,7 @@ var Form = React.createClass({
}, },
componentDidMount() { componentDidMount() {
var formState = {}; let formState = {};
reactDFS(this.props.children, (child) => { reactDFS(this.props.children, (child) => {
if (child.type === Input) { if (child.type === Input) {
@ -42,7 +42,7 @@ var Form = React.createClass({
}, },
getProps() { getProps() {
var props = _.clone(this.props); let props = _.clone(this.props);
props.onSubmit = this.handleSubmit; props.onSubmit = this.handleSubmit;
@ -50,7 +50,7 @@ var Form = React.createClass({
}, },
getInputProps({props, type}) { getInputProps({props, type}) {
var additionalProps = {}; let additionalProps = {};
if (type === Input || type === Checkbox) { if (type === Input || type === Checkbox) {
let inputName = props.name; let inputName = props.name;
@ -75,7 +75,7 @@ var Form = React.createClass({
}, },
handleInputChange(inputName, type, event) { handleInputChange(inputName, type, event) {
var form = _.clone(this.state.form); let form = _.clone(this.state.form);
form[inputName] = event.target.value; form[inputName] = event.target.value;

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
var Icon = React.createClass({ let Icon = React.createClass({
propTypes: { propTypes: {
name: React.PropTypes.string.isRequired name: React.PropTypes.string.isRequired

View File

@ -2,7 +2,7 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import _ from 'lodash'; import _ from 'lodash';
var Input = React.createClass({ let Input = React.createClass({
propTypes: { propTypes: {
value: React.PropTypes.string, value: React.PropTypes.string,
@ -28,7 +28,7 @@ var Input = React.createClass({
}, },
getProps() { getProps() {
var props = _.clone(this.props); let props = _.clone(this.props);
props.type = (this.props.password) ? 'password' : 'text'; props.type = (this.props.password) ? 'password' : 'text';
@ -36,7 +36,7 @@ var Input = React.createClass({
}, },
getClass() { getClass() {
var classes = { let classes = {
'input': true, 'input': true,
['input_' + this.props.inputType]: true, ['input_' + this.props.inputType]: true,

View File

@ -1,11 +1,11 @@
import React from 'react/addons'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import _ from 'lodash'; import _ from 'lodash';
import {Motion, spring} from 'react-motion'; import {Motion, spring} from 'react-motion';
import Widget from 'core-components/widget'; import Widget from 'core-components/widget';
var WidgetTransition = React.createClass({ let WidgetTransition = React.createClass({
propTypes: { propTypes: {
sideToShow: React.PropTypes.string sideToShow: React.PropTypes.string
@ -35,7 +35,7 @@ var WidgetTransition = React.createClass({
return ( return (
<div className={this.getClass()}> <div className={this.getClass()}>
{React.Children.map(this.props.children, function (child, index) { {React.Children.map(this.props.children, function (child, index) {
var modifiedChild; let modifiedChild;
if (index === 0) { if (index === 0) {
modifiedChild = React.cloneElement(child, { modifiedChild = React.cloneElement(child, {
@ -60,7 +60,7 @@ var WidgetTransition = React.createClass({
}, },
getClass() { getClass() {
var classes = { let classes = {
'widget-transition': true, 'widget-transition': true,
[this.props.className]: (this.props.className) [this.props.className]: (this.props.className)
}; };

View File

@ -1,7 +1,7 @@
import React from 'react/addons'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
var Widget = React.createClass({ let Widget = React.createClass({
propTypes: { propTypes: {
title: React.PropTypes.string, title: React.PropTypes.string,
children: React.PropTypes.node.isRequired children: React.PropTypes.node.isRequired
@ -23,7 +23,7 @@ var Widget = React.createClass({
}, },
renderTitle() { renderTitle() {
var titleNode = null; let titleNode = null;
if (this.props.title) { if (this.props.title) {
titleNode = <h2 className="widget--title">{this.props.title}</h2>; titleNode = <h2 className="widget--title">{this.props.title}</h2>;
@ -33,7 +33,7 @@ var Widget = React.createClass({
}, },
getClass() { getClass() {
var classes = { let classes = {
'widget': true 'widget': true
}; };

View File

@ -1,13 +1,13 @@
import keys from 'data/i18n-keys' import keys from 'data/i18n-keys'
var languages = [ let languages = [
'en', 'us',
'es' 'es'
]; ];
var i18nData = function (key, lang) { let i18nData = function (key, lang) {
var langIndex = languages.indexOf(lang); let langIndex = languages.indexOf(lang);
return keys[key][langIndex]; return keys[key][langIndex];
}; };

View File

@ -4,7 +4,7 @@ import $ from 'jquery';
const APIUtils = { const APIUtils = {
root: 'http://localhost:3000/server/', root: 'http://localhost:3000/api/',
getPromise(path, method, data) { getPromise(path, method, data) {
return (resolve, reject) => { return (resolve, reject) => {

View File

@ -2,8 +2,8 @@ import _ from 'lodash';
export default function (defaultFunction, callback, options = {}, extraPreventions = []) { export default function (defaultFunction, callback, options = {}, extraPreventions = []) {
return function (nativeEvent) { return function (nativeEvent) {
var preventions = {'default': false}; let preventions = {'default': false};
var event = _.extend({}, nativeEvent, options, { let event = _.extend({}, nativeEvent, options, {
preventDefault() { preventDefault() {
nativeEvent.preventDefault(); nativeEvent.preventDefault();
preventions['default'] = true; preventions['default'] = true;

View File

@ -2,7 +2,7 @@ import React from 'react';
import _ from 'lodash'; import _ from 'lodash';
export default function () { export default function () {
var className = 'fa'; let className = 'fa';
_.each(arguments, (arg) => { _.each(arguments, (arg) => {
className += ' fa-' + arg; className += ' fa-' + arg;

View File

@ -3,11 +3,11 @@ import MessageFormat from 'messageformat';
import CommonStore from 'stores/common-store'; import CommonStore from 'stores/common-store';
import i18nData from 'data/i18n-data'; import i18nData from 'data/i18n-data';
var mf = new MessageFormat('en'); let mf = new MessageFormat('en');
var i18n = function (key, params = null) { let i18n = function (key, params = null) {
var i18nKey = i18nData(key, CommonStore.language); let i18nKey = i18nData(key, CommonStore.language);
var message = mf.compile(i18nKey); let message = mf.compile(i18nKey);
return message(params); return message(params);
}; };

10
src/lib/react-dfs.js vendored
View File

@ -1,8 +1,8 @@
import React from 'react/addons'; import React from 'react';
import _ from 'lodash'; import _ from 'lodash';
var reactDFS = function (children, visitFunction) { let reactDFS = function (children, visitFunction) {
var stack = []; let stack = [];
React.Children.forEach(children, child => stack.push(child)); React.Children.forEach(children, child => stack.push(child));
stack.reverse(); stack.reverse();
@ -20,13 +20,13 @@ var reactDFS = function (children, visitFunction) {
} }
}; };
var renderChildrenWithProps = function(children, mapFunction) { let renderChildrenWithProps = function(children, mapFunction) {
if (typeof children !== 'object' || children === null) { if (typeof children !== 'object' || children === null) {
return children; return children;
} }
return React.Children.map(children, function (child) { return React.Children.map(children, function (child) {
var props = mapFunction(child); let props = mapFunction(child);
if (typeof child !== 'object' || child === null) { if (typeof child !== 'object' || child === null) {
return child; return child;

View File

@ -1,4 +1,4 @@
const React = require('react/addons'); const React = require('react');
const { PropTypes } = React; const { PropTypes } = React;
const { TransitionMotion, spring } = require('react-motion'); const { TransitionMotion, spring } = require('react-motion');

View File

@ -2,10 +2,10 @@ import Reflux from 'reflux';
import CommonActions from 'actions/common-actions'; import CommonActions from 'actions/common-actions';
var CommonStore = Reflux.createStore({ let CommonStore = Reflux.createStore({
init() { init() {
this.language = 'en'; this.language = 'us';
this.listenTo(CommonActions.changeLanguage, this.changeLanguage); this.listenTo(CommonActions.changeLanguage, this.changeLanguage);
}, },

View File

@ -3,7 +3,7 @@ import APIUtils from 'lib/APIUtils';
import UserActions from 'actions/user-actions'; import UserActions from 'actions/user-actions';
var UserStore = Reflux.createStore({ let UserStore = Reflux.createStore({
init() { init() {
this.user = null; this.user = null;