API & Client: registration controls

This commit is contained in:
SamR1
2018-01-01 11:10:39 +01:00
parent 62d87d05f5
commit cac4f368bf
16 changed files with 346 additions and 73 deletions

View File

@ -7,6 +7,7 @@
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-helmet": "^5.2.0",
"react-key-index": "^0.1.1",
"react-redux": "^5.0.6",
"react-router-dom": "^4.2.2",
"react-router-redux": "^5.0.0-alpha.9",

View File

@ -1,9 +1,14 @@
import keyIndex from 'react-key-index'
import mpwoApi from '../mpwoApi'
function AuthError(message) {
return { type: 'AUTH_ERROR', message }
}
function AuthErrors(messages) {
return { type: 'AUTH_ERRORS', messages }
}
function ProfileSuccess(message) {
return { type: 'PROFILE_SUCCESS', message }
}
@ -27,6 +32,11 @@ const updateFormDataPassword = value => ({
password: value,
})
const updateFormDataPasswordConf = value => ({
type: 'UPDATE_FORMDATA_PASSWORD_CONF',
passwordConf: value,
})
export function getProfile(dispatch) {
return mpwoApi
.getProfile()
@ -46,7 +56,11 @@ export function getProfile(dispatch) {
export function register(formData) {
return function(dispatch) {
return mpwoApi
.register(formData.username, formData.email, formData.password)
.register(
formData.username,
formData.email,
formData.password,
formData.passwordConf)
.then(ret => {
if (ret.status === 'success') {
window.localStorage.setItem('authToken', ret.auth_token)
@ -92,6 +106,20 @@ export function logout() {
return { type: 'LOGOUT' }
}
function RegisterFormControl (formData) {
const errMsg = []
if (formData.username.length < 3 || formData.username.length > 12) {
errMsg.push('Username: 3 to 12 characters required.')
}
if (formData.password !== formData.passwordConf) {
errMsg.push('Password and password confirmation don\'t match.')
}
if (formData.password.length < 8) {
errMsg.push('Password: 8 characters required.')
}
return errMsg
}
export function handleUserFormSubmit(event, formType) {
event.preventDefault()
return (dispatch, getState) => {
@ -101,7 +129,12 @@ export function handleUserFormSubmit(event, formType) {
if (formType === 'Login') {
dispatch(login(formData.formData))
} else { // formType === 'Register'
dispatch(register(formData.formData))
const ret = RegisterFormControl(formData.formData)
if (ret.length === 0) {
dispatch(register(formData.formData))
} else {
dispatch(AuthErrors(keyIndex(ret, 1)))
}
}
}
}
@ -112,7 +145,9 @@ export const handleFormChange = event => dispatch => {
return dispatch(updateFormDataEmail(event.target.value))
case 'username':
return dispatch(updateFormDataUsername(event.target.value))
default: // case 'password':
case 'password':
return dispatch(updateFormDataPassword(event.target.value))
default: // case 'password-conf':
return dispatch(updateFormDataPasswordConf(event.target.value))
}
}

View File

@ -1,5 +1,5 @@
.App {
/*text-align: center;*/
text-align: center;
}
.App-logo {
@ -27,6 +27,10 @@
to { transform: rotate(360deg); }
}
.card {
text-align: left;
}
.page-title {
font-size: 2em;
margin: 1em;

View File

@ -1,10 +1,13 @@
import React from 'react'
import { Helmet } from 'react-helmet'
export default function Form (props) {
return (
<div>
<h1>{props.formType}</h1>
<Helmet>
<title>mpwo - {props.formType}</title>
</Helmet>
<h1 className="page-title">{props.formType}</h1>
<div className="container">
<div className="row">
<div className="col-md-3" />
@ -13,7 +16,7 @@ export default function Form (props) {
<form onSubmit={event =>
props.handleUserFormSubmit(event, props.formType)}
>
{props.formType === 'Register' &&
{props.formType === 'Register' &&
<div className="form-group">
<input
name="username"
@ -24,16 +27,16 @@ export default function Form (props) {
onChange={props.onHandleFormChange}
/>
</div>
}
<div className="form-group">
<input
name="email"
className="form-control input-lg"
type="email"
placeholder="Enter an email address"
required
onChange={props.onHandleFormChange}
/>
}
<div className="form-group">
<input
name="email"
className="form-control input-lg"
type="email"
placeholder="Enter an email address"
required
onChange={props.onHandleFormChange}
/>
</div>
<div className="form-group">
<input
@ -45,6 +48,18 @@ export default function Form (props) {
onChange={props.onHandleFormChange}
/>
</div>
{props.formType === 'Register' &&
<div className="form-group">
<input
name="password-conf"
className="form-control input-lg"
type="password"
placeholder="Enter password confirmation"
required
onChange={props.onHandleFormChange}
/>
</div>
}
<input
type="submit"
className="btn btn-primary btn-lg btn-block"

View File

@ -11,7 +11,7 @@ class Logout extends React.Component {
render() {
return (
<div>
<p>
<p className="App-center">
You are now logged out.
Click <Link to="/login">here</Link> to log back in.</p>
</div>

View File

@ -16,6 +16,17 @@ function UserForm(props) {
{ props.message !== '' && (
<code>{props.message}</code>
)}
{ props.messages.length > 0 && (
<code>
<ul>
{props.messages.map(msg => (
<li key={msg.id}>
{msg.value}
</li>
))}
</ul>
</code>
)}
<Form
formType={props.formType}
userForm={props.formData}
@ -32,6 +43,7 @@ export default connect(
state => ({
formData: state.formData,
message: state.message,
messages: state.messages,
}),
dispatch => ({
onHandleFormChange: event => {

View File

@ -17,7 +17,7 @@ export default class MpwoApi {
.then(response => response.json())
.catch(error => error)
}
static register(username, email, password) {
static register(username, email, password, passwordConf) {
const request = new Request(`${apiUrl}auth/register`, {
method: 'POST',
headers: new Headers({
@ -27,6 +27,7 @@ export default class MpwoApi {
username: username,
email: email,
password: password,
password_conf: passwordConf,
}),
})
return fetch(request)

View File

@ -2,20 +2,70 @@ import { combineReducers } from 'redux'
import initial from './initial'
const formData = (state = initial.formData, action) => {
switch (action.type) {
case 'UPDATE_FORMDATA_EMAIL':
return {
formData: {
...state.formData,
email: action.email
},
}
case 'UPDATE_FORMDATA_USERNAME':
return {
formData: {
...state.formData,
username: action.username
},
}
case 'UPDATE_FORMDATA_PASSWORD':
return {
formData: {
...state.formData,
password: action.password
},
}
case 'UPDATE_FORMDATA_PASSWORD_CONF':
return {
formData: {
...state.formData,
passwordConf: action.passwordConf
},
}
case 'PROFILE_SUCCESS':
return initial.formData
default:
return state
}
}
const message = (state = initial.message, action) => {
switch (action.type) {
case 'AUTH_ERROR':
case 'PROFILE_ERROR':
return action.message
case 'LOGOUT':
return ''
case 'PROFILE_SUCCESS':
case '@@router/LOCATION_CHANGE':
return ''
default:
return state
}
}
const messages = (state = initial.messages, action) => {
switch (action.type) {
case 'AUTH_ERRORS':
return action.messages
case 'LOGOUT':
case 'PROFILE_SUCCESS':
case '@@router/LOCATION_CHANGE':
return []
default:
return state
}
}
const user = (state = initial.user, action) => {
switch (action.type) {
case 'AUTH_ERROR':
@ -37,40 +87,11 @@ const user = (state = initial.user, action) => {
}
}
const formData = (state = initial.formData, action) => {
switch (action.type) {
case 'UPDATE_FORMDATA_EMAIL':
return {
formData: {
...state.formData,
email: action.email
},
}
case 'UPDATE_FORMDATA_USERNAME':
return {
formData: {
...state.formData,
username: action.username
},
}
case 'UPDATE_FORMDATA_PASSWORD':
return {
formData: {
...state.formData,
password: action.password
},
}
case 'PROFILE_SUCCESS':
return initial.formData
default:
return state
}
}
const reducers = combineReducers({
message,
user,
formData,
message,
messages,
user,
})
export default reducers

View File

@ -1,5 +1,6 @@
export default {
message: '',
messages: [],
user: {
id: '',
username: '',
@ -12,7 +13,8 @@ export default {
formData: {
username: '',
email: '',
password: ''
password: '',
passwordConf: '',
}
},
}