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
node_modules
bower_components
server/vendor
api/vendor
# Build files
build
server/composer.lock
api/composer.lock
.idea
.jshintrc

View File

@ -13,23 +13,20 @@ OpenSupports v4.0
3. Install npm `sudo apt-get install npm`
4. Install gulp `sudo npm install -g gulp`
5. Go to repo `cd os4-react`
6. Install dependences `sudo npm install`
7. Rebuild node-sass `sudo npm rebuild node-sass`
6. Install dependences `npm install`
7. Rebuild node-sass `npm rebuild node-sass`
8. Run `gulp dev`
9. Go to the main app: `http://localhost:3000/app` or the component demo `http://localhost:3000/demo`
### 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)
10. Your browser will automatically be opened and directed to the browser-sync 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
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));
// Proxy php server api
server.use('/server', proxy('http://localhost:8080/', {
server.use('/api', proxy('http://localhost:8080/', {
forwardPath: function(req, res) {
return require('url').parse(req.url).path;
}

44
package.json Executable file → Normal file
View File

@ -1,19 +1,12 @@
{
"name": "react-rocket-boilerplate",
"version": "0.2.0",
"author": "Jake Marsh <jakemmarsh@gmail.com>",
"description": "Boilerplate using React, Browserify, SASS, and Gulp.",
"name": "os4-react",
"version": "4.0.0",
"author": "Ivan Diaz <ivan@opensupports.com>",
"description": "OpenSupports version 4 with reactjs",
"repository": {
"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,
"engines": {
"node": "^0.12.x",
@ -46,20 +39,25 @@
"gulp-util": "^3.0.6",
"humps": "^0.6.0",
"jest-cli": "^0.5.10",
"jquery": "^2.1.4",
"lodash": "^3.10.0",
"messageformat": "^0.2.2",
"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",
"vinyl-source-stream": "^1.1.0",
"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": {
"scriptPreprocessor": "./preprocessor.js",
"testFileExtensions": [
@ -74,9 +72,5 @@
"unmockedModulePathPatterns": [
"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';
var CommonActions = Reflux.createActions([
let CommonActions = Reflux.createActions([
'changeLanguage'
]);

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
'use strict';
import React from 'react/addons';
import React from 'react';
import {Link} from 'react-router';
import DocumentTitle from 'react-document-title';
@ -10,9 +10,9 @@ import Checkbox from 'core-components/checkbox';
import Widget from 'core-components/widget';
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: {
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 routes from './Routes';
@ -8,6 +9,4 @@ if ( process.env.NODE_ENV !== 'production' ) {
window.React = React;
}
Router.run(routes, Router.HistoryLocation, (Handler, state) => {
React.render(<Handler params={state.params} query={state.query} />, document.getElementById('app'));
});
render(routes, 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 UserStore from 'stores/user-store';
@ -10,7 +10,7 @@ import Checkbox from 'core-components/checkbox';
import Widget from 'core-components/widget';
import WidgetTransition from 'core-components/widget-transition';
var MainHomePageLoginWidget = React.createClass({
let MainHomePageLoginWidget = React.createClass({
getInitialState() {
return {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +1,13 @@
jest.dontMock('../button.js');
import React from 'react/addons';
import React from 'react';
import Button from '../button.js';
var TestUtils = React.addons.TestUtils;
let TestUtils = React.addons.TestUtils;
describe('Button', () => {
it('should render children', () => {
var button = TestUtils.renderIntoDocument(
describe('Button', function () {
it('should render children', function () {
let button = TestUtils.renderIntoDocument(
<Button>
testcontent
</Button>
@ -16,19 +16,20 @@ describe('Button', () => {
expect(button.getDOMNode().textContent).toEqual('testcontent');
});
it('should add passed types to class', () => {
var types = [
it('should add passed types to class', function () {
let types = [
'primary',
'clean',
'link'
];
types.forEach((type) => {
var button = TestUtils.renderIntoDocument(
types.forEach(function (type) {
let button = TestUtils.renderIntoDocument(
<Button type={type}>
testcontent
</Button>
);
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');
import React from 'react/addons';
import React from 'react';
import Form from 'core-components/form.js';
import Input from 'core-components/input.js';
var TestUtils = React.addons.TestUtils;
let TestUtils = React.addons.TestUtils;
describe('Form', () => {
var results = TestUtils.renderIntoDocument(
describe('Form', function () {
let results = TestUtils.renderIntoDocument(
<Form onSubmit={jest.genMockFunction()}>
<div>
<Input name="first" value="value1"/>
@ -17,9 +17,9 @@ describe('Form', () => {
<Input name="third" value="value3" />
</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({
first: 'value1',
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'}});
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({
form: {
first: 'value6',
@ -51,7 +51,7 @@ describe('Form', () => {
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());
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 {Navigation} from 'react-router';
import Router from 'react-router';
import callback from 'lib/callback';
var Button = React.createClass({
let Button = React.createClass({
mixins: [Navigation],
contextTypes: {
router: React.PropTypes.object
},
propTypes: {
children: React.PropTypes.node,
@ -37,7 +38,7 @@ var Button = React.createClass({
},
getClass() {
var classes = {
let classes = {
'button': true
};
@ -49,7 +50,7 @@ var Button = React.createClass({
handleClick() {
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 getIcon from 'lib/get-icon';
var CheckBox = React.createClass({
let CheckBox = React.createClass({
propTypes: {
alignment: React.PropTypes.string,
@ -38,7 +38,7 @@ var CheckBox = React.createClass({
},
getProps() {
var props = _.clone(this.props);
let props = _.clone(this.props);
props.type = 'checkbox';
@ -52,7 +52,7 @@ var CheckBox = React.createClass({
},
getClass() {
var classes = {
let classes = {
'checkbox': true,
'checkbox_checked': this.state.checked,

View File

@ -5,14 +5,14 @@ import {Motion, spring} from 'react-motion';
import callback from 'lib/callback';
var DropDown = React.createClass({
let DropDown = React.createClass({
propTypes: {
defaultSelectedIndex: React.PropTypes.number,
selectedIndex: React.PropTypes.number,
items: React.PropTypes.arrayOf(React.PropTypes.shape({
content: React.PropTypes.string.isRequired,
content: React.PropTypes.node.isRequired,
icon: React.PropTypes.string
})).isRequired
},
@ -31,11 +31,11 @@ var DropDown = React.createClass({
},
getAnimationStyles() {
var closedStyle = {
let closedStyle = {
opacity: spring(0, [200, 20]),
translateY: spring(20, [200, 20])
};
var openedStyle = {
let openedStyle = {
opacity: spring(1, [200, 20]),
translateY: spring(0, [200, 20])
};
@ -47,12 +47,12 @@ var DropDown = React.createClass({
},
render() {
var animation = this.getAnimationStyles();
let animation = this.getAnimationStyles();
return (
<div className={this.getClass()}>
<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>
<Motion defaultStyle={animation.defaultStyle} style={animation.style}>
{this.renderList}
@ -62,7 +62,7 @@ var DropDown = React.createClass({
},
renderList({opacity, translateY}) {
var style = { opacity: opacity, transform: `translateY(${translateY}px)`};
let style = { opacity: opacity, transform: `translateY(${translateY}px)`};
return (
<div className="drop-down--list-container" style={style}>
@ -75,14 +75,14 @@ var DropDown = React.createClass({
renderItem(item, index) {
return (
<li className="drop-down--list-item" onClick={this.handleItemClick.bind(this, index)} onMouseDown={this.handleItemMouseDown}>
<li {...this.getItemProps(index)}>
{item.content}
</li>
);
},
getClass() {
var classes = {
let classes = {
'drop-down': true,
[this.props.className]: (this.props.className)
@ -91,6 +91,15 @@ var DropDown = React.createClass({
return classNames(classes);
},
getItemProps(index) {
return {
className: 'drop-down--list-item',
onClick: this.handleItemClick.bind(this, index),
onMouseDown: this.handleItemMouseDown,
key: index
};
},
handleBlur() {
this.setState({
opened: false
@ -110,7 +119,9 @@ var DropDown = React.createClass({
});
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 {reactDFS, renderChildrenWithProps} from 'lib/react-dfs';
@ -6,7 +6,7 @@ import {reactDFS, renderChildrenWithProps} from 'lib/react-dfs';
import Input from 'core-components/input';
import Checkbox from 'core-components/checkbox';
var Form = React.createClass({
let Form = React.createClass({
validations: {},
@ -17,7 +17,7 @@ var Form = React.createClass({
},
componentDidMount() {
var formState = {};
let formState = {};
reactDFS(this.props.children, (child) => {
if (child.type === Input) {
@ -42,7 +42,7 @@ var Form = React.createClass({
},
getProps() {
var props = _.clone(this.props);
let props = _.clone(this.props);
props.onSubmit = this.handleSubmit;
@ -50,7 +50,7 @@ var Form = React.createClass({
},
getInputProps({props, type}) {
var additionalProps = {};
let additionalProps = {};
if (type === Input || type === Checkbox) {
let inputName = props.name;
@ -75,7 +75,7 @@ var Form = React.createClass({
},
handleInputChange(inputName, type, event) {
var form = _.clone(this.state.form);
let form = _.clone(this.state.form);
form[inputName] = event.target.value;

View File

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

View File

@ -2,7 +2,7 @@ import React from 'react';
import classNames from 'classnames';
import _ from 'lodash';
var Input = React.createClass({
let Input = React.createClass({
propTypes: {
value: React.PropTypes.string,
@ -28,7 +28,7 @@ var Input = React.createClass({
},
getProps() {
var props = _.clone(this.props);
let props = _.clone(this.props);
props.type = (this.props.password) ? 'password' : 'text';
@ -36,7 +36,7 @@ var Input = React.createClass({
},
getClass() {
var classes = {
let classes = {
'input': 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 _ from 'lodash';
import {Motion, spring} from 'react-motion';
import Widget from 'core-components/widget';
var WidgetTransition = React.createClass({
let WidgetTransition = React.createClass({
propTypes: {
sideToShow: React.PropTypes.string
@ -35,7 +35,7 @@ var WidgetTransition = React.createClass({
return (
<div className={this.getClass()}>
{React.Children.map(this.props.children, function (child, index) {
var modifiedChild;
let modifiedChild;
if (index === 0) {
modifiedChild = React.cloneElement(child, {
@ -60,7 +60,7 @@ var WidgetTransition = React.createClass({
},
getClass() {
var classes = {
let classes = {
'widget-transition': true,
[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';
var Widget = React.createClass({
let Widget = React.createClass({
propTypes: {
title: React.PropTypes.string,
children: React.PropTypes.node.isRequired
@ -23,7 +23,7 @@ var Widget = React.createClass({
},
renderTitle() {
var titleNode = null;
let titleNode = null;
if (this.props.title) {
titleNode = <h2 className="widget--title">{this.props.title}</h2>;
@ -33,7 +33,7 @@ var Widget = React.createClass({
},
getClass() {
var classes = {
let classes = {
'widget': true
};

View File

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

View File

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

View File

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

View File

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

View File

@ -3,11 +3,11 @@ import MessageFormat from 'messageformat';
import CommonStore from 'stores/common-store';
import i18nData from 'data/i18n-data';
var mf = new MessageFormat('en');
let mf = new MessageFormat('en');
var i18n = function (key, params = null) {
var i18nKey = i18nData(key, CommonStore.language);
var message = mf.compile(i18nKey);
let i18n = function (key, params = null) {
let i18nKey = i18nData(key, CommonStore.language);
let message = mf.compile(i18nKey);
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';
var reactDFS = function (children, visitFunction) {
var stack = [];
let reactDFS = function (children, visitFunction) {
let stack = [];
React.Children.forEach(children, child => stack.push(child));
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) {
return children;
}
return React.Children.map(children, function (child) {
var props = mapFunction(child);
let props = mapFunction(child);
if (typeof child !== 'object' || child === null) {
return child;

View File

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

View File

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

View File

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