Ivan - OS-48 - Add basic login logout logic

This commit is contained in:
ivan 2016-07-07 16:16:38 -03:00
parent 75d4378445
commit 3381d9c222
13 changed files with 221 additions and 21 deletions

View File

@ -1,7 +1,9 @@
import Reflux from 'reflux';
let CommonActions = Reflux.createActions([
'changeLanguage'
'changeLanguage',
'logged',
'loggedOut'
]);
export default CommonActions;

View File

@ -8,6 +8,10 @@ import CommonStore from 'stores/common-store';
let App = React.createClass({
contextTypes: {
router: React.PropTypes.object
},
mixins: [Reflux.listenTo(CommonStore, 'onCommonStoreChanged')],
render() {
@ -19,8 +23,14 @@ let App = React.createClass({
},
onCommonStoreChanged(change) {
if (change === 'i18n') {
this.forceUpdate();
let handle = {
'i18n': () => {this.forceUpdate()},
'logged': () => {this.context.router.push('/app/dashboard')},
'loggedOut': () => {this.context.router.push('/app')}
};
if (handle[change]) {
handle[change]();
}
}
});

View File

@ -1,8 +1,18 @@
import React from 'react';
import UserStore from 'stores/user-store';
import CommonActions from 'actions/common-actions';
import DashboardMenu from 'app/main/dashboard/dashboard-menu';
const DashboardLayout = React.createClass({
componentWillMount() {
if (!UserStore.isLoggedIn()) {
CommonActions.loggedOut();
}
},
render() {
return (
<div>

View File

@ -1,4 +1,6 @@
const React = require( 'react');
const React = require('react');
const Reflux = require('reflux');
const _ = require('lodash');
const classNames = require('classnames');
const UserActions = require('actions/user-actions');
@ -12,10 +14,13 @@ const Widget = require('core-components/widget');
const WidgetTransition = require('core-components/widget-transition');
let MainHomePageLoginWidget = React.createClass({
mixins: [Reflux.listenTo(UserStore, 'onUserStoreChanged')],
getInitialState() {
return {
sideToShow: 'front'
sideToShow: 'front',
loginFormErrors: {}
};
},
@ -31,7 +36,7 @@ let MainHomePageLoginWidget = React.createClass({
renderLogin() {
return (
<Widget className="main-home-page--widget" title="Login">
<Form className="login-widget--form" onSubmit={this.handleLoginFormSubmit}>
<Form className="login-widget--form" ref="loginForm" onSubmit={this.handleLoginFormSubmit} errors={this.state.loginFormErrors} onValidateErrors={this.handleLoginFormErrorsValidation}>
<div className="login-widget--inputs">
<Input placeholder="email" name="email" className="login-widget--input" validation="EMAIL" required/>
<Input placeholder="password" name="password" className="login-widget--input" password required/>
@ -71,6 +76,12 @@ let MainHomePageLoginWidget = React.createClass({
UserActions.login(formState);
},
handleLoginFormErrorsValidation(errors) {
this.setState({
loginFormErrors: errors
});
},
handleForgetPasswordClick() {
this.setState({
sideToShow: 'back'
@ -81,6 +92,18 @@ let MainHomePageLoginWidget = React.createClass({
this.setState({
sideToShow: 'front'
});
},
onUserStoreChanged(event) {
if (event === 'LOGIN_FAIL') {
this.setState({
loginFormErrors: {
password: 'Password does not match'
}
}, function () {
this.refs.loginForm.refs.password.focus()
}.bind(this));
}
}
});

View File

@ -3,8 +3,17 @@ const React = require( 'react');
const MainHomePageLoginWidget = require('app/main/main-home/main-home-page-login-widget');
const MainHomePagePortal = require('app/main/main-home/main-home-page-portal');
const CommonActions = require('actions/common-actions');
const UserStore = require('stores/user-store');
const MainHomePage = React.createClass({
componentWillMount() {
if (UserStore.isLoggedIn()) {
CommonActions.logged();
}
},
render() {
return (
<div className="main-home-page">

View File

@ -2,6 +2,8 @@ import React from 'react';
import i18n from 'lib-app/i18n';
import CommonActions from 'actions/common-actions';
import UserActions from 'actions/user-actions';
import UserStore from 'stores/user-store';
import Button from 'core-components/button';
import DropDown from 'core-components/drop-down';
@ -22,13 +24,31 @@ let MainLayoutHeader = React.createClass({
render() {
return (
<div className="main-layout-header">
{this.renderAccessLinks()}
<DropDown className="main-layout-header--languages" items={this.getLanguageList()} onChange={this.changeLanguage}/>
</div>
);
},
renderAccessLinks() {
let result;
if (UserStore.isLoggedIn()) {
result = (
<div className="main-layout-header--login-links">
Welcome, pepito
<Button type="clean" onClick={this.logout}>(Close Session)</Button>
</div>
);
} else {
result = (
<div className="main-layout-header--login-links">
<Button type="clean" route={{to:'/app'}}>{i18n('LOG_IN')}</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>
);
);
}
return result;
},
getLanguageList() {
@ -44,6 +64,10 @@ let MainLayoutHeader = React.createClass({
let language = languageList[event.index];
CommonActions.changeLanguage(codeLanguages[language]);
},
logout() {
UserActions.logout();
}
});

View File

@ -11,8 +11,16 @@ import Input from 'core-components/input';
import Widget from 'core-components/widget';
import WidgetTransition from 'core-components/widget-transition';
const CommonActions = require('actions/common-actions');
let MainSignUpPageWidget = React.createClass({
componentDidMount() {
if (UserStore.isLoggedIn()) {
CommonActions.logged();
}
},
render() {
return (
<div className="main-signup-page">

View File

@ -10,6 +10,12 @@ const Checkbox = require('core-components/checkbox');
const Form = React.createClass({
propTypes: {
errors: React.PropTypes.func,
onValidateErrors: React.PropTypes.func,
onSubmit: React.PropTypes.func
},
getInitialState() {
return {
form: {},
@ -47,7 +53,7 @@ const Form = React.createClass({
additionalProps = {
ref: fieldName,
value: this.state.form[fieldName] || props.value,
error: this.state.errors[fieldName],
error: this.getFieldError(fieldName),
onChange: this.handleFieldChange.bind(this, fieldName, type),
onBlur: this.validateField.bind(this, fieldName)
}
@ -56,6 +62,15 @@ const Form = React.createClass({
return additionalProps;
},
getFieldError(fieldName) {
let error = this.state.errors[fieldName];
if (this.props.errors) {
error = this.props.errors[fieldName]
}
return error;
},
getFirstErrorField() {
let fieldName = _.findKey(this.state.errors);
let fieldNode;
@ -119,9 +134,7 @@ const Form = React.createClass({
event.preventDefault();
if (this.hasFormErrors()) {
this.setState({
errors: this.getAllFieldErrors()
}, this.focusFirstErrorField);
this.updateErrors(this.getAllFieldErrors(), this.focusFirstErrorField);
} else if (this.props.onSubmit) {
this.props.onSubmit(this.state.form);
}
@ -150,9 +163,17 @@ const Form = React.createClass({
},
validateField(fieldName) {
this.updateErrors(this.getErrorsWithValidatedField(fieldName));
},
updateErrors(errors, callback) {
this.setState({
errors: this.getErrorsWithValidatedField(fieldName)
});
errors
}, callback);
if (this.props.onValidateErrors) {
this.props.onValidateErrors(errors);
}
},
focusFirstErrorField() {

View File

@ -22,5 +22,15 @@ module.exports = [
return response;
}
},
{
path: 'user/logout',
time: 1000,
response: function () {
return {
status: 'success',
data: {}
};
}
}
];

View File

@ -12,8 +12,14 @@ function processData (data) {
}
module.exports = {
call: function (path, data, callback) {
APIUtils.post(root + path, processData(data)).then(callback);
call: function ({path, data, onSuccess, onFail}) {
APIUtils.post(root + path, processData(data)).then(function (result) {
if (result.status === 'success') {
onSuccess && onSuccess(result);
} else {
onFail && onFail(result);
}
});
},
setConfig: function (userId, token) {
SessionStorage.setItem('userId', userId);

View File

@ -0,0 +1,35 @@
import SessionStorage from 'sessionstorage';
class SessionStore {
static initialize() {
if (!SessionStorage.getItem('language')) {
SessionStorage.setItem('language', 'english');
}
}
static createSession(userId, token) {
SessionStorage.setItem('userId', userId);
SessionStorage.setItem('token', token);
}
static getSessionData() {
return {
userId: SessionStorage.getItem('userId'),
token: SessionStorage.getItem('token')
};
}
static isLoggedIn() {
return !!SessionStorage.getItem('userId');
}
static closeSession() {
SessionStorage.removeItem('userId');
SessionStorage.removeItem('token');
}
}
SessionStore.initialize();
export default SessionStore;

View File

@ -8,11 +8,25 @@ let CommonStore = Reflux.createStore({
this.language = 'us';
this.listenTo(CommonActions.changeLanguage, this.changeLanguage);
this.listenTo(CommonActions.logged, this.logged);
this.listenTo(CommonActions.loggedOut, this.loggedOut);
},
changeLanguage(lang) {
this.language = lang;
this.trigger('i18n');
},
logged() {
this.trigger('logged');
},
loggedOut() {
this.trigger('loggedOut');
},
isLogged() {
return this.logged()
}
});

View File

@ -1,7 +1,9 @@
const Reflux = require('reflux');
const API = require('lib-app/api-call');
const SessionStore = require('lib-app/session-store');
const UserActions = require('actions/user-actions');
const CommonActions = require('actions/common-actions');
const UserStore = Reflux.createStore({
@ -15,11 +17,37 @@ const UserStore = Reflux.createStore({
},
loginUser(loginData) {
API.call('user/login', loginData, result => {
console.log(result);
API.setConfig(result.userId, result.token);
API.call({
path: 'user/login',
data: loginData,
onSuccess: this.handleLoginSuccess,
onFail: this.handleLoginFail
});
},
logoutUser() {
API.call({
path: 'user/logout',
onSuccess: function () {
SessionStore.closeSession();
this.trigger('LOGOUT');
CommonActions.loggedOut();
}.bind(this)
});
},
isLoggedIn() {
return SessionStore.isLoggedIn();
},
handleLoginSuccess(result) {
SessionStore.createSession(result.data.userId, result.data.token);
this.trigger('LOGIN_SUCCESS');
CommonActions.logged();
},
handleLoginFail(result) {
this.trigger('LOGIN_FAIL');
}
});