Add settings page.
authorAlexandre Segura <mex.zktk@gmail.com>
Mon, 19 Jun 2017 17:56:41 +0200
changeset 53 d8588379529e
parent 52 96f8a4a59bd9
child 54 fad489be9c77
Add settings page.
client/src/APIClient.js
client/src/actions/userActions.js
client/src/components/Navbar.js
client/src/components/Settings.js
client/src/constants/actionTypes.js
client/src/index.js
client/src/reducers/authReducer.js
client/src/sagas/index.js
src/irinotes/settings.py
--- a/client/src/APIClient.js	Mon Jun 19 15:36:52 2017 +0200
+++ b/client/src/APIClient.js	Mon Jun 19 17:56:41 2017 +0200
@@ -31,8 +31,7 @@
 
     var headers = new Headers(),
         token = localStorage.getItem('token') || '';
-    headers.append("Authorization", "Bearer " + token);
-    headers.append("Content-Type", "application/json");
+    headers.append("Authorization", "JWT " + token);
 
     return this.createRequest(method, uri, data, headers);
   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/actions/userActions.js	Mon Jun 19 17:56:41 2017 +0200
@@ -0,0 +1,10 @@
+import * as types from '../constants/actionTypes';
+
+export const updateSettings = (username, firstname, lastname) => {
+  return {
+    type: types.USER_UPDATE_SETTINGS_ASYNC,
+    username,
+    firstname,
+    lastname
+  };
+}
--- a/client/src/components/Navbar.js	Mon Jun 19 15:36:52 2017 +0200
+++ b/client/src/components/Navbar.js	Mon Jun 19 17:56:41 2017 +0200
@@ -1,3 +1,4 @@
+
 import PropTypes from 'prop-types';
 import React, { Component } from 'react';
 import { connect } from 'react-redux';
@@ -23,6 +24,11 @@
     this.props.history.push('/login');
   }
 
