Client: login/register

Client: login/register

Client: login/register

Client: login/register


Client: login/register


Client: login/register

Client: login/register

Client: login/register

Client: login/register
This commit is contained in:
SamR1
2017-12-25 17:45:28 +01:00
parent 166cbd201a
commit 3b13ee67c0
15 changed files with 568 additions and 41 deletions

View File

@ -0,0 +1,117 @@
import mpwoApi from '../mpwoApi'
function AuthError(message) {
return { type: 'AUTH_ERROR', message }
}
function ProfileSuccess(message) {
return { type: 'PROFILE_SUCCESS', message }
}
function ProfileError(message) {
return { type: 'PROFILE_ERROR', message }
}
const updateFormDataEmail = value => ({
type: 'UPDATE_FORMDATA_EMAIL',
email: value,
})
const updateFormDataUsername = value => ({
type: 'UPDATE_FORMDATA_USERNAME',
username: value,
})
const updateFormDataPassword = value => ({
type: 'UPDATE_FORMDATA_PASSWORD',
password: value,
})
export function getProfile(dispatch) {
return mpwoApi
.getProfile()
.then(ret => {
if (ret.status === 'success') {
dispatch(ProfileSuccess(ret))
} else {
dispatch(ProfileError(ret.message))
}
})
.catch(error => {
throw error
})
}
export function register(formData) {
return function(dispatch) {
return mpwoApi
.register(formData.username, formData.email, formData.password)
.then(ret => {
if (ret.status === 'success') {
window.localStorage.setItem('authToken', ret.auth_token)
getProfile(dispatch)
} else {
dispatch(AuthError(ret.message))
}
})
.catch(error => {
throw error
})
}
}
export function login(formData) {
return function(dispatch) {
return mpwoApi
.login(formData.email, formData.password)
.then(ret => {
if (ret.status === 'success') {
window.localStorage.setItem('authToken', ret.auth_token)
getProfile(dispatch)
} else {
dispatch(AuthError(ret.message))
}
})
.catch(error => {
throw error
})
}
}
export function loadProfile() {
if (window.localStorage.getItem('authToken')) {
return function(dispatch) {
getProfile(dispatch)
}
}
return { type: 'LOGOUT' }
}
export function logout() {
return { type: 'LOGOUT' }
}
export function handleUserFormSubmit(event, formType) {
event.preventDefault()
return (dispatch, getState) => {
const state = getState()
let { formData } = state.formData
formData.formData = state.formData.formData
if (formType === 'Login') {
dispatch(login(formData.formData))
} else { // formType === 'Register'
dispatch(register(formData.formData))
}
}
}
export const handleFormChange = event => dispatch => {
switch (event.target.name) {
case 'email':
return dispatch(updateFormDataEmail(event.target.value))
case 'username':
return dispatch(updateFormDataUsername(event.target.value))
default: // case 'password':
return dispatch(updateFormDataPassword(event.target.value))
}
}

View File

