Update the user store to be immutable

This commit is contained in:
Grégoire Delattre 2017-06-02 14:39:07 +02:00
parent d0d3f63012
commit 06517be48b
4 changed files with 80 additions and 43 deletions

View File

@ -46,7 +46,7 @@ function mapStateToProps(state) {
torrentCount = state.torrentStore.get('torrents').size; torrentCount = state.torrentStore.get('torrents').size;
} }
return { return {
username: state.userStore.username, username: state.userStore.get('username'),
torrentCount: torrentCount, torrentCount: torrentCount,
alerts: state.alerts, alerts: state.alerts,
} }

View File

@ -2,11 +2,13 @@ import React from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { bindActionCreators } from 'redux' import { bindActionCreators } from 'redux'
import { Control, Form } from 'react-redux-form';
import { updateUser } from '../../actions/users' import { updateUser } from '../../actions/users'
function mapStateToProps(state) { function mapStateToProps(state) {
return { user: state.userStore }; return {
polochonToken: state.userStore.get('polochonToken'),
polochonUrl: state.userStore.get('polochonUrl'),
};
} }
const mapDispatchToProps = (dispatch) => const mapDispatchToProps = (dispatch) =>
bindActionCreators({ updateUser }, dispatch) bindActionCreators({ updateUser }, dispatch)
@ -14,16 +16,40 @@ const mapDispatchToProps = (dispatch) =>
class UserEdit extends React.Component { class UserEdit extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = {
polochonToken: props.polochonToken,
polochonUrl: props.polochonUrl,
};
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
this.handleUrlInput = this.handleUrlInput.bind(this);
this.handleTokenInput = this.handleTokenInput.bind(this);
} }
handleSubmit() { handleSubmit(ev) {
ev.preventDefault();
this.props.updateUser({ this.props.updateUser({
'polochon_url': this.props.user.polochonUrl, 'polochon_url': this.refs.polochonUrl.value,
'polochon_token': this.props.user.polochonToken, 'polochon_token': this.refs.polochonToken.value,
'password': this.refs.newPassword.value, 'password': this.refs.newPassword.value,
'password_confirm': this.refs.newPasswordConfirm.value, 'password_confirm': this.refs.newPasswordConfirm.value,
}); });
} }
handleTokenInput() {
this.setState({ polochonToken: this.refs.polochonToken.value });
}
handleUrlInput() {
this.setState({ polochonUrl: this.refs.polochonUrl.value });
}
componentWillReceiveProps(nextProps) {
if ((nextProps.polochonUrl !== "")
&& (this.state.polochonUrl === "")
&& (nextProps.polochonToken !== "")
&& (this.state.polochonToken === "")) {
this.setState({
polochonToken: nextProps.polochonToken,
polochonUrl: nextProps.polochonUrl,
});
}
}
render() { render() {
return ( return (
<div className="container"> <div className="container">
@ -31,35 +57,44 @@ class UserEdit extends React.Component {
<div className="col-md-6 col-md-offset-3 col-xs-12"> <div className="col-md-6 col-md-offset-3 col-xs-12">
<h2>Edit user</h2> <h2>Edit user</h2>
<hr /> <hr />
<form className="form-horizontal" onSubmit={(ev) => this.handleSubmit(ev)}>
<Form model="userStore" className="form-horizontal" onSubmit={(val) => this.handleSubmit(val)}>
<div className="form-group"> <div className="form-group">
<label className="control-label">Polochon URL</label> <label className="control-label">Polochon URL</label>
<Control.text model="userStore.polochonUrl" className="form-control" /> <input
className="form-control"
value={this.state.polochonUrl}
onChange={this.handleUrlInput}
ref="polochonUrl"
/>
</div> </div>
<div className="form-group"> <div className="form-group">
<label className="control-label">Polochon token</label> <label className="control-label">Polochon token</label>
<Control.text model="userStore.polochonToken" className="form-control"/> <input
className="form-control"
value={this.state.polochonToken}
onChange={this.handleTokenInput}
ref="polochonToken"
/>
</div> </div>
<hr /> <hr />
<div className="form-group"> <div className="form-group">
<label className="control-label">Password</label> <label className="control-label">Password</label>
<input autoComplete="off" className="form-control" ref="newPassword" type="password"/> <input type="password" autoComplete="off" ref="newPassword" className="form-control"/>
</div> </div>
<div className="form-group"> <div className="form-group">
<label className="control-label">Confirm Password</label> <label className="control-label">Confirm Password</label>
<input autoComplete="off" className="form-control" ref="newPasswordConfirm" type="password"/> <input type="password" autoComplete="off" ref="newPasswordConfirm" className="form-control"/>
</div> </div>
<div> <div>
<input className="btn btn-primary pull-right" type="submit" value="Update"/> <input type="submit" className="btn btn-primary pull-right" value="Update"/>
</div> </div>
</Form> </form>
</div> </div>
</div> </div>
</div> </div>
); );

View File

@ -5,7 +5,10 @@ import { bindActionCreators } from 'redux'
import { loginUser } from '../../actions/users' import { loginUser } from '../../actions/users'
function mapStateToProps(state) { function mapStateToProps(state) {
return { user: state.userStore }; return {
isLogged: state.userStore.get('isLogged'),
loading: state.userStore.get('loading'),
};
} }
const mapDispatchToProps = (dispatch) => const mapDispatchToProps = (dispatch) =>
bindActionCreators({ loginUser }, dispatch) bindActionCreators({ loginUser }, dispatch)
@ -16,7 +19,7 @@ class UserLoginForm extends React.Component {
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (!nextProps.user.isLogged) { if (!nextProps.isLogged) {
return return
} }
if (!nextProps.location.query.redirect) { if (!nextProps.location.query.redirect) {
@ -29,7 +32,7 @@ class UserLoginForm extends React.Component {
} }
handleSubmit(e) { handleSubmit(e) {
e.preventDefault(); e.preventDefault();
if (this.props.user.userLoading) { if (this.props.loading) {
return; return;
} }
const username = this.refs.username.value; const username = this.refs.username.value;
@ -57,12 +60,12 @@ class UserLoginForm extends React.Component {
<p></p> <p></p>
</div> </div>
<div> <div>
{this.props.user.userLoading && {this.props.loading &&
<button className="btn btn-primary pull-right"> <button className="btn btn-primary pull-right">
<i className="fa fa-spinner fa-spin"></i> <i className="fa fa-spinner fa-spin"></i>
</button> </button>
} }
{this.props.user.userLoading || {this.props.loading ||
<input className="btn btn-primary pull-right" type="submit" value="Log in"/> <input className="btn btn-primary pull-right" type="submit" value="Log in"/>
} }
<br/> <br/>

View File

@ -1,46 +1,45 @@
import { OrderedMap, Map, fromJS } from 'immutable'
import jwtDecode from 'jwt-decode' import jwtDecode from 'jwt-decode'
import Cookies from 'universal-cookie' import Cookies from 'universal-cookie'
const defaultState = { const defaultState = Map({
userLoading: false, loading: false,
username: "", username: "",
isAdmin: false, isAdmin: false,
isLogged: false, isLogged: false,
polochonToken: "", polochonToken: "",
polochonUrl: "", polochonUrl: "",
}; });
export default function userStore(state = defaultState, action) { export default function userStore(state = defaultState, action) {
switch (action.type) { switch (action.type) {
case 'USER_LOGIN_PENDING': case 'USER_LOGIN_PENDING':
return Object.assign({}, state, { return state.set('loading', true);
userLoading: true,
})
case 'USER_LOGIN_FULFILLED': case 'USER_LOGIN_FULFILLED':
if (action.payload.response.status === "error") { if (action.payload.response.status === "error") {
return logoutUser(state) return logoutUser()
} }
return updateFromToken(state, action.payload.response.data.token) return updateFromToken(state, action.payload.response.data.token)
case 'USER_SET_TOKEN': case 'USER_SET_TOKEN':
return updateFromToken(state, action.payload.token) return updateFromToken(state, action.payload.token)
case 'USER_LOGOUT': case 'USER_LOGOUT':
return logoutUser(state) return logoutUser()
case 'GET_USER_FULFILLED': case 'GET_USER_FULFILLED':
return Object.assign({}, state, { return state.merge(Map({
polochonToken: action.payload.response.data.token, polochonToken: action.payload.response.data.token,
polochonUrl: action.payload.response.data.url, polochonUrl: action.payload.response.data.url,
}) }))
default: default:
return state; return state;
} }
} }
function logoutUser(state) { function logoutUser() {
localStorage.removeItem('token'); localStorage.removeItem('token');
const cookies = new Cookies(); const cookies = new Cookies();
cookies.remove('token'); cookies.remove('token');
return defaultState
return Object.assign({}, state, defaultState)
} }
function updateFromToken(state, token) { function updateFromToken(state, token) {
@ -50,10 +49,10 @@ function updateFromToken(state, token) {
const cookies = new Cookies(); const cookies = new Cookies();
cookies.set('token', token); cookies.set('token', token);
return Object.assign({}, state, { return state.merge(Map({
userLoading: false, userLoading: false,
isLogged: true, isLogged: true,
isAdmin: decodedToken.isAdmin, isAdmin: decodedToken.isAdmin,
username: decodedToken.username, username: decodedToken.username,
}) }))
} }