+  onClickSettings = (e) => {
+    e.preventDefault();
+    this.props.history.push('/settings');
+  }
+
   onClickLogout = (e) => {
     e.preventDefault();
     this.props.authActions.logout();
@@ -33,7 +39,7 @@
     if (this.props.currentUser) {
       return (
         <NavDropdown title={ this.props.currentUser.username } id="user-dropdown">
-          <MenuItem>Settings</MenuItem>
+          <MenuItem onClick={this.onClickSettings}>Settings</MenuItem>
           <MenuItem onClick={this.onClickLogout}>Logout</MenuItem>
         </NavDropdown>
       );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/Settings.js	Mon Jun 19 17:56:41 2017 +0200
@@ -0,0 +1,71 @@
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import { Grid, Row, Col, Button, FormGroup, ControlLabel, FormControl } from 'react-bootstrap';
+import '../App.css';
+import Navbar from './Navbar';
+import * as userActions from '../actions/userActions';
+
+class Settings extends Component {
+
+  updateSettings = () => {
+    const username = this.props.currentUser.username;
+    const firstname = this.firstname.value;
+    const lastname = this.lastname.value;
+
+    this.props.userActions.updateSettings(username, firstname, lastname);
+  }
+
+  render() {
+
+    const firstname = this.props.currentUser ? this.props.currentUser.first_name : '';
+    const lastname = this.props.currentUser ? this.props.currentUser.last_name : '';
+
+    return (
+      <div>
+        <Navbar history={this.props.history} />
+        <Grid fluid>
+          <Row>
+            <Col md={6} mdOffset={3}>
+              <form>
+                <FormGroup>
+                  <ControlLabel>First name</ControlLabel>
+                  <FormControl
+                    name="firstname"
+                    defaultValue={ firstname }
+                    placeholder="John"
+                    inputRef={ ref => { this.firstname = ref; } }
+                  />
+                </FormGroup>
+                <FormGroup>
+                  <ControlLabel>Last name</ControlLabel>
+                  <FormControl
+                    name="lastname"
+                    defaultValue={ lastname }
+                    placeholder="Doe"
+                    inputRef={ ref => { this.lastname = ref; } }
+                  />
+                </FormGroup>
+              </form>
+              <Button block bsStyle="success" onClick={this.updateSettings}>Save settings</Button>
+            </Col>
+          </Row>
+        </Grid>
+      </div>
+    );
+  }
+}
+
+function mapStateToProps(state, props) {
+  return {
+    currentUser: state.get('currentUser'),
+  };
+}
+
+function mapDispatchToProps(dispatch) {
+  return {
+    userActions: bindActionCreators(userActions, dispatch)
+  }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Settings);
--- a/client/src/constants/actionTypes.js	Mon Jun 19 15:36:52 2017 +0200
+++ b/client/src/constants/actionTypes.js	Mon Jun 19 17:56:41 2017 +0200
@@ -17,3 +17,6 @@
 export const AUTH_STORE_TOKEN_ASYNC = 'AUTH_STORE_TOKEN_ASYNC';
 export const AUTH_STORE_TOKEN = 'AUTH_STORE_TOKEN';
 export const AUTH_LOGOUT = 'AUTH_LOGOUT';
+
+export const USER_UPDATE_SETTINGS_ASYNC = 'USER_UPDATE_SETTINGS_ASYNC';
+export const USER_UPDATE_SETTINGS = 'USER_UPDATE_SETTINGS'
--- a/client/src/index.js	Mon Jun 19 15:36:52 2017 +0200
+++ b/client/src/index.js	Mon Jun 19 17:56:41 2017 +0200
@@ -9,6 +9,7 @@
 import Sessions from './components/Sessions';
 import Session from './components/Session';
 import Login from './components/Login';
+import Settings from './components/Settings';
 import './index.css';
 import registerServiceWorker from './registerServiceWorker';
 import configureStore from './store/configureStore';
@@ -20,6 +21,7 @@
   <Provider store={store}>
     <ConnectedRouter history={history}>
       <div>
+        <Route exact path="/settings" component={Settings} />
         <Route exact path="/sessions/:id" component={Session} />
         <Route exact path="/sessions" component={Sessions} />
         <Route exact path="/login" component={Login} />
--- a/client/src/reducers/authReducer.js	Mon Jun 19 15:36:52 2017 +0200
+++ b/client/src/reducers/authReducer.js	Mon Jun 19 17:56:41 2017 +0200
@@ -14,6 +14,11 @@
       return null;
     case types.AUTH_LOGIN_SUCCESS:
       return action.user;
+    case types.USER_UPDATE_SETTINGS:
+      state.first_name = action.firstname;
+      state.last_name = action.lastname;
+      localStorage.setItem('currentUser', JSON.stringify(state));
+      return state;
     default:
       return state;
   }
--- a/client/src/sagas/index.js	Mon Jun 19 15:36:52 2017 +0200
+++ b/client/src/sagas/index.js	Mon Jun 19 17:56:41 2017 +0200
@@ -137,6 +137,22 @@
   }
 }
 
+function* watchUpdateSettings() {
+  while (true) {
+    const { username, firstname, lastname } = yield take(types.USER_UPDATE_SETTINGS_ASYNC);
+    try {
+      yield client.put('/api/auth/user/', {
+        username,
+        first_name: firstname,
+        last_name: lastname
+      });
+      yield put({ type: types.USER_UPDATE_SETTINGS, firstname, lastname });
+    } catch (e) {
+
+    }
+  }
+}
+
 // ---
 
 export default function* rootSaga() {
@@ -149,5 +165,6 @@
     watchLoginSubmit(),
     watchLoginRequest(),
     watchStoreToken(),
+    watchUpdateSettings(),
   ])
 }
--- a/src/irinotes/settings.py	Mon Jun 19 15:36:52 2017 +0200
+++ b/src/irinotes/settings.py	Mon Jun 19 17:56:41 2017 +0200
@@ -234,3 +234,4 @@
 CORS_ORIGIN_ALLOW_ALL = True
 CORS_URLS_REGEX = r'^/api/.*$'
 
+