# HG changeset patch # User Alexandre Segura # Date 1498484750 -7200 # Node ID 06f609adfbf8758c0cfccd2356971f6b1308b6a6 # Parent 2a861fed6bded4576bf6aa712be42b71bf96e4ad Add registration page. diff -r 2a861fed6bde -r 06f609adfbf8 client/src/App.scss --- a/client/src/App.scss Mon Jun 26 16:05:47 2017 +0200 +++ b/client/src/App.scss Mon Jun 26 15:45:50 2017 +0200 @@ -169,7 +169,7 @@ .start { top: 0; left: 0; - padding: 10px 0 0 10px; + padding: 20px 0 0 10px; } .finish { bottom: 0; @@ -198,3 +198,8 @@ background-color: #fff; padding: 20px 0; } + +.panel-login, +.panel-register { + margin-top: 60px; +} diff -r 2a861fed6bde -r 06f609adfbf8 client/src/actions/authActions.js --- a/client/src/actions/authActions.js Mon Jun 26 16:05:47 2017 +0200 +++ b/client/src/actions/authActions.js Mon Jun 26 15:45:50 2017 +0200 @@ -13,3 +13,13 @@ type: types.AUTH_LOGOUT }; } + +export const registerSubmit = (username, email, password1, password2) => { + return { + type: types.AUTH_REGISTER_SUBMIT, + username, + email, + password1, + password2 + }; +} diff -r 2a861fed6bde -r 06f609adfbf8 client/src/components/Login.js --- a/client/src/components/Login.js Mon Jun 26 16:05:47 2017 +0200 +++ b/client/src/components/Login.js Mon Jun 26 15:45:50 2017 +0200 @@ -15,6 +15,11 @@ this.props.authActions.loginSubmit(username, password); } + onClickRegister = (e) => { + e.preventDefault(); + this.props.history.push('/register'); + } + renderError() { return ( Bad credentials @@ -22,13 +27,18 @@ } render() { + + const panelHeader = ( +

Login

+ ) + return (
- +
Username @@ -42,6 +52,9 @@
+

+ Not registered yet? Create an account. +

diff -r 2a861fed6bde -r 06f609adfbf8 client/src/components/Register.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/Register.js Mon Jun 26 15:45:50 2017 +0200 @@ -0,0 +1,101 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { Grid, Row, Col, Panel, FormGroup, ControlLabel, FormControl, Button, Alert, HelpBlock } from 'react-bootstrap'; +import '../App.css'; +import Navbar from './Navbar'; +import * as authActions from '../actions/authActions'; + +class Register extends Component { + + register = () => { + const username = this.username.value; + const email = this.email.value; + const password1 = this.password1.value; + const password2 = this.password2.value; + + this.props.authActions.registerSubmit(username, email, password1, password2); + } + + onClickLogin = (e) => { + e.preventDefault(); + this.props.history.push('/login'); + } + + renderError() { + return ( + Bad credentials + ) + } + + renderErrorMessage(errorMessages, fieldname) { + if (errorMessages && errorMessages.has(fieldname)) { + return errorMessages.get(fieldname).map((message, key) => + { message } + ); + } + } + + render() { + + const panelHeader = ( +

Register

+ ) + + const errorMessages = this.props.register.get('errorMessages'); + + return ( +
+ + + + + +
+ + Username + { this.username = ref; }} /> + { this.renderErrorMessage(errorMessages, 'username') } + + + Email + { this.email = ref; }} /> + { this.renderErrorMessage(errorMessages, 'email') } + + + Password + { this.password1 = ref; }} /> + { this.renderErrorMessage(errorMessages, 'password1') } + + + Confirm password + { this.password2 = ref; }} /> + { this.renderErrorMessage(errorMessages, 'password2') } + + +
+
+

+ Already registered? Sign in. +