@ -1,7 +1,10 @@
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import './App.css'
import Logout from './Logout'
import NavBar from './NavBar'
import UserForm from './User/UserForm'
export default class App extends React.Component {
constructor(props) {
@ -13,9 +16,37 @@ export default class App extends React.Component {
return (
<div className="App">
<NavBar />
<p className="App-body">
App in progress
</p>
<div className="container">
<div className="row">
<div className="col-md-6">
<br />
<Switch>
<Route
exact path="/register"
render={() => (
<UserForm
formType={'Register'}
/>
)}
/>
<Route
exact path="/login"
render={() => (
<UserForm
formType={'Login'}
/>
)}
/>
<Route
exact path="/logout"
render={() => (
<Logout />
)}
/>
</Switch>
</div>
</div>
</div>
</div>
)
}

View File

@ -0,0 +1,31 @@
import React from 'react'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import { logout } from '../actions'
class Logout extends React.Component {
componentDidMount() {
this.props.UserLogout()
}
render() {
return (
<div>
<p>
You are now logged out.
Click <Link to="/login">here</Link> to log back in.</p>
</div>
)
}
}
export default connect(
state => ({
user: state.user,
}),
dispatch => ({
UserLogout: () => {
dispatch(logout())
}
})
)(Logout)

View File

@ -1,14 +1,9 @@
import React from 'react'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
export default class NavBar extends React.Component {
constructor(props) {
super(props)
this.props = props
}
render() {
return (
function NavBar (props) {
return (
<header>
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<span className="navbar-brand">mpwo</span>
@ -36,10 +31,50 @@ export default class NavBar extends React.Component {
Home
</Link>
</li>
{!props.user.isAuthenticated && (
<li className="nav-item">
<Link
className="nav-link"
to={{
pathname: '/login',
}}
>
Login
</Link>
</li>
)}
{!props.user.isAuthenticated && (
<li className="nav-item">
<Link
className="nav-link"
to={{
pathname: '/register',
}}
>
Register
</Link>
</li>
)}
{props.user.isAuthenticated && (
<li className="nav-item">
<Link
className="nav-link"
to={{
pathname: '/logout',
}}
>
Logout
</Link>
</li>
)}
</ul>
</div>
</nav>
</header>
)
}
)
}
export default connect(
state => ({
user: state.user,
})
)(NavBar)

View File

@ -0,0 +1,52 @@
import React from 'react'
export default function Form (props) {
return (
<div>
<h1>{props.formType}</h1>
<hr /><br />
<form onSubmit={event =>
props.handleUserFormSubmit(event, props.formType)}
>
{props.formType === 'Register' &&
<div className="form-group">
<input
name="username"
className="form-control input-lg"
type="text"
placeholder="Enter a username"
required
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>
<div className="form-group">
<input
name="password"
className="form-control input-lg"
type="password"
placeholder="Enter a password"
required
onChange={props.onHandleFormChange}
/>
</div>
<input
type="submit"
className="btn btn-primary btn-lg btn-block"
value="Submit"
/>
</form>
</div>
)
}

View File

@ -0,0 +1,36 @@
import React from 'react'
import { connect } from 'react-redux'
import Form from './Form'
import { handleFormChange, handleUserFormSubmit } from '../../actions'
function UserForm(props) {
return (
<div>
{props.message !== '' && (
<code>{props.message}</code>
)}
<Form
formType={props.formType}
userForm={props.formData}
onHandleFormChange={event => props.onHandleFormChange(event)}
handleUserFormSubmit={(event, formType) =>
props.onHandleUserFormSubmit(event, formType)}
/>
</div>
)
}
export default connect(
state => ({
formData: state.formData,
message: state.message,
}),
dispatch => ({
onHandleFormChange: event => {
dispatch(handleFormChange(event))
},
onHandleUserFormSubmit: (event, formType) => {
dispatch(handleUserFormSubmit(event, formType))
},
})
)(UserForm)

View File

@ -10,7 +10,7 @@ import App from './components/App'
import Root from './components/Root'
import registerServiceWorker from './registerServiceWorker'
import reducers from './reducers'
import { loadProfile } from './actions'
export const history = createBrowserHistory()
@ -24,6 +24,10 @@ export const store = createStore(
)
)
if (window.localStorage.getItem('authToken') !== null) {
store.dispatch(loadProfile())
}
ReactDOM.render(
<Root store={store} history={history}>
<App />

View File

@ -0,0 +1,48 @@
const apiUrl = `${process.env.REACT_APP_API_URL}`
export default class MpwoApi {
static login(email, password) {
const request = new Request(`${apiUrl}auth/login`, {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json',
}),
body: JSON.stringify({
email: email,
password: password,
}),
})
return fetch(request)
.then(response => response.json())
.catch(error => error)
}
static register(username, email, password) {
const request = new Request(`${apiUrl}auth/register`, {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json',
}),
body: JSON.stringify({
username: username,
email: email,
password: password,
}),
})
return fetch(request)
.then(response => response.json())
.catch(error => error)
}
static getProfile() {
const request = new Request(`${apiUrl}auth/profile`, {
method: 'GET',
headers: new Headers({
'Content-Type': 'application/json',
Authorization: `Bearer ${window.localStorage.getItem('authToken')}`,
}),
})
return fetch(request)
.then(response => response.json())
.catch(error => error)
}
}

View File

@ -1,9 +1,76 @@
import { combineReducers } from 'redux'
import user from './user'
import initial from './initial'
const message = (state = initial.message, action) => {
switch (action.type) {
case 'AUTH_ERROR':
case 'PROFILE_ERROR':
return action.message
case 'LOGOUT':
return ''
case 'PROFILE_SUCCESS':
return ''
default:
return state
}
}
const user = (state = initial.user, action) => {
switch (action.type) {
case 'AUTH_ERROR':
case 'PROFILE_ERROR':
case 'LOGOUT':
window.localStorage.removeItem('authToken')
return initial.user
case 'PROFILE_SUCCESS':
return {
id: action.message.data.id,
username: action.message.data.username,
email: action.message.data.email,
isAdmin: action.message.data.admin,
createdAt: action.message.data.created_at,
isAuthenticated: true
}
default:
return state
}
}
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,
})
export default reducers

View File

@ -0,0 +1,18 @@
export default {
message: '',
user: {
id: '',
username: '',
email: '',
createdAt: '',
isAdmin: false,
isAuthenticated: false,
},
formData: {
formData: {
username: '',
email: '',
password: ''
}
},
}

View File

@ -1,21 +0,0 @@
const user = (state = null, action) => {
switch (action.type) {
case 'AUTH_ERROR':
case 'PROFILE_ERROR':
case 'LOGOUT':
window.localStorage.removeItem('authToken')
return null
case 'PROFILE_SUCCESS':
return {
id: action.message.data.id,
username: action.message.data.username,
email: action.message.data.email,
isAdmin: action.message.data.is_admin,
createdAt: action.message.data.created_at,
}
default:
return state
}
}
export default user