+ +
+
+
+ ); + } +} + +function mapStateToProps(state, props) { + return { + register: state['register'] + }; +} + +function mapDispatchToProps(dispatch) { + return { + authActions: bindActionCreators(authActions, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Register); diff -r 2a861fed6bde -r 06f609adfbf8 client/src/constants/actionTypes.js --- a/client/src/constants/actionTypes.js Mon Jun 26 16:05:47 2017 +0200 +++ b/client/src/constants/actionTypes.js Mon Jun 26 15:45:50 2017 +0200 @@ -12,6 +12,12 @@ export const AUTH_LOGIN_REQUEST = 'AUTH_LOGIN_REQUEST'; export const AUTH_LOGIN_SUCCESS = 'AUTH_LOGIN_SUCCESS'; export const AUTH_LOGIN_ERROR = 'AUTH_LOGIN_ERROR'; + +export const AUTH_REGISTER_SUBMIT = 'AUTH_REGISTER_SUBMIT'; +export const AUTH_REGISTER_REQUEST = 'AUTH_REGISTER_REQUEST'; +export const AUTH_REGISTER_SUCCESS = 'AUTH_REGISTER_SUCCESS'; +export const AUTH_REGISTER_ERROR = 'AUTH_REGISTER_ERROR'; + export const AUTH_STORE_TOKEN_ASYNC = 'AUTH_STORE_TOKEN_ASYNC'; export const AUTH_STORE_TOKEN = 'AUTH_STORE_TOKEN'; export const AUTH_LOGOUT = 'AUTH_LOGOUT'; diff -r 2a861fed6bde -r 06f609adfbf8 client/src/index.js --- a/client/src/index.js Mon Jun 26 16:05:47 2017 +0200 +++ b/client/src/index.js Mon Jun 26 15:45:50 2017 +0200 @@ -9,6 +9,7 @@ import SessionList from './components/SessionList'; import Session from './components/Session'; import Login from './components/Login'; +import Register from './components/Register'; import Settings from './components/Settings'; import './index.css'; import registerServiceWorker from './registerServiceWorker'; @@ -27,6 +28,7 @@ +
diff -r 2a861fed6bde -r 06f609adfbf8 client/src/reducers/authReducer.js --- a/client/src/reducers/authReducer.js Mon Jun 26 16:05:47 2017 +0200 +++ b/client/src/reducers/authReducer.js Mon Jun 26 15:45:50 2017 +0200 @@ -8,6 +8,7 @@ case types.AUTH_LOGOUT: return false; case types.AUTH_LOGIN_SUCCESS: + case types.AUTH_REGISTER_SUCCESS: return true; default: return state; @@ -20,6 +21,7 @@ case types.AUTH_LOGOUT: return null; case types.AUTH_LOGIN_SUCCESS: + case types.AUTH_REGISTER_SUCCESS: return new UserRecord(action.user); case types.USER_UPDATE_SETTINGS: return state.merge({ @@ -68,3 +70,31 @@ return state } } + +const registerState = Immutable.Map({ + loading: false, + success: false, + error: false, + errorMessages: Immutable.Map({}) +}); + +export const register = (state = registerState, action) => { + switch (action.type) { + case types.AUTH_REGISTER_REQUEST: + return Immutable.Map({ + loading: true, + success: false, + error: false, + }) + case types.AUTH_REGISTER_SUCCESS: + case types.AUTH_REGISTER_ERROR: + return Immutable.Map({ + loading: false, + success: action.type === types.AUTH_REGISTER_SUCCESS, + error: action.type === types.AUTH_REGISTER_ERROR, + errorMessages: action.type === types.AUTH_REGISTER_ERROR ? Immutable.Map(action.error) : Immutable.Map({}) + }) + default: + return state + } +} diff -r 2a861fed6bde -r 06f609adfbf8 client/src/reducers/index.js --- a/client/src/reducers/index.js Mon Jun 26 16:05:47 2017 +0200 +++ b/client/src/reducers/index.js Mon Jun 26 15:45:50 2017 +0200 @@ -4,7 +4,7 @@ import notes from './notesReducer'; import { sessions } from './sessionsReducer'; -import { isAuthenticated, currentUser, login, token } from './authReducer'; +import { isAuthenticated, currentUser, login, register, token } from './authReducer'; import { autoSubmit } from './miscReducer'; const rootReducer = combineReducers({ @@ -13,6 +13,7 @@ isAuthenticated, currentUser, login, + register, token, router: routerReducer, autoSubmit diff -r 2a861fed6bde -r 06f609adfbf8 client/src/sagas/authSaga.js --- a/client/src/sagas/authSaga.js Mon Jun 26 16:05:47 2017 +0200 +++ b/client/src/sagas/authSaga.js Mon Jun 26 15:45:50 2017 +0200 @@ -37,6 +37,45 @@ } } +export function* watchRegisterSubmit() { + while (true) { + const { username, email, password1, password2 } = yield take(types.AUTH_REGISTER_SUBMIT); + yield put({ type: types.AUTH_REGISTER_REQUEST, username, email, password1, password2 }); + } +} + +function* watchRegisterRequest(context) { + while (true) { + try { + + const { username, email, password1, password2 } = yield take(types.AUTH_REGISTER_REQUEST); + + const client = context.client; + const response = yield client.post('/api/auth/registration/', { + username, + email, + password1, + password2 + }); + + const actions = [{ + type: types.AUTH_STORE_TOKEN_ASYNC, + token: response.token, + }, { + type: types.AUTH_REGISTER_SUCCESS, + user: response.user, + token: response.token, + }]; + + yield all(actions.map(action => put(action))); + context.history.push('/sessions'); + + } catch(e) { + yield put({ type: types.AUTH_REGISTER_ERROR, error: e }); + } + } +} + function* watchStoreToken() { while (true) { const { token } = yield take(types.AUTH_STORE_TOKEN_ASYNC); @@ -67,6 +106,8 @@ yield all([ watchLoginSubmit(), watchLoginRequest(context), + watchRegisterSubmit(), + watchRegisterRequest(context), watchStoreToken(), watchUpdateSettings(context), ]) diff -r 2a861fed6bde -r 06f609adfbf8 client/src/store/configureStore.js --- a/client/src/store/configureStore.js Mon Jun 26 16:05:47 2017 +0200 +++ b/client/src/store/configureStore.js Mon Jun 26 15:45:50 2017 +0200 @@ -35,7 +35,13 @@ loading: false, success: false, error: false, - }) + }), + register: Immutable.Map({ + loading: false, + success: false, + error: false, + errorMessages: Immutable.Map({}) + }), }; const immutableTransformConfig = {