From f5925e82d19460047d866ed2f62ec7a8ecb6808c Mon Sep 17 00:00:00 2001 From: lightertu Date: Fri, 2 Jun 2017 01:42:26 -0700 Subject: [PATCH 01/23] after login redirect to dashboard --- src/components/Login/Login.js | 234 ++++++++++-------- src/components/Login/TextInput.js | 2 - .../Login/modules/actions/fetchUserActions.js | 10 +- 3 files changed, 136 insertions(+), 110 deletions(-) diff --git a/src/components/Login/Login.js b/src/components/Login/Login.js index 0a891f0..8fb5773 100644 --- a/src/components/Login/Login.js +++ b/src/components/Login/Login.js @@ -1,25 +1,25 @@ import React, { Component } from 'react' -import { withRouter } from 'react-router'; -import {Input, Button, Form, Header, Card , Menu, Segment} from 'semantic-ui-react' -import axios from 'axios'; -import TextInput from './TextInput'; +import { withRouter } from 'react-router' +import { Input, Button, Form, Header, Card, Menu, Segment } from 'semantic-ui-react' +import axios from 'axios' +import TextInput from './TextInput' -function ErrorMessage(props) { +function ErrorMessage (props) { let wrapperStyles = { justifyContent: 'center', - margin: "auto", - marginBottom: "1em", - animation: "shake 150ms ease-in-out" + margin: 'auto', + marginBottom: '1em', + animation: 'shake 150ms ease-in-out' } let paraStyles = { - backgroundColor: "#FB4F4F", - color: "white", - margin: 0, - padding: "0.5em 1em", - fontSize: "0.8em", - fontFamily: 'arial', - userSelect: "none" + backgroundColor: '#FB4F4F', + color: 'white', + margin: 0, + padding: '0.5em 1em', + fontSize: '0.8em', + fontFamily: 'arial', + userSelect: 'none' } return ( @@ -32,118 +32,125 @@ function ErrorMessage(props) { } class Login extends Component { - constructor(props) { - super(props); + constructor (props) { + super(props) this.state = { - email: '', - password: '', - passwordConfirm: '', - login: true, - activeItem: 'Login', + email: '', + password: '', + passwordConfirm: '', + login: true, + activeItem: 'Login', locks: [true, true, true, true, true] - }; + } - this.handleSubmit = this.handleSubmit.bind(this); - this.handleItemClick= this.handleItemClick.bind(this); - this.login = this.login.bind(this); - this._changeEmail = this._changeEmail.bind(this); - this._changePassword = this._changePassword.bind(this); - this._changePasswordConfirm = this._changePasswordConfirm.bind(this); - this._errorMessage = this._errorMessage.bind(this); - this._errorVisible = this._errorVisible.bind(this); + this.handleSubmit = this.handleSubmit.bind(this) + this.handleItemClick = this.handleItemClick.bind(this) + this.login = this.login.bind(this) + this._changeEmail = this._changeEmail.bind(this) + this._changePassword = this._changePassword.bind(this) + this._changePasswordConfirm = this._changePasswordConfirm.bind(this) + this._errorMessage = this._errorMessage.bind(this) + this._errorVisible = this._errorVisible.bind(this) this.passwordConfirmValidate = this.passwordConfirmValidate.bind(this) - this._releaseLock = this._releaseLock.bind(this); - this._setLock = this._setLock.bind(this); + this._releaseLock = this._releaseLock.bind(this) + this._setLock = this._setLock.bind(this) } - handleItemClick(e, { name }) { - this.setState({ activeItem: name, error: false, email: '', password: '', passwordConfirm: '', locks: [true, true, true , true, true]}); - this.props.setErrorMessage(""); - this.props.setErrorDisplay(false); + handleItemClick (e, {name}) { + this.setState({ + activeItem: name, + error: false, + email: '', + password: '', + passwordConfirm: '', + locks: [true, true, true, true, true] + }) + this.props.setErrorMessage('') + this.props.setErrorDisplay(false) } - _changeEmail(event) { - this.setState({email: event.target.value}); + _changeEmail (event) { + this.setState({email: event.target.value}) } - _errorMessage(error){ - this.props.setErrorMessage(error); - } + _errorMessage (error) { + this.props.setErrorMessage(error) + } - _errorVisible(boolean){ - this.props.setErrorDisplay(boolean); - } + _errorVisible (boolean) { + this.props.setErrorDisplay(boolean) + } - _releaseLock(value) { - let locks = this.state.locks; - locks[value] = false; - this.setState({locks: locks}); - } + _releaseLock (value) { + let locks = this.state.locks + locks[value] = false + this.setState({locks: locks}) + } - _setLock(value) { - let locks = this.state.locks; - locks[value] = true; - this.setState({locks: locks}); - } + _setLock (value) { + let locks = this.state.locks + locks[value] = true + this.setState({locks: locks}) + } - _changePassword(event) { - this.setState({password: event.target.value}); - } + _changePassword (event) { + this.setState({password: event.target.value}) + } - _changePasswordConfirm(event) { - this.setState({passwordConfirm: event.target.value}); - } + _changePasswordConfirm (event) { + this.setState({passwordConfirm: event.target.value}) + } - login(e) { // handles login - e.preventDefault(); - if(!this.state.locks[0] && !this.state.locks[1]) { - this.props.fetchUser(this.state.email, this.state.password); + login (e) { // handles login + e.preventDefault() + if (!this.state.locks[0] && !this.state.locks[1]) { + this.props.fetchUser(this.state.email, this.state.password) } - this.setState({email: '', password: ''}); - if(this.props.errorMessage == "") { - this.props.setErrorMessage("Both entries must be valid"); + this.setState({email: '', password: ''}) + if (this.props.errorMessage === '') { + this.props.setErrorMessage('Both entries must be valid') } - this.props.setErrorDisplay(true); + this.props.setErrorDisplay(true) } - handleSubmit(e) { // handles create user - e.preventDefault(); - if(!this.state.locks[2] && !this.state.locks[3] && !this.state.locks[4]) { - this.props.generateUser(this.state.email, this.state.password); + handleSubmit (e) { // handles create user + e.preventDefault() + if (!this.state.locks[2] && !this.state.locks[3] && !this.state.locks[4]) { + this.props.generateUser(this.state.email, this.state.password) } else { - this.setState({email: '', password: '', passwordConfirm: ''}); - if(this.props.errorMessage == "") { - this.props.setErrorMessage("All entries must be valid"); + this.setState({email: '', password: '', passwordConfirm: ''}) + if (this.props.errorMessage == '') { + this.props.setErrorMessage('All entries must be valid') + } + this.props.setErrorDisplay(true) } - this.props.setErrorDisplay(true); - } } - validateEmail(value) { + validateEmail (value) { // regex from http://stackoverflow.com/questions/46155/validate-email-address-in-javascript - let re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - return re.test(value); + let re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + return re.test(value) } - commonValidate(value) { - return true; + commonValidate (value) { + return true } - passwordConfirmValidate(value) { - return value === this.state.password; + passwordConfirmValidate (value) { + return value === this.state.password } - loginSuccess() { - this.props.router.push("/dashboard") + loginSuccess () { + this.props.router.push('/dashboard') } - render() { + render () { // response is the response from the server, // state is the state of user generation - const { response, state, loginState, login, auth, user, errorMessage, errorDisplay } = this.props + const {response, state, loginState, login, auth, user, errorMessage, errorDisplay} = this.props const cardStyle = { - marginTop:'200px', + marginTop: '200px', padding: 0, zIndex: 3 } @@ -154,24 +161,34 @@ class Login extends Component { marginBottom: 40 } - const { activeItem } = this.state + const {activeItem} = this.state - let loading = (); - if(state == "generating user") { - loading = (); + let loading = () + if (state === 'generating user') { + loading = () } console.log(errorMessage, errorDisplay) return ( -
- - - - - +
+ + + + + {(activeItem === 'Login') ? ( - +
- {errorDisplay ? : null} + {errorDisplay ? + : null} ) : ( - + - {errorDisplay ? : null} + {errorDisplay ? : null} - { @@ -34,16 +36,18 @@ let fetchUser = (dispatch) => { setAuthorizationToken(token); dispatch(setCurrentUser(token)); + browserHistory.push("/dashboard") + dispatch({ type: SET_ERROR_MESSAGE, message: data.message }); + + }) .catch((error) => { dispatch(fetchUserFailure(error, payload)); - console.log(error.response.data.error) - - + console.log(error) dispatch({ type: SET_ERROR_MESSAGE, message: error.response.data.error From 62e157433358b1942eaf57f9255f6677f1648ef9 Mon Sep 17 00:00:00 2001 From: lightertu Date: Fri, 2 Jun 2017 14:11:24 -0700 Subject: [PATCH 02/23] authentication global reducer --- package.json | 4 +- src/components/Login/Login.js | 252 +++++++++--------- src/main.js | 9 +- src/routes/Auth/components/AuthView.js | 59 ++++ src/routes/Auth/constants.js | 5 + src/routes/Auth/containers/authContainer.js | 38 +++ src/routes/Auth/index.js | 24 ++ src/routes/Auth/modules/actions/index.js | 16 ++ .../actionHandlers/authActionsHandlers.js | 12 + .../actionHandlers/errorActionsHandlers.js | 35 +++ .../actionHandlers/fetchUserActionsHandler.js | 35 +++ .../generateUserActionsHandlers.js | 28 ++ .../modules/reducers/actionHandlers/index.js | 12 + src/routes/Auth/modules/reducers/index.js | 16 ++ src/routes/Auth/modules/reducers/reducer.js | 21 ++ src/routes/Auth/modules/utils/index.js | 19 ++ .../Login/modules/actions/fetchUserActions.js | 1 - .../modules/actions/generateUserActions.js | 4 +- .../actionHandlers/fetchUserActionsHandler.js | 2 +- .../actionHandlers/fetchUserActionsHandler.js | 2 +- src/routes/index.js | 63 +++-- src/store/authentication.js | 15 ++ src/store/createStore.js | 11 +- src/store/reducers.js | 5 + 24 files changed, 530 insertions(+), 158 deletions(-) create mode 100644 src/routes/Auth/components/AuthView.js create mode 100644 src/routes/Auth/constants.js create mode 100644 src/routes/Auth/containers/authContainer.js create mode 100644 src/routes/Auth/index.js create mode 100644 src/routes/Auth/modules/actions/index.js create mode 100644 src/routes/Auth/modules/reducers/actionHandlers/authActionsHandlers.js create mode 100644 src/routes/Auth/modules/reducers/actionHandlers/errorActionsHandlers.js create mode 100644 src/routes/Auth/modules/reducers/actionHandlers/fetchUserActionsHandler.js create mode 100644 src/routes/Auth/modules/reducers/actionHandlers/generateUserActionsHandlers.js create mode 100644 src/routes/Auth/modules/reducers/actionHandlers/index.js create mode 100644 src/routes/Auth/modules/reducers/index.js create mode 100644 src/routes/Auth/modules/reducers/reducer.js create mode 100644 src/routes/Auth/modules/utils/index.js create mode 100644 src/store/authentication.js diff --git a/package.json b/package.json index 0b26bc8..e9a442d 100644 --- a/package.json +++ b/package.json @@ -119,11 +119,13 @@ "react-dom": "^15.5.4", "react-redux": "^5.0.1", "react-router": "^3.0.0", + "react-router-redux": "^4.0.8", "react-sticky": "^5.0.8", "react-stickynode": "^1.2.1", "react-tap-event-plugin": "^2.0.1", "react-transition-group": "^1.1.1", "redux": "^3.6.0", + "redux-auth-wrapper": "^1.1.0", "redux-thunk": "^2.0.0", "rimraf": "^2.5.4", "sass-loader": "^4.0.0", @@ -132,9 +134,9 @@ "semantic-ui-react": "^0.68", "style-loader": "^0.13.1", "url-loader": "^0.5.6", + "validator": "^7.0.0", "webpack": "^1.15.0", "webpack-hot-middleware": "^2.18.0", - "validator": "^7.0.0", "yargs": "^6.3.0" }, "devDependencies": { diff --git a/src/components/Login/Login.js b/src/components/Login/Login.js index 8fb5773..6a0d9e1 100644 --- a/src/components/Login/Login.js +++ b/src/components/Login/Login.js @@ -168,6 +168,132 @@ class Login extends Component { loading = () } console.log(errorMessage, errorDisplay) + + const loginForm = + + + {errorDisplay ? : null} + + + + + + + const signupForm = + +
+ {errorDisplay ? : null} + + + + {loading} + +
+ return (
@@ -177,131 +303,7 @@ class Login extends Component { - {(activeItem === 'Login') ? ( - -
- {errorDisplay ? - : null} - - - - -
- ) : ( - -
- {errorDisplay ? : null} - - - - {loading} - -
- )} + {(activeItem === 'Login') ? (loginForm ) : ( signupForm )}
) diff --git a/src/main.js b/src/main.js index ad6de02..2b4ec7a 100644 --- a/src/main.js +++ b/src/main.js @@ -5,6 +5,8 @@ import createStore from './store/createStore' import injectTapEventPlugin from 'react-tap-event-plugin' import AppContainer from './containers/AppContainer' import setAuthorizationToken from './components/utils/setAuthorizationToken' +import { applyMiddleware, compose } from 'redux' + // imports for web auth import jwt from 'jsonwebtoken' @@ -14,16 +16,19 @@ import { setCurrentUser } from './routes/Login/modules/actions/authActions' // Store Instantiation // ======================================================== const initialState = window.__INITIAL_STATE__ + + const store = createStore(initialState) // set auth token +/* if (localStorage.jwtToken) { setAuthorizationToken(localStorage.jwtToken) store.dispatch(setCurrentUser(jwt.decode(localStorage.jwtToken))) - - } +*/ + // ======================================================== // Render Setup // ======================================================== diff --git a/src/routes/Auth/components/AuthView.js b/src/routes/Auth/components/AuthView.js new file mode 100644 index 0000000..d109bb5 --- /dev/null +++ b/src/routes/Auth/components/AuthView.js @@ -0,0 +1,59 @@ +import React, { Component, PropTypes } from 'react' +import { routerActions } from 'react-router-redux' +import { connect } from 'react-redux' + +import { login } from '../modules/actions/' + +function select(state, ownProps) { + const isAuthenticated = state.name || false + const redirect = ownProps.location.query.redirect || '/' + return { + isAuthenticated, + redirect + } +} + +class LoginContainer extends Component { + + static propTypes = { + login: PropTypes.func.isRequired, + replace: PropTypes.func.isRequired + }; + + componentWillMount() { + const { isAuthenticated, replace, redirect } = this.props + if (isAuthenticated) { + replace(redirect) + } + } + + componentWillReceiveProps(nextProps) { + const { isAuthenticated, replace, redirect } = nextProps + const { isAuthenticated: wasAuthenticated } = this.props + + if (!wasAuthenticated && isAuthenticated) { + replace(redirect) + } + } + + onClick = (e) => { + e.preventDefault() + this.props.login({ + name: this.refs.name.value + }) + }; + + render() { + return ( +
+

Enter your name

+ +
+ +
+ ) + } + +} + +export default connect(select, { login, replace: routerActions.replace })(LoginContainer) \ No newline at end of file diff --git a/src/routes/Auth/constants.js b/src/routes/Auth/constants.js new file mode 100644 index 0000000..d6d2293 --- /dev/null +++ b/src/routes/Auth/constants.js @@ -0,0 +1,5 @@ +/** + * Created by rui on 6/2/17. + */ +export const USER_LOGGED_IN = 'USER_LOGGED_IN' +export const USER_LOGGED_OUT = 'USER_LOGGED_OUT' diff --git a/src/routes/Auth/containers/authContainer.js b/src/routes/Auth/containers/authContainer.js new file mode 100644 index 0000000..ae9e6f0 --- /dev/null +++ b/src/routes/Auth/containers/authContainer.js @@ -0,0 +1,38 @@ +import { connect } from 'react-redux' + +/* This is a container component. Notice it does not contain any JSX, + nor does it import React. This component is **only** responsible for + wiring in the actions and state necessary to render a presentational + component - in this case, the counter: */ + +import authView from '../components/AuthView' +//import * as Actions from '../modules/actions' + +const mapDispatchToProps = (dispatch) => ({ + /* + generateUser: Actions.generateUserActions.generateUser(dispatch), + fetchUser: Actions.fetchUserActions.fetchUser(dispatch), + logout: Actions.fetchUserActions.logout(dispatch), + setErrorDisplay: Actions.errorActions.setErrorDisplay(dispatch), + setErrorMessage: Actions.errorActions.setErrorMessage(dispatch), + setErrorColor: Actions.errorActions.setErrorColor(dispatch) + */ +}) + +const mapStateToProps = (state, ownProps) => { + return { + /* + state: state.login.state, + response: state.login.response, + loginState: state.login.loginState, + login: state.login.login, + user: state.login.user, + auth: state.login.isAuthenticated, + errorDisplay: state.login.errorDisplay, + errorMessage: state.login.errorMessage, + errorColor: state.login.errorColor + */ + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(authView) diff --git a/src/routes/Auth/index.js b/src/routes/Auth/index.js new file mode 100644 index 0000000..ebdd6b3 --- /dev/null +++ b/src/routes/Auth/index.js @@ -0,0 +1,24 @@ +import {injectReducer} from '../../store/reducers' + +export default (store) => ({ + path: 'auth', + /* Async getComponent is only invoked when route matches */ + getComponent (nextState, cb) { + /* Webpack - use 'require.ensure' to create a split point + and embed an async module loader (jsonp) when bundling */ + require.ensure([], (require) => { + /* Webpack - use require callback to define + dependencies for bundling */ + const Login = require('./containers/authContainer').default; + //const reducer = require('./modules/reducers').default; + + /* Add the reducer to the store on key 'auth' */ + //injectReducer(store, {key: 'auth', reducer}); + + /* Return getComponent */ + cb(null, Login) + + /* Webpack named bundle */ + }, 'auth') + } +}); diff --git a/src/routes/Auth/modules/actions/index.js b/src/routes/Auth/modules/actions/index.js new file mode 100644 index 0000000..ddfbe82 --- /dev/null +++ b/src/routes/Auth/modules/actions/index.js @@ -0,0 +1,16 @@ +import * as constants from '../../constants' + +export function login(data) { + localStorage.setItem('token', JSON.stringify(data.name)) + return { + type: constants.USER_LOGGED_IN, + payload: data + } +} + +export function logout() { + localStorage.removeItem('token') + return { + type: constants.USER_LOGGED_OUT + } +} \ No newline at end of file diff --git a/src/routes/Auth/modules/reducers/actionHandlers/authActionsHandlers.js b/src/routes/Auth/modules/reducers/actionHandlers/authActionsHandlers.js new file mode 100644 index 0000000..659607a --- /dev/null +++ b/src/routes/Auth/modules/reducers/actionHandlers/authActionsHandlers.js @@ -0,0 +1,12 @@ +import isEmpty from 'lodash/isEmpty'; + +let handleSetCurrentUser = (state, user) => { + return Object.assign({}, state, { + isAuthenticated: !isEmpty(user), + user: user + }); +}; + +export { + handleSetCurrentUser +} \ No newline at end of file diff --git a/src/routes/Auth/modules/reducers/actionHandlers/errorActionsHandlers.js b/src/routes/Auth/modules/reducers/actionHandlers/errorActionsHandlers.js new file mode 100644 index 0000000..375841e --- /dev/null +++ b/src/routes/Auth/modules/reducers/actionHandlers/errorActionsHandlers.js @@ -0,0 +1,35 @@ +let handleErrorDisplay = (state, bool) => { + return state; +}; + +let handleErrorTrue = (state) => { + return Object.assign({}, state, { + errorDisplay: true + }); +}; + +let handleErrorFalse = (state) => { + return Object.assign({}, state, { + errorDisplay: false + }); +} + +let handleErrorMessage = (state, payload) => { + return Object.assign({}, state, { + errorMessage: payload + }); +}; + +let handleErrorColor = (state, payload) => { + return Object.assign({}, state, { + color: payload + }); +}; + +export { + handleErrorTrue, + handleErrorFalse, + handleErrorMessage, + handleErrorDisplay, + handleErrorColor +} diff --git a/src/routes/Auth/modules/reducers/actionHandlers/fetchUserActionsHandler.js b/src/routes/Auth/modules/reducers/actionHandlers/fetchUserActionsHandler.js new file mode 100644 index 0000000..d610d26 --- /dev/null +++ b/src/routes/Auth/modules/reducers/actionHandlers/fetchUserActionsHandler.js @@ -0,0 +1,35 @@ +let handleFetchUser = (state, payload) => { + return Object.assign({}, state, { + loginState: "fetching user", + response: {}, + login: {}, + state: "waiting" + }); +}; +let handleFetchUserSuccess = (state, payload) => { + if(!payload.data.message) { + payload.data.message = "logged in" + } + state.login = payload.data; + state.Loginstate = "fetch success" + return Object.assign({}, state, { + login: payload.data, + loginState: "fetching success", + response: {}, + state: "waiting" + }); +}; +let handleFetchUserFailure = (state, payload) => { + state.login = payload.data; + state.loginState = "generation failure" + return Object.assign({}, state, { + login: {}, + loginState: "fetching failure" + }); +}; + +export { + handleFetchUser, + handleFetchUserSuccess, + handleFetchUserFailure +} diff --git a/src/routes/Auth/modules/reducers/actionHandlers/generateUserActionsHandlers.js b/src/routes/Auth/modules/reducers/actionHandlers/generateUserActionsHandlers.js new file mode 100644 index 0000000..f660331 --- /dev/null +++ b/src/routes/Auth/modules/reducers/actionHandlers/generateUserActionsHandlers.js @@ -0,0 +1,28 @@ +let handleGenerateUser = (state, payload) => { + return Object.assign({}, state, { + state: "generating user", + response: {} + }); +}; +let handleGenerateUserSuccess = (state, payload) => { + state.response = payload.data; + state.state = "generation success" + return Object.assign({}, state, { + response: payload.data, + state: "generation success" + }); +}; +let handleGenerateUserFailure = (state, payload) => { + state.response = payload.data; + state.state = "generation failure" + return Object.assign({}, state, { + response: {}, + state: "generation failure" + }); +}; + +export { + handleGenerateUser, + handleGenerateUserSuccess, + handleGenerateUserFailure +} diff --git a/src/routes/Auth/modules/reducers/actionHandlers/index.js b/src/routes/Auth/modules/reducers/actionHandlers/index.js new file mode 100644 index 0000000..eabbaa7 --- /dev/null +++ b/src/routes/Auth/modules/reducers/actionHandlers/index.js @@ -0,0 +1,12 @@ +import * as fetchUserActionsHandlers from "./fetchUserActionsHandler" +import * as generateUserActionsHandlers from "./generateUserActionsHandlers" +import * as authActionsHandlers from "./authActionsHandlers" +import * as errorActionsHandlers from "./errorActionsHandlers" + + +export { + generateUserActionsHandlers, + fetchUserActionsHandlers, + authActionsHandlers, + errorActionsHandlers +} \ No newline at end of file diff --git a/src/routes/Auth/modules/reducers/index.js b/src/routes/Auth/modules/reducers/index.js new file mode 100644 index 0000000..1f32048 --- /dev/null +++ b/src/routes/Auth/modules/reducers/index.js @@ -0,0 +1,16 @@ +import * as constants from '../../constants' + +const initialState = { + isAuthenticated: false, + jwtToken: "" +} + +export default function userUpdate (state = initialState, {type, payload}) { + if (type === constants.USER_LOGGED_IN) { + return payload + } + else if (type === constants.USER_LOGGED_OUT) { + return {} + } + return state +} \ No newline at end of file diff --git a/src/routes/Auth/modules/reducers/reducer.js b/src/routes/Auth/modules/reducers/reducer.js new file mode 100644 index 0000000..dd0b308 --- /dev/null +++ b/src/routes/Auth/modules/reducers/reducer.js @@ -0,0 +1,21 @@ +/** + * Created by Joseph on 5/11/17. + */ +import * as Actions from "../actions" +import * as ActionsHandlers from "./actionHandlers" + +const initialState = { + response: { success: "", message: ""}, + state: "waiting", + login: { success: "", message: ""}, + loginState: "waiting", + isAuthenticated: false, + user: {}, + errorDisplay: false, + errorMessage: "", + errorColor: "" +}; + +export default function activityReducer (state = initialState, action) { + return state; +}; diff --git a/src/routes/Auth/modules/utils/index.js b/src/routes/Auth/modules/utils/index.js new file mode 100644 index 0000000..f8bdf9f --- /dev/null +++ b/src/routes/Auth/modules/utils/index.js @@ -0,0 +1,19 @@ +/** + * Created by rui on 6/2/17. + */ + +import React from 'react'; + +export function checkHttpStatus(response) { + if (response.status >= 200 && response.status < 300) { + return response + } else { + let error = new Error(response.statusText) + error.response = response + throw error + } +} + +export function parseJSON(response) { + return response.json() +} \ No newline at end of file diff --git a/src/routes/Login/modules/actions/fetchUserActions.js b/src/routes/Login/modules/actions/fetchUserActions.js index 0b5b7b1..6b0cf73 100644 --- a/src/routes/Login/modules/actions/fetchUserActions.js +++ b/src/routes/Login/modules/actions/fetchUserActions.js @@ -1,7 +1,6 @@ // created by Joseph 5/11/17 import axios from "axios"; -import jwt from 'jsonwebtoken'; import setAuthorizationToken from '../../../../components/utils/setAuthorizationToken'; const SERVER_URL = "http://localhost:3000"; import { setCurrentUser } from "./authActions" diff --git a/src/routes/Login/modules/actions/generateUserActions.js b/src/routes/Login/modules/actions/generateUserActions.js index ae50f66..9a0be60 100644 --- a/src/routes/Login/modules/actions/generateUserActions.js +++ b/src/routes/Login/modules/actions/generateUserActions.js @@ -2,6 +2,7 @@ import axios from "axios"; import { SET_ERROR_MESSAGE, SET_ERROR_TRUE } from "./errorActions" +import { browserHistory } from "react-router" const SERVER_URL = "http://localhost:3000"; export const GENERATE_USER = "GENERATE_USER"; @@ -34,9 +35,10 @@ let generateUser = (dispatch) => { dispatch({ type: SET_ERROR_MESSAGE, - message: "successfully created user "+email + message: "Sign up successful, now login" }); + browserHistory.push("/login"); }) .catch((error) => { dispatch(generateUserFailure(error, payload)); diff --git a/src/routes/Login/modules/reducers/actionHandlers/fetchUserActionsHandler.js b/src/routes/Login/modules/reducers/actionHandlers/fetchUserActionsHandler.js index 6c5e9c8..d610d26 100644 --- a/src/routes/Login/modules/reducers/actionHandlers/fetchUserActionsHandler.js +++ b/src/routes/Login/modules/reducers/actionHandlers/fetchUserActionsHandler.js @@ -1,6 +1,6 @@ let handleFetchUser = (state, payload) => { return Object.assign({}, state, { - loginsState: "fetching user", + loginState: "fetching user", response: {}, login: {}, state: "waiting" diff --git a/src/routes/Welcome/modules/reducers/actionHandlers/fetchUserActionsHandler.js b/src/routes/Welcome/modules/reducers/actionHandlers/fetchUserActionsHandler.js index 6c5e9c8..d610d26 100644 --- a/src/routes/Welcome/modules/reducers/actionHandlers/fetchUserActionsHandler.js +++ b/src/routes/Welcome/modules/reducers/actionHandlers/fetchUserActionsHandler.js @@ -1,6 +1,6 @@ let handleFetchUser = (state, payload) => { return Object.assign({}, state, { - loginsState: "fetching user", + loginState: "fetching user", response: {}, login: {}, state: "waiting" diff --git a/src/routes/index.js b/src/routes/index.js index ca0c984..d751f9e 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -6,38 +6,51 @@ import CounterRoute from './Counter' import WelcomeRoute from './Welcome' import Dashboard from './Dashboard' import Survey from './Survey' +import AuthRoute from './Auth' import PageNotFound from './PageNotFound' +import { createStore, combineReducers, applyMiddleware, compose } from 'redux' +import { Router, Route, IndexRoute, browserHistory } from 'react-router' +import { routerReducer, syncHistoryWithStore, routerActions, routerMiddleware } from 'react-router-redux' +import { UserAuthWrapper } from 'redux-auth-wrapper' +const UserIsAuthenticated = UserAuthWrapper({ + authSelector: state => state.user, + redirectAction: routerActions.replace, + wrapperDisplayName: 'UserIsAuthenticated' +}) + /* Note: Instead of using JSX, we recommend using react-router PlainRoute objects to build route definitions. */ - -export const createRoutes = (store) => ({ - path: '/', - - component: CoreLayout, - indexRoute: WelcomeRoute, - childRoutes: [ - CounterRoute(store), - ActivityRoute(store), - LoginRoute(store), - Dashboard(store), - Survey(store), - PageNotFound(store), - ] -}); - +export const createRoutes = (store) => { + const history = syncHistoryWithStore(browserHistory, store) + return { + path: '/', + history: history, + component: CoreLayout, + indexRoute: WelcomeRoute, + childRoutes: [ + CounterRoute(store), + ActivityRoute(store), + LoginRoute(store), + AuthRoute(store), + Dashboard(store), + Survey(store), + PageNotFound(store), + ] + } +} /* -getChildRoutes (location, cb) { - require.ensure([], (require) => { - cb(null, [ - // Remove imports! - require('./Counter').default(store) - ]) - }) -} -*/ + getChildRoutes (location, cb) { + require.ensure([], (require) => { + cb(null, [ + // Remove imports! + require('./Counter').default(store) + ]) + }) + } + */ /* Note: childRoutes can be chunked or otherwise loaded programmatically using getChildRoutes with the following signature: diff --git a/src/store/authentication.js b/src/store/authentication.js new file mode 100644 index 0000000..59a4b50 --- /dev/null +++ b/src/store/authentication.js @@ -0,0 +1,15 @@ +/** + * Created by rui on 6/2/17. + */ +import browserHistory from 'react-router/lib/browserHistory' + +// ------------------------------------ +// Specialized Action Creator +// ------------------------------------ + +// ------------------------------------ +// Reducer +// ------------------------------------ +import authenticationReducer from "../routes/Auth/modules/reducers" + +export default authenticationReducer \ No newline at end of file diff --git a/src/store/createStore.js b/src/store/createStore.js index 90baee8..2d7b223 100644 --- a/src/store/createStore.js +++ b/src/store/createStore.js @@ -3,6 +3,8 @@ import thunk from 'redux-thunk' import {browserHistory} from 'react-router' import makeRootReducer from './reducers' import {updateLocation} from './location' +import { routerReducer, syncHistoryWithStore, routerActions, routerMiddleware } from 'react-router-redux' + import generateUsers from "../routes/Activity/modules/UserGenerator" @@ -15,7 +17,14 @@ export default (initialState = {}) => { // ====================================================== // Store Enhancers // ====================================================== - const enhancers = []; + + const routingMiddleware = routerMiddleware(browserHistory); + const routingEnhancer = compose( + // Middleware you want to use in development: + applyMiddleware(routingMiddleware), + ) + + const enhancers = [routingEnhancer]; let composeEnhancers = compose; diff --git a/src/store/reducers.js b/src/store/reducers.js index ebea21c..fa16fbd 100644 --- a/src/store/reducers.js +++ b/src/store/reducers.js @@ -1,9 +1,14 @@ import {combineReducers} from 'redux' import locationReducer from './location' +import authenticationReducer from './authentication' +import { routerReducer, syncHistoryWithStore, routerActions, routerMiddleware } from 'react-router-redux' + export const makeRootReducer = (asyncReducers) => { return combineReducers({ location: locationReducer, + authentication: authenticationReducer, + routing: routerReducer, ...asyncReducers }) }; From 028b0b12f4a488f16c957a37ba1176e0ff71adbf Mon Sep 17 00:00:00 2001 From: lightertu Date: Sat, 3 Jun 2017 20:44:14 -0700 Subject: [PATCH 03/23] authn redux actions done --- .eslintrc | 34 +++++++---- src/routes/Activity/index.js | 7 ++- src/routes/Auth/index.js | 7 +-- src/routes/Auth/modules/actions/index.js | 19 ++----- .../Auth/modules/actions/loginActions.js | 53 ++++++++++++++++++ .../Auth/modules/actions/logoutActions.js | 27 +++++++++ .../actionHandlers/authActionsHandlers.js | 12 ---- .../actionHandlers/errorActionsHandlers.js | 35 ------------ .../actionHandlers/fetchUserActionsHandler.js | 35 ------------ .../generateUserActionsHandlers.js | 28 ---------- .../modules/reducers/actionHandlers/index.js | 10 +--- .../actionHandlers/loginActionsHandlers.js | 14 +++++ src/routes/Auth/modules/reducers/index.js | 23 +++++--- src/routes/Auth/modules/reducers/reducer.js | 42 +++++++------- src/routes/Counter/components/Counter.js | 23 -------- .../Counter/containers/CounterContainer.js | 39 ------------- src/routes/Counter/index.js | 24 -------- src/routes/Counter/modules/counter.js | 56 ------------------- src/routes/Dashboard/index.js | 4 +- src/routes/UserIsAuthenticated.js | 11 ++++ src/routes/index.js | 10 ---- src/store/authentication.js | 15 ----- .../actions/authenticationActions.js | 20 +++++++ src/store/authentication/actions/index.js | 7 +++ .../authenticationActionsHandlers.js | 13 +++++ .../reducer/actionHandlers/index.js | 6 ++ src/store/authentication/reducer/index.js | 23 ++++++++ src/store/reducers.js | 2 +- 28 files changed, 253 insertions(+), 346 deletions(-) create mode 100644 src/routes/Auth/modules/actions/loginActions.js create mode 100644 src/routes/Auth/modules/actions/logoutActions.js delete mode 100644 src/routes/Auth/modules/reducers/actionHandlers/authActionsHandlers.js delete mode 100644 src/routes/Auth/modules/reducers/actionHandlers/errorActionsHandlers.js delete mode 100644 src/routes/Auth/modules/reducers/actionHandlers/fetchUserActionsHandler.js delete mode 100644 src/routes/Auth/modules/reducers/actionHandlers/generateUserActionsHandlers.js create mode 100644 src/routes/Auth/modules/reducers/actionHandlers/loginActionsHandlers.js delete mode 100644 src/routes/Counter/components/Counter.js delete mode 100644 src/routes/Counter/containers/CounterContainer.js delete mode 100644 src/routes/Counter/index.js delete mode 100644 src/routes/Counter/modules/counter.js create mode 100644 src/routes/UserIsAuthenticated.js delete mode 100644 src/store/authentication.js create mode 100644 src/store/authentication/actions/authenticationActions.js create mode 100644 src/store/authentication/actions/index.js create mode 100644 src/store/authentication/reducer/actionHandlers/authenticationActionsHandlers.js create mode 100644 src/store/authentication/reducer/actionHandlers/index.js create mode 100644 src/store/authentication/reducer/index.js diff --git a/.eslintrc b/.eslintrc index dd726b6..8a052e6 100644 --- a/.eslintrc +++ b/.eslintrc @@ -10,22 +10,32 @@ "promise" ], "env": { - "browser" : true + "browser": true }, "globals": { - "__DEV__" : false, - "__TEST__" : false, - "__PROD__" : false, - "__COVERAGE__" : false + "__DEV__": false, + "__TEST__": false, + "__PROD__": false, + "__COVERAGE__": false }, "rules": { - "key-spacing" : 0, -// "jsx-quotes" : [0, "prefer-single"], - "jsx-quotes" : 0, - "max-len" : [2, 120, 2], + "key-spacing": 0, + // "jsx-quotes" : [0, "prefer-single"], + "jsx-quotes": 0, + "max-len": [ + 2, + 120, + 2 + ], // "object-curly-spacing" : [2, "always"], - "object-curly-spacing" : ["error", "never"], - "semi" : [2, "always"], - "indent" : 0 + "object-curly-spacing": [ + "error", + "never" + ], + "semi": [ + 2, + "always" + ], + "indent": 0 } } diff --git a/src/routes/Activity/index.js b/src/routes/Activity/index.js index bec0822..8aa0118 100644 --- a/src/routes/Activity/index.js +++ b/src/routes/Activity/index.js @@ -3,6 +3,7 @@ */ import {injectReducer} from '../../store/reducers' +import UserIsAuthenticated from "../UserIsAuthenticated" export default (store) => ({ path: 'activity', @@ -14,15 +15,15 @@ export default (store) => ({ require.ensure([], (require) => { /* Webpack - use require callback to define dependencies for bundling */ - const Groups = require('./containers/ActivityContainer').default; + const activity = require('./containers/ActivityContainer').default; + const securedActivity = UserIsAuthenticated(activity); /* Add the reducer to the store on key 'counter' */ - // injectReducer(store, {key: 'counter', reducer}) const reducer = require('./modules/reducer/reducer').default; injectReducer(store, {key: 'activity', reducer}); /* Return getComponent */ - cb(null, Groups) + cb(null, securedActivity) /* Webpack named bundle */ }, 'activity') diff --git a/src/routes/Auth/index.js b/src/routes/Auth/index.js index ebdd6b3..ba63a9b 100644 --- a/src/routes/Auth/index.js +++ b/src/routes/Auth/index.js @@ -10,10 +10,9 @@ export default (store) => ({ /* Webpack - use require callback to define dependencies for bundling */ const Login = require('./containers/authContainer').default; - //const reducer = require('./modules/reducers').default; - - /* Add the reducer to the store on key 'auth' */ - //injectReducer(store, {key: 'auth', reducer}); + const authReducer = require('./modules/reducers') + /* The reducer is merged with global reducer */ + injectReducer(store, {key: 'auth', authReducer}); /* Return getComponent */ cb(null, Login) diff --git a/src/routes/Auth/modules/actions/index.js b/src/routes/Auth/modules/actions/index.js index ddfbe82..085c705 100644 --- a/src/routes/Auth/modules/actions/index.js +++ b/src/routes/Auth/modules/actions/index.js @@ -1,16 +1,9 @@ -import * as constants from '../../constants' +import * as loginActions from "./loginActions" +import * as logoutActions from "./logoutActions" -export function login(data) { - localStorage.setItem('token', JSON.stringify(data.name)) - return { - type: constants.USER_LOGGED_IN, - payload: data - } +export { + loginActions, + logoutActions } -export function logout() { - localStorage.removeItem('token') - return { - type: constants.USER_LOGGED_OUT - } -} \ No newline at end of file + diff --git a/src/routes/Auth/modules/actions/loginActions.js b/src/routes/Auth/modules/actions/loginActions.js new file mode 100644 index 0000000..c971bf8 --- /dev/null +++ b/src/routes/Auth/modules/actions/loginActions.js @@ -0,0 +1,53 @@ +/** + * Created by rui on 6/2/17. + */ + +import axios from 'axios' +import { authenticationActions } from '../../../../store/authentication/actions' + +const SERVER_URL = 'http://localhost:3000' +export const LOGIN = 'LOGIN' + +let login = (dispatch) => { + return (email, password) => { + let payload = {email: email, password: password} + + /* first dispatch an action so we know that user is logging in*/ + dispatch({type: LOGIN, payload: null}) + + let url = SERVER_URL + '/api/auth/login' + axios.post(url, { + email: email, + password: password + }) + .then((response) => { + /* this is the jwt token */ + const token = response.data.token + + /* store token in the local storage*/ + localStorage.setItem('jwtToken', token) + + /* this will set the the authorization token in all axios requests. */ + axios.defaults.headers.common['Authorization'] = token; + + dispatch(loginSuccess(response)) + + /* dispatching this action to store the jwtToken in the global redux store */ + dispatch(authenticationActions.authenticationSuccess(token)) + }) + .catch((error) => { + dispatch(loginFailure(error, payload)) + }) + } +} + +/* user failure */ +export const LOGIN_FAILURE = 'LOGIN_FAILURE' +let loginFailure = (error, payload) => { + return {type: LOGIN_FAILURE, error: error, payload: payload} +} + +export const LOGIN_SUCCESS = 'LOGIN_FAILURE' +let loginSuccess = (error, payload) => { + return {type: LOGIN_SUCCESS, error: error, payload: payload} +} diff --git a/src/routes/Auth/modules/actions/logoutActions.js b/src/routes/Auth/modules/actions/logoutActions.js new file mode 100644 index 0000000..c3658d5 --- /dev/null +++ b/src/routes/Auth/modules/actions/logoutActions.js @@ -0,0 +1,27 @@ +/** + * Created by rui on 6/2/17. + */ + +import { authenticationActions } from "../../../../store/authentication/actions" +import { browserHistory } from 'react-router' +import axios from 'axios' + +export const LOGOUT = 'LOGOUT' +let logout = (dispatch) => { + return () => { + browserHistory.push("/"); + localstorage.removeitem('token') + + /* remove the axios token from the client side */ + delete axios.defaults.headers.common['Authorization']; + dispatch({type: LOGOUT, payload: null}) + + /* this action will be handled in the global authentication reducer, therefore we can + * remove the token from the store */ + dispatch(authenticationActions.unauthenticationSuccess(null)); + } +} + +export { + logout +} diff --git a/src/routes/Auth/modules/reducers/actionHandlers/authActionsHandlers.js b/src/routes/Auth/modules/reducers/actionHandlers/authActionsHandlers.js deleted file mode 100644 index 659607a..0000000 --- a/src/routes/Auth/modules/reducers/actionHandlers/authActionsHandlers.js +++ /dev/null @@ -1,12 +0,0 @@ -import isEmpty from 'lodash/isEmpty'; - -let handleSetCurrentUser = (state, user) => { - return Object.assign({}, state, { - isAuthenticated: !isEmpty(user), - user: user - }); -}; - -export { - handleSetCurrentUser -} \ No newline at end of file diff --git a/src/routes/Auth/modules/reducers/actionHandlers/errorActionsHandlers.js b/src/routes/Auth/modules/reducers/actionHandlers/errorActionsHandlers.js deleted file mode 100644 index 375841e..0000000 --- a/src/routes/Auth/modules/reducers/actionHandlers/errorActionsHandlers.js +++ /dev/null @@ -1,35 +0,0 @@ -let handleErrorDisplay = (state, bool) => { - return state; -}; - -let handleErrorTrue = (state) => { - return Object.assign({}, state, { - errorDisplay: true - }); -}; - -let handleErrorFalse = (state) => { - return Object.assign({}, state, { - errorDisplay: false - }); -} - -let handleErrorMessage = (state, payload) => { - return Object.assign({}, state, { - errorMessage: payload - }); -}; - -let handleErrorColor = (state, payload) => { - return Object.assign({}, state, { - color: payload - }); -}; - -export { - handleErrorTrue, - handleErrorFalse, - handleErrorMessage, - handleErrorDisplay, - handleErrorColor -} diff --git a/src/routes/Auth/modules/reducers/actionHandlers/fetchUserActionsHandler.js b/src/routes/Auth/modules/reducers/actionHandlers/fetchUserActionsHandler.js deleted file mode 100644 index d610d26..0000000 --- a/src/routes/Auth/modules/reducers/actionHandlers/fetchUserActionsHandler.js +++ /dev/null @@ -1,35 +0,0 @@ -let handleFetchUser = (state, payload) => { - return Object.assign({}, state, { - loginState: "fetching user", - response: {}, - login: {}, - state: "waiting" - }); -}; -let handleFetchUserSuccess = (state, payload) => { - if(!payload.data.message) { - payload.data.message = "logged in" - } - state.login = payload.data; - state.Loginstate = "fetch success" - return Object.assign({}, state, { - login: payload.data, - loginState: "fetching success", - response: {}, - state: "waiting" - }); -}; -let handleFetchUserFailure = (state, payload) => { - state.login = payload.data; - state.loginState = "generation failure" - return Object.assign({}, state, { - login: {}, - loginState: "fetching failure" - }); -}; - -export { - handleFetchUser, - handleFetchUserSuccess, - handleFetchUserFailure -} diff --git a/src/routes/Auth/modules/reducers/actionHandlers/generateUserActionsHandlers.js b/src/routes/Auth/modules/reducers/actionHandlers/generateUserActionsHandlers.js deleted file mode 100644 index f660331..0000000 --- a/src/routes/Auth/modules/reducers/actionHandlers/generateUserActionsHandlers.js +++ /dev/null @@ -1,28 +0,0 @@ -let handleGenerateUser = (state, payload) => { - return Object.assign({}, state, { - state: "generating user", - response: {} - }); -}; -let handleGenerateUserSuccess = (state, payload) => { - state.response = payload.data; - state.state = "generation success" - return Object.assign({}, state, { - response: payload.data, - state: "generation success" - }); -}; -let handleGenerateUserFailure = (state, payload) => { - state.response = payload.data; - state.state = "generation failure" - return Object.assign({}, state, { - response: {}, - state: "generation failure" - }); -}; - -export { - handleGenerateUser, - handleGenerateUserSuccess, - handleGenerateUserFailure -} diff --git a/src/routes/Auth/modules/reducers/actionHandlers/index.js b/src/routes/Auth/modules/reducers/actionHandlers/index.js index eabbaa7..01438e5 100644 --- a/src/routes/Auth/modules/reducers/actionHandlers/index.js +++ b/src/routes/Auth/modules/reducers/actionHandlers/index.js @@ -1,12 +1,6 @@ -import * as fetchUserActionsHandlers from "./fetchUserActionsHandler" -import * as generateUserActionsHandlers from "./generateUserActionsHandlers" -import * as authActionsHandlers from "./authActionsHandlers" -import * as errorActionsHandlers from "./errorActionsHandlers" +import * as loginActionsHandlers from "./loginActionsHandlers" export { - generateUserActionsHandlers, - fetchUserActionsHandlers, - authActionsHandlers, - errorActionsHandlers + loginActionsHandlers, } \ No newline at end of file diff --git a/src/routes/Auth/modules/reducers/actionHandlers/loginActionsHandlers.js b/src/routes/Auth/modules/reducers/actionHandlers/loginActionsHandlers.js new file mode 100644 index 0000000..e0ef0bb --- /dev/null +++ b/src/routes/Auth/modules/reducers/actionHandlers/loginActionsHandlers.js @@ -0,0 +1,14 @@ +import isEmpty from 'lodash/isEmpty' + +let handleLogin = (state, payload) => { + return state.set('authenticating', true) +} + +let handleLoginSuccess = (state, payload) => { + return state.set('authenticating', false) + .set('jwtToken', payload.token) +} + +export { + handleLogin +} \ No newline at end of file diff --git a/src/routes/Auth/modules/reducers/index.js b/src/routes/Auth/modules/reducers/index.js index 1f32048..274cedf 100644 --- a/src/routes/Auth/modules/reducers/index.js +++ b/src/routes/Auth/modules/reducers/index.js @@ -1,16 +1,23 @@ -import * as constants from '../../constants' +import * as Actions from '../actions' const initialState = { isAuthenticated: false, - jwtToken: "" + jwtToken: localStorage.getItem('jwtToken') || null } -export default function userUpdate (state = initialState, {type, payload}) { - if (type === constants.USER_LOGGED_IN) { - return payload - } - else if (type === constants.USER_LOGGED_OUT) { - return {} +export default (state = initialState, action) => { + switch (action.type) { + case(Actions.loginActions.LOGIN): + return state + case(Actions.loginActions.LOGIN_SUCCESS): + return state + + case(Actions.loginActions.LOGIN_FAILURE): + return state + + case(Actions.logoutActions.LOGOUT): + return state } + return state } \ No newline at end of file diff --git a/src/routes/Auth/modules/reducers/reducer.js b/src/routes/Auth/modules/reducers/reducer.js index dd0b308..4e47443 100644 --- a/src/routes/Auth/modules/reducers/reducer.js +++ b/src/routes/Auth/modules/reducers/reducer.js @@ -1,21 +1,25 @@ -/** - * Created by Joseph on 5/11/17. - */ -import * as Actions from "../actions" -import * as ActionsHandlers from "./actionHandlers" +import { Map, List } from 'immutable' +import * as Actions from '../actions' -const initialState = { - response: { success: "", message: ""}, - state: "waiting", - login: { success: "", message: ""}, - loginState: "waiting", - isAuthenticated: false, - user: {}, - errorDisplay: false, - errorMessage: "", - errorColor: "" -}; +const initialState = Map({ + jwtToken: localStorage.getItem('jwtToken') || null, + authenticating: false, +}) -export default function activityReducer (state = initialState, action) { - return state; -}; +export default (state = initialState, action) => { + switch (action.type) { + case(Actions.loginActions.LOGIN): + return state + + case(Actions.loginActions.LOGIN_SUCCESS): + return state + + case(Actions.loginActions.LOGIN_FAILURE): + return state + + case(Actions.logoutActions.LOGOUT): + return state + } + + return state +} diff --git a/src/routes/Counter/components/Counter.js b/src/routes/Counter/components/Counter.js deleted file mode 100644 index df50004..0000000 --- a/src/routes/Counter/components/Counter.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react' - -export const Counter = (props) => ( -
-

Counter: {props.view}

- - {' '} - -
-) - -Counter.propTypes = { - counter: React.PropTypes.number.isRequired, - doubleAsync: React.PropTypes.func.isRequired, - increment: React.PropTypes.func.isRequired -} - -export default Counter diff --git a/src/routes/Counter/containers/CounterContainer.js b/src/routes/Counter/containers/CounterContainer.js deleted file mode 100644 index 8c45dd2..0000000 --- a/src/routes/Counter/containers/CounterContainer.js +++ /dev/null @@ -1,39 +0,0 @@ -import {connect} from 'react-redux' -import { increment, doubleAsync } from '../modules/counter' - -/* This is a container component. Notice it does not contain any JSX, - nor does it import React. This component is **only** responsible for - wiring in the actions and state necessary to render a presentational - component - in this case, the counter: */ - -import Counter from '../components/Counter' - -/* Object of action creators (can also be function that returns object). - Keys will be passed as props to presentational components. Here we are - implementing our wrapper around increment; the component doesn't care */ - -const mapDispatchToProps = { - increment: () => increment(1), - doubleAsync -}; - -const mapStateToProps = (state, ownProps) => ({ - counter: state.counter, - view: ownProps.location.query.view -}); - -/* Note: mapStateToProps is where you should use `reselect` to create selectors, ie: - - import { createSelector } from 'reselect' - const counter = (state) => state.counter - const tripleCount = createSelector(counter, (count) => count * 3) - const mapStateToProps = (state) => ({ - counter: tripleCount(state) - }) - - Selectors can compute derived data, allowing Redux to store the minimal possible state. - Selectors are efficient. A selector is not recomputed unless one of its arguments change. - Selectors are composable. They can be used as input to other selectors. - https://github.com/reactjs/reselect */ - -export default connect(mapStateToProps, mapDispatchToProps)(Counter) diff --git a/src/routes/Counter/index.js b/src/routes/Counter/index.js deleted file mode 100644 index 55a49f4..0000000 --- a/src/routes/Counter/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import {injectReducer} from '../../store/reducers' - -export default (store) => ({ - path: 'counter', - /* Async getComponent is only invoked when route matches */ - getComponent (nextState, cb) { - /* Webpack - use 'require.ensure' to create a split point - and embed an async module loader (jsonp) when bundling */ - require.ensure([], (require) => { - /* Webpack - use require callback to define - dependencies for bundling */ - const Counter = require('./containers/CounterContainer').default; - const reducer = require('./modules/counter').default; - - /* Add the reducer to the store on key 'counter' */ - injectReducer(store, {key: 'counter', reducer}); - - /* Return getComponent */ - cb(null, Counter) - - /* Webpack named bundle */ - }, 'counter') - } -}) diff --git a/src/routes/Counter/modules/counter.js b/src/routes/Counter/modules/counter.js deleted file mode 100644 index dde8d19..0000000 --- a/src/routes/Counter/modules/counter.js +++ /dev/null @@ -1,56 +0,0 @@ -// ------------------------------------ -// Constants -// ------------------------------------ -export const COUNTER_INCREMENT = 'COUNTER_INCREMENT' -export const COUNTER_DOUBLE_ASYNC = 'COUNTER_DOUBLE_ASYNC' - -// ------------------------------------ -// Actions -// ------------------------------------ -export function increment (value = 1) { - return { - type : COUNTER_INCREMENT, - payload : value - } -} - -/* This is a thunk, meaning it is a function that immediately - returns a function for lazy evaluation. It is incredibly useful for - creating async actions, especially when combined with redux-thunk! */ - -export const doubleAsync = () => { - return (dispatch, getState) => { - return new Promise((resolve) => { - setTimeout(() => { - dispatch({ - type : COUNTER_DOUBLE_ASYNC, - payload : getState().counter - }) - resolve() - }, 200) - }) - } -} - -export const actions = { - increment, - doubleAsync -} - -// ------------------------------------ -// Action Handlers -// ------------------------------------ -const ACTION_HANDLERS = { - [COUNTER_INCREMENT] : (state, action) => state + action.payload, - [COUNTER_DOUBLE_ASYNC] : (state, action) => state * 2 -} - -// ------------------------------------ -// Reducer -// ------------------------------------ -const initialState = 0 -export default function counterReducer (state = initialState, action) { - const handler = ACTION_HANDLERS[action.type] - - return handler ? handler(state, action) : state -} diff --git a/src/routes/Dashboard/index.js b/src/routes/Dashboard/index.js index 6a7dfd6..0360ee2 100644 --- a/src/routes/Dashboard/index.js +++ b/src/routes/Dashboard/index.js @@ -1,4 +1,5 @@ import {injectReducer} from '../../store/reducers' +import UserIsAuthenticated from "../UserIsAuthenticated" export default (store) => ({ path: 'dashboard', @@ -10,13 +11,14 @@ export default (store) => ({ /* Webpack - use require callback to define dependencies for bundling */ const Dashboard = require('./containers/DashboardContainer').default; + const securedDashboard = UserIsAuthenticated(Dashboard); const reducer = require('./modules/reducer/reducer').default; /* Add the reducer to the store on key 'counter' */ injectReducer(store, {key: 'dashboard', reducer}); /* Return getComponent */ - cb(null, Dashboard) + cb(null, securedDashboard) /* Webpack named bundle */ }, 'dashboard') diff --git a/src/routes/UserIsAuthenticated.js b/src/routes/UserIsAuthenticated.js new file mode 100644 index 0000000..00bbca5 --- /dev/null +++ b/src/routes/UserIsAuthenticated.js @@ -0,0 +1,11 @@ +/** + * Created by rui on 6/2/17. + */ +import { routerActions } from 'react-router-redux' +import { UserAuthWrapper } from 'redux-auth-wrapper' + +export default UserAuthWrapper({ + authSelector: state => state.authentication.jwtToken, + redirectAction: routerActions.replace, + wrapperDisplayName: 'UserIsAuthenticated' +}) diff --git a/src/routes/index.js b/src/routes/index.js index d751f9e..739c4e6 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -2,7 +2,6 @@ import CoreLayout from '../layouts/CoreLayout' import LoginRoute from './Login' import ActivityRoute from './Activity' -import CounterRoute from './Counter' import WelcomeRoute from './Welcome' import Dashboard from './Dashboard' import Survey from './Survey' @@ -11,14 +10,6 @@ import PageNotFound from './PageNotFound' import { createStore, combineReducers, applyMiddleware, compose } from 'redux' import { Router, Route, IndexRoute, browserHistory } from 'react-router' import { routerReducer, syncHistoryWithStore, routerActions, routerMiddleware } from 'react-router-redux' -import { UserAuthWrapper } from 'redux-auth-wrapper' - - -const UserIsAuthenticated = UserAuthWrapper({ - authSelector: state => state.user, - redirectAction: routerActions.replace, - wrapperDisplayName: 'UserIsAuthenticated' -}) /* Note: Instead of using JSX, we recommend using react-router PlainRoute objects to build route definitions. */ @@ -30,7 +21,6 @@ export const createRoutes = (store) => { component: CoreLayout, indexRoute: WelcomeRoute, childRoutes: [ - CounterRoute(store), ActivityRoute(store), LoginRoute(store), AuthRoute(store), diff --git a/src/store/authentication.js b/src/store/authentication.js deleted file mode 100644 index 59a4b50..0000000 --- a/src/store/authentication.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Created by rui on 6/2/17. - */ -import browserHistory from 'react-router/lib/browserHistory' - -// ------------------------------------ -// Specialized Action Creator -// ------------------------------------ - -// ------------------------------------ -// Reducer -// ------------------------------------ -import authenticationReducer from "../routes/Auth/modules/reducers" - -export default authenticationReducer \ No newline at end of file diff --git a/src/store/authentication/actions/authenticationActions.js b/src/store/authentication/actions/authenticationActions.js new file mode 100644 index 0000000..808f049 --- /dev/null +++ b/src/store/authentication/actions/authenticationActions.js @@ -0,0 +1,20 @@ +/** + * Created by rui on 6/2/17. + */ + +export const UNAUTHENTICATIONSUCCESS = 'UNAUTHENTICATIONSUCCESS' +let unauthenticationSuccess = () => { + return {type: UNAUTHENTICATIONSUCCESS, payload: null} +} + +export const AUTHENTICATION_SUCCESS = 'AUTHENTICATION_SUCCESS' + +// the payload here is the token +let authenticationSuccess = (payload) => { + return {type: AUTHENTICATION_SUCCESS, payload: payload} +} + +export { + authenticationSuccess, + unauthenticationSuccess +} diff --git a/src/store/authentication/actions/index.js b/src/store/authentication/actions/index.js new file mode 100644 index 0000000..26ce561 --- /dev/null +++ b/src/store/authentication/actions/index.js @@ -0,0 +1,7 @@ +import * as authenticationActions from "./authenticationActions" + +export { + authenticationActions +} + + diff --git a/src/store/authentication/reducer/actionHandlers/authenticationActionsHandlers.js b/src/store/authentication/reducer/actionHandlers/authenticationActionsHandlers.js new file mode 100644 index 0000000..45aca56 --- /dev/null +++ b/src/store/authentication/reducer/actionHandlers/authenticationActionsHandlers.js @@ -0,0 +1,13 @@ +import isEmpty from 'lodash/isEmpty' + +let handleAuthenticationSuccess = (state, token) => { + return state.set('jwtToken', token) +} + +let handleUnauthenticationSuccess = (state, payload) => { + return state.set('jwtToken', null) +} +export { + handleAuthenticationSuccess, + handleUnauthenticationSuccess +} \ No newline at end of file diff --git a/src/store/authentication/reducer/actionHandlers/index.js b/src/store/authentication/reducer/actionHandlers/index.js new file mode 100644 index 0000000..51998af --- /dev/null +++ b/src/store/authentication/reducer/actionHandlers/index.js @@ -0,0 +1,6 @@ +import * as authenticationActionsHandlers from "./authenticationActionsHandlers" + + +export { + authenticationActionsHandlers +} \ No newline at end of file diff --git a/src/store/authentication/reducer/index.js b/src/store/authentication/reducer/index.js new file mode 100644 index 0000000..73cd742 --- /dev/null +++ b/src/store/authentication/reducer/index.js @@ -0,0 +1,23 @@ +/** + * Created by rui on 6/2/17. + */ +import { Map, List } from 'immutable' +import * as Actions from '../actions' +import * as ActionsHandlers from './actionHandlers' + +const initialState = { + jwtToken: localStorage.getItem('jwtToken') || null +} + +export default (state = initialState, action) => { + switch (action.type) { + case(Actions.authenticationActions.AUTHENTICATION_SUCCESS): + return ActionsHandlers.authenticationActionsHandlers.handleAuthenticationSuccess(state, action.payload) + + case(Actions.authenticationActions.UNAUTHENTICATIONSUCCESS): + return ActionsHandlers.authenticationActionsHandlers.handleUnauthenticationSuccess(state, action.payload) + + default: + return state + } +} diff --git a/src/store/reducers.js b/src/store/reducers.js index fa16fbd..06a85a1 100644 --- a/src/store/reducers.js +++ b/src/store/reducers.js @@ -1,6 +1,6 @@ import {combineReducers} from 'redux' import locationReducer from './location' -import authenticationReducer from './authentication' +import authenticationReducer from './authentication/reducer' import { routerReducer, syncHistoryWithStore, routerActions, routerMiddleware } from 'react-router-redux' From 63d951383d0b7773435a66372c4c89bb2631b836 Mon Sep 17 00:00:00 2001 From: lightertu Date: Sat, 3 Jun 2017 23:13:24 -0700 Subject: [PATCH 04/23] removed old login route --- .../login/controllers/loginControllers.js | 1 + src/containers/AppContainer.js | 5 +- src/main.js | 8 -- src/routes/Auth/components/AuthView.js | 59 ------------- src/routes/Auth/constants.js | 5 -- src/routes/Auth/containers/authContainer.js | 38 --------- src/routes/Auth/index.js | 23 ----- src/routes/Auth/modules/actions/index.js | 9 -- src/routes/Auth/modules/reducers/index.js | 23 ----- src/routes/Login/components/LoginView.js | 82 ++++++++++++++++++ src/routes/Login/containers/LoginContainer.js | 36 -------- src/routes/Login/containers/loginContainer.js | 28 +++++++ src/routes/Login/index.js | 32 +++++-- .../Login/modules/actions/authActions.js | 8 -- .../Login/modules/actions/errorActions.js | 46 ---------- .../Login/modules/actions/fetchUserActions.js | 84 ------------------- .../modules/actions/generateUserActions.js | 74 ---------------- src/routes/Login/modules/actions/index.js | 16 ++-- .../modules/actions/loginActions.js | 18 ++-- .../modules/actions/logoutActions.js | 0 .../modules/reducer}/actionHandlers/index.js | 0 .../actionHandlers/loginActionsHandlers.js | 3 +- src/routes/Login/modules/reducer/index.js | 3 + .../modules/reducer}/reducer.js | 7 +- .../actionHandlers/authActionsHandlers.js | 12 --- .../actionHandlers/errorActionsHandlers.js | 35 -------- .../actionHandlers/fetchUserActionsHandler.js | 35 -------- .../generateUserActionsHandlers.js | 28 ------- .../modules/reducers/actionHandlers/index.js | 12 --- src/routes/Login/modules/reducers/index.js | 3 - src/routes/Login/modules/reducers/reducer.js | 56 ------------- .../{Auth => Login}/modules/utils/index.js | 0 .../Questions/testQuestionView.js | 2 +- .../Welcome/containers/WelcomeContainer.js | 25 +----- .../Welcome/modules/actions/authActions.js | 8 -- .../Welcome/modules/actions/errorActions.js | 46 ---------- .../modules/actions/fetchUserActions.js | 75 ----------------- .../modules/actions/generateUserActions.js | 64 -------------- src/routes/Welcome/modules/actions/index.js | 11 --- .../actionHandlers/authActionsHandlers.js | 12 --- .../actionHandlers/errorActionsHandlers.js | 35 -------- .../actionHandlers/fetchUserActionsHandler.js | 35 -------- .../generateUserActionsHandlers.js | 28 ------- .../modules/reducers/actionHandlers/index.js | 12 --- src/routes/Welcome/modules/reducers/index.js | 3 - .../Welcome/modules/reducers/reducer.js | 56 ------------- src/routes/index.js | 13 +-- src/store/authentication/reducer/index.js | 4 +- src/store/createStore.js | 8 +- 49 files changed, 178 insertions(+), 1048 deletions(-) delete mode 100644 src/routes/Auth/components/AuthView.js delete mode 100644 src/routes/Auth/constants.js delete mode 100644 src/routes/Auth/containers/authContainer.js delete mode 100644 src/routes/Auth/index.js delete mode 100644 src/routes/Auth/modules/actions/index.js delete mode 100644 src/routes/Auth/modules/reducers/index.js create mode 100644 src/routes/Login/components/LoginView.js delete mode 100644 src/routes/Login/containers/LoginContainer.js create mode 100644 src/routes/Login/containers/loginContainer.js delete mode 100644 src/routes/Login/modules/actions/authActions.js delete mode 100644 src/routes/Login/modules/actions/errorActions.js delete mode 100644 src/routes/Login/modules/actions/fetchUserActions.js delete mode 100644 src/routes/Login/modules/actions/generateUserActions.js rename src/routes/{Auth => Login}/modules/actions/loginActions.js (85%) rename src/routes/{Auth => Login}/modules/actions/logoutActions.js (100%) rename src/routes/{Auth/modules/reducers => Login/modules/reducer}/actionHandlers/index.js (100%) rename src/routes/{Auth/modules/reducers => Login/modules/reducer}/actionHandlers/loginActionsHandlers.js (87%) create mode 100644 src/routes/Login/modules/reducer/index.js rename src/routes/{Auth/modules/reducers => Login/modules/reducer}/reducer.js (71%) delete mode 100644 src/routes/Login/modules/reducers/actionHandlers/authActionsHandlers.js delete mode 100644 src/routes/Login/modules/reducers/actionHandlers/errorActionsHandlers.js delete mode 100644 src/routes/Login/modules/reducers/actionHandlers/fetchUserActionsHandler.js delete mode 100644 src/routes/Login/modules/reducers/actionHandlers/generateUserActionsHandlers.js delete mode 100644 src/routes/Login/modules/reducers/actionHandlers/index.js delete mode 100644 src/routes/Login/modules/reducers/index.js delete mode 100644 src/routes/Login/modules/reducers/reducer.js rename src/routes/{Auth => Login}/modules/utils/index.js (100%) delete mode 100644 src/routes/Welcome/modules/actions/authActions.js delete mode 100644 src/routes/Welcome/modules/actions/errorActions.js delete mode 100644 src/routes/Welcome/modules/actions/fetchUserActions.js delete mode 100644 src/routes/Welcome/modules/actions/generateUserActions.js delete mode 100644 src/routes/Welcome/modules/actions/index.js delete mode 100644 src/routes/Welcome/modules/reducers/actionHandlers/authActionsHandlers.js delete mode 100644 src/routes/Welcome/modules/reducers/actionHandlers/errorActionsHandlers.js delete mode 100644 src/routes/Welcome/modules/reducers/actionHandlers/fetchUserActionsHandler.js delete mode 100644 src/routes/Welcome/modules/reducers/actionHandlers/generateUserActionsHandlers.js delete mode 100644 src/routes/Welcome/modules/reducers/actionHandlers/index.js delete mode 100644 src/routes/Welcome/modules/reducers/index.js delete mode 100644 src/routes/Welcome/modules/reducers/reducer.js diff --git a/server/routes/auth/login/controllers/loginControllers.js b/server/routes/auth/login/controllers/loginControllers.js index 1f6117b..c9f711e 100644 --- a/server/routes/auth/login/controllers/loginControllers.js +++ b/server/routes/auth/login/controllers/loginControllers.js @@ -17,6 +17,7 @@ const properties = ['email', 'password']; function validateInput(payload, properties) { + console.log(payload) return validateFormat(payload, properties) && UserLoginInfoValidator(payload.email, payload.password); } diff --git a/src/containers/AppContainer.js b/src/containers/AppContainer.js index a825e69..ef83731 100644 --- a/src/containers/AppContainer.js +++ b/src/containers/AppContainer.js @@ -1,6 +1,8 @@ import React, {Component, PropTypes} from 'react' import {browserHistory, Router, Route} from 'react-router' import {Provider} from 'react-redux' +import { syncHistoryWithStore } from 'react-router-redux' + class AppContainer extends Component { @@ -12,11 +14,12 @@ class AppContainer extends Component { /*
*/ render() { const {routes, store} = this.props; + const history = syncHistoryWithStore(browserHistory, store) return (
- +
diff --git a/src/main.js b/src/main.js index 2b4ec7a..269f708 100644 --- a/src/main.js +++ b/src/main.js @@ -10,7 +10,6 @@ import { applyMiddleware, compose } from 'redux' // imports for web auth import jwt from 'jsonwebtoken' -import { setCurrentUser } from './routes/Login/modules/actions/authActions' // ======================================================== // Store Instantiation @@ -22,13 +21,6 @@ const store = createStore(initialState) // set auth token -/* -if (localStorage.jwtToken) { - setAuthorizationToken(localStorage.jwtToken) - store.dispatch(setCurrentUser(jwt.decode(localStorage.jwtToken))) -} -*/ - // ======================================================== // Render Setup // ======================================================== diff --git a/src/routes/Auth/components/AuthView.js b/src/routes/Auth/components/AuthView.js deleted file mode 100644 index d109bb5..0000000 --- a/src/routes/Auth/components/AuthView.js +++ /dev/null @@ -1,59 +0,0 @@ -import React, { Component, PropTypes } from 'react' -import { routerActions } from 'react-router-redux' -import { connect } from 'react-redux' - -import { login } from '../modules/actions/' - -function select(state, ownProps) { - const isAuthenticated = state.name || false - const redirect = ownProps.location.query.redirect || '/' - return { - isAuthenticated, - redirect - } -} - -class LoginContainer extends Component { - - static propTypes = { - login: PropTypes.func.isRequired, - replace: PropTypes.func.isRequired - }; - - componentWillMount() { - const { isAuthenticated, replace, redirect } = this.props - if (isAuthenticated) { - replace(redirect) - } - } - - componentWillReceiveProps(nextProps) { - const { isAuthenticated, replace, redirect } = nextProps - const { isAuthenticated: wasAuthenticated } = this.props - - if (!wasAuthenticated && isAuthenticated) { - replace(redirect) - } - } - - onClick = (e) => { - e.preventDefault() - this.props.login({ - name: this.refs.name.value - }) - }; - - render() { - return ( -
-

Enter your name

- -
- -
- ) - } - -} - -export default connect(select, { login, replace: routerActions.replace })(LoginContainer) \ No newline at end of file diff --git a/src/routes/Auth/constants.js b/src/routes/Auth/constants.js deleted file mode 100644 index d6d2293..0000000 --- a/src/routes/Auth/constants.js +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Created by rui on 6/2/17. - */ -export const USER_LOGGED_IN = 'USER_LOGGED_IN' -export const USER_LOGGED_OUT = 'USER_LOGGED_OUT' diff --git a/src/routes/Auth/containers/authContainer.js b/src/routes/Auth/containers/authContainer.js deleted file mode 100644 index ae9e6f0..0000000 --- a/src/routes/Auth/containers/authContainer.js +++ /dev/null @@ -1,38 +0,0 @@ -import { connect } from 'react-redux' - -/* This is a container component. Notice it does not contain any JSX, - nor does it import React. This component is **only** responsible for - wiring in the actions and state necessary to render a presentational - component - in this case, the counter: */ - -import authView from '../components/AuthView' -//import * as Actions from '../modules/actions' - -const mapDispatchToProps = (dispatch) => ({ - /* - generateUser: Actions.generateUserActions.generateUser(dispatch), - fetchUser: Actions.fetchUserActions.fetchUser(dispatch), - logout: Actions.fetchUserActions.logout(dispatch), - setErrorDisplay: Actions.errorActions.setErrorDisplay(dispatch), - setErrorMessage: Actions.errorActions.setErrorMessage(dispatch), - setErrorColor: Actions.errorActions.setErrorColor(dispatch) - */ -}) - -const mapStateToProps = (state, ownProps) => { - return { - /* - state: state.login.state, - response: state.login.response, - loginState: state.login.loginState, - login: state.login.login, - user: state.login.user, - auth: state.login.isAuthenticated, - errorDisplay: state.login.errorDisplay, - errorMessage: state.login.errorMessage, - errorColor: state.login.errorColor - */ - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(authView) diff --git a/src/routes/Auth/index.js b/src/routes/Auth/index.js deleted file mode 100644 index ba63a9b..0000000 --- a/src/routes/Auth/index.js +++ /dev/null @@ -1,23 +0,0 @@ -import {injectReducer} from '../../store/reducers' - -export default (store) => ({ - path: 'auth', - /* Async getComponent is only invoked when route matches */ - getComponent (nextState, cb) { - /* Webpack - use 'require.ensure' to create a split point - and embed an async module loader (jsonp) when bundling */ - require.ensure([], (require) => { - /* Webpack - use require callback to define - dependencies for bundling */ - const Login = require('./containers/authContainer').default; - const authReducer = require('./modules/reducers') - /* The reducer is merged with global reducer */ - injectReducer(store, {key: 'auth', authReducer}); - - /* Return getComponent */ - cb(null, Login) - - /* Webpack named bundle */ - }, 'auth') - } -}); diff --git a/src/routes/Auth/modules/actions/index.js b/src/routes/Auth/modules/actions/index.js deleted file mode 100644 index 085c705..0000000 --- a/src/routes/Auth/modules/actions/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import * as loginActions from "./loginActions" -import * as logoutActions from "./logoutActions" - -export { - loginActions, - logoutActions -} - - diff --git a/src/routes/Auth/modules/reducers/index.js b/src/routes/Auth/modules/reducers/index.js deleted file mode 100644 index 274cedf..0000000 --- a/src/routes/Auth/modules/reducers/index.js +++ /dev/null @@ -1,23 +0,0 @@ -import * as Actions from '../actions' - -const initialState = { - isAuthenticated: false, - jwtToken: localStorage.getItem('jwtToken') || null -} - -export default (state = initialState, action) => { - switch (action.type) { - case(Actions.loginActions.LOGIN): - return state - case(Actions.loginActions.LOGIN_SUCCESS): - return state - - case(Actions.loginActions.LOGIN_FAILURE): - return state - - case(Actions.logoutActions.LOGOUT): - return state - } - - return state -} \ No newline at end of file diff --git a/src/routes/Login/components/LoginView.js b/src/routes/Login/components/LoginView.js new file mode 100644 index 0000000..072023c --- /dev/null +++ b/src/routes/Login/components/LoginView.js @@ -0,0 +1,82 @@ +import React, { Component, PropTypes } from 'react' + +import { Button, Form, Grid, Header, Image, Input, Message, Segment } from 'semantic-ui-react' + +function select (state, ownProps) { + const isAuthenticated = state.authentication.jwtToken !== null + const redirect = ownProps.location.query.redirect || '/dashboard' + return { + isAuthenticated, + redirect + } +} + +class LoginView extends Component { + constructor (props) { + super(props) + this.state = {email: '', password: ''} + } + + static propTypes = { + login: PropTypes.func.isRequired, + replace: PropTypes.func.isRequired + } + + componentWillMount () { + const {isAuthenticated, replace, redirect} = this.props + if (isAuthenticated) { + console.log(redirect); + replace(redirect) + } + } + + componentWillReceiveProps (nextProps) { + const {isAuthenticated, replace, redirect} = nextProps + const {isAuthenticated: wasAuthenticated} = this.props + + if (!wasAuthenticated && isAuthenticated) { + console.log("logged in"); + replace(redirect) + } + } + + handleChange = (e, {name, value}) => this.setState({[name]: value}) + + handleSubmit = e => { + const {email, password} = this.state + const {login} = this.props + e.preventDefault() + login(email, password) + } + + render () { + return ( + + + +
+
+ Log-in +
+ + + + + + + +
+
+ + New to us? Sign Up + +
+
+ ) + } + +} + +export default LoginView \ No newline at end of file diff --git a/src/routes/Login/containers/LoginContainer.js b/src/routes/Login/containers/LoginContainer.js deleted file mode 100644 index bc001c2..0000000 --- a/src/routes/Login/containers/LoginContainer.js +++ /dev/null @@ -1,36 +0,0 @@ -import {connect} from 'react-redux' - -/* This is a container component. Notice it does not contain any JSX, - nor does it import React. This component is **only** responsible for - wiring in the actions and state necessary to render a presentational - component - in this case, the counter: */ - -import Login from '../../../components/Login' -import * as Actions from '../modules/actions' - - -const mapDispatchToProps = (dispatch) => ({ - generateUser: Actions.generateUserActions.generateUser(dispatch), - fetchUser: Actions.fetchUserActions.fetchUser(dispatch), - logout: Actions.fetchUserActions.logout(dispatch), - setErrorDisplay: Actions.errorActions.setErrorDisplay(dispatch), - setErrorMessage: Actions.errorActions.setErrorMessage(dispatch), - setErrorColor: Actions.errorActions.setErrorColor(dispatch) -}); - -const mapStateToProps = (state, ownProps) => { - return { - state: state.login.state, - response: state.login.response, - loginState: state.login.loginState, - login: state.login.login, - user: state.login.user, - auth: state.login.isAuthenticated, - errorDisplay: state.login.errorDisplay, - errorMessage: state.login.errorMessage, - errorColor: state.login.errorColor - } -}; - - -export default connect(mapStateToProps, mapDispatchToProps)(Login) diff --git a/src/routes/Login/containers/loginContainer.js b/src/routes/Login/containers/loginContainer.js new file mode 100644 index 0000000..ed7e3db --- /dev/null +++ b/src/routes/Login/containers/loginContainer.js @@ -0,0 +1,28 @@ +import { connect } from 'react-redux' +import { routerActions } from 'react-router-redux' + + +/* This is a container component. Notice it does not contain any JSX, + nor does it import React. This component is **only** responsible for + wiring in the actions and state necessary to render a presentational + component - in this case, the counter: */ + +import authView from '../components/LoginView' +import * as Actions from '../modules/actions' + +const mapDispatchToProps = (dispatch) => ({ + login: Actions.loginActions.login(dispatch), + /* not sure what does it do, but it is quite important*/ + /* https://github.com/mjrussell/redux-auth-wrapper/blob/master/examples/localStorage/components/Login.js */ + replace: routerActions.replace, + logout: Actions.logoutActions.logout(dispatch), +}) + +const mapStateToProps = (state, ownProps) => { + return { + isAuthenticated: state.authentication.jwtToken !== null, + redirect: ownProps.location.query.redirect || '/dashboard' + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(authView) diff --git a/src/routes/Login/index.js b/src/routes/Login/index.js index 782360d..d24e48c 100644 --- a/src/routes/Login/index.js +++ b/src/routes/Login/index.js @@ -1,5 +1,26 @@ -import {injectReducer} from '../../store/reducers' +import { injectReducer } from '../../store/reducers' +import { Map, List } from 'immutable' +import * as Actions from './modules/actions' +const initialState = Map({ }) + +const reducer = (state = initialState, action) => { + switch (action.type) { + case(Actions.loginActions.LOGIN): + return state + + case(Actions.loginActions.LOGIN_SUCCESS): + return state + + case(Actions.loginActions.LOGIN_FAILURE): + return state + + case(Actions.logoutActions.LOGOUT): + return state + } + + return state +} export default (store) => ({ path: 'login', /* Async getComponent is only invoked when route matches */ @@ -9,11 +30,10 @@ export default (store) => ({ require.ensure([], (require) => { /* Webpack - use require callback to define dependencies for bundling */ - const Login = require('./containers/LoginContainer').default; - const reducer = require('./modules/reducers/reducer').default; - - /* Add the reducer to the store on key 'counter' */ - injectReducer(store, {key: 'login', reducer}); + const Login = require('./containers/loginContainer').default + const loginReducer = require('./modules/reducer').default + /* The reducer is merged with global reducer */ + injectReducer(store, {key: 'login', reducer}) /* Return getComponent */ cb(null, Login) diff --git a/src/routes/Login/modules/actions/authActions.js b/src/routes/Login/modules/actions/authActions.js deleted file mode 100644 index bfec32d..0000000 --- a/src/routes/Login/modules/actions/authActions.js +++ /dev/null @@ -1,8 +0,0 @@ -export const SET_CURRENT_USER = "SET_CURRENT_USER"; -let setCurrentUser = (user) => { - return { type: SET_CURRENT_USER, user: user }; -}; - -export { - setCurrentUser -} diff --git a/src/routes/Login/modules/actions/errorActions.js b/src/routes/Login/modules/actions/errorActions.js deleted file mode 100644 index 9a524dc..0000000 --- a/src/routes/Login/modules/actions/errorActions.js +++ /dev/null @@ -1,46 +0,0 @@ -export const SET_ERROR_DISPLAY = "SET_ERROR_DISPLAY"; -let setErrorDisplay = (dispatch) => { - return (bool) => { - dispatch({ - type: SET_ERROR_DISPLAY, - bool: bool - }); - - if(bool) { - dispatch(setErrorTrue()); - } else { - dispatch(setErrorFalse()); - } - - }; -}; - -export const SET_ERROR_FALSE = "SET_ERROR_FALSE"; -let setErrorFalse = () => { - return { type: SET_ERROR_FALSE}; -}; - -export const SET_ERROR_TRUE = "SET_ERROR_TRUE"; -let setErrorTrue = () => { - return { type: SET_ERROR_TRUE}; -}; - -export const SET_ERROR_MESSAGE = "SET_ERROR_MESSAGE"; -let setErrorMessage = (dispatch) => { - return (message) => { - dispatch({type: SET_ERROR_MESSAGE, message: message }); - } -}; - -export const SET_ERROR_COLOR = "SET_ERROR_COLOR"; -let setErrorColor = (color) => { - return { type: SET_ERROR_COLOR, payload: color}; -}; - -export { - setErrorFalse, - setErrorTrue, - setErrorMessage, - setErrorDisplay, - setErrorColor -} diff --git a/src/routes/Login/modules/actions/fetchUserActions.js b/src/routes/Login/modules/actions/fetchUserActions.js deleted file mode 100644 index 6b0cf73..0000000 --- a/src/routes/Login/modules/actions/fetchUserActions.js +++ /dev/null @@ -1,84 +0,0 @@ -// created by Joseph 5/11/17 - -import axios from "axios"; -import setAuthorizationToken from '../../../../components/utils/setAuthorizationToken'; -const SERVER_URL = "http://localhost:3000"; -import { setCurrentUser } from "./authActions" -import { SET_ERROR_MESSAGE } from "./errorActions" -import { browserHistory } from "react-router" - - -export const FETCH_USER = "FETCH_USER"; -let fetchUser = (dispatch) => { - return (email, password) => { - let payload = { - email: email, - password: password - }; - - dispatch({ - type: FETCH_USER, - payload: payload - }); - - let url = SERVER_URL + "/api/auth/login"; - axios.post(url, { - email: email, - password: password - }) - .then((response) => { - dispatch(fetchUserSuccess(response)); - - let data = response.data - const token = data.token; - localStorage.setItem('jwtToken', token); - setAuthorizationToken(token); - dispatch(setCurrentUser(token)); - - browserHistory.push("/dashboard") - - dispatch({ - type: SET_ERROR_MESSAGE, - message: data.message - }); - - - }) - .catch((error) => { - dispatch(fetchUserFailure(error, payload)); - console.log(error) - dispatch({ - type: SET_ERROR_MESSAGE, - message: error.response.data.error - }); - }); - } -}; - -/* user success */ -export const FETCH_USER_SUCCESS = "FETCH_USER_SUCCESS"; -let fetchUserSuccess = (response) => { - return { type: FETCH_USER_SUCCESS, payload: response }; -}; - -/* user failure */ -export const FETCH_USER_FAILURE = "FETCH_USER_FAILURE"; -let fetchUserFailure = (error, payload) => { - return { type: FETCH_USER_FAILURE, error: error, payload: payload }; -}; - -export const LOGOUT = "LOGOUT"; -let logout = (dispatch) => { - return () => { - localStorage.removeItem('jwtToken'); - setAuthorizationToken(false); - dispatch(setCurrentUser({})); - } -}; - -export { - fetchUser, - fetchUserSuccess, - fetchUserFailure, - logout -} diff --git a/src/routes/Login/modules/actions/generateUserActions.js b/src/routes/Login/modules/actions/generateUserActions.js deleted file mode 100644 index 9a0be60..0000000 --- a/src/routes/Login/modules/actions/generateUserActions.js +++ /dev/null @@ -1,74 +0,0 @@ -// created by Joseph 5/11/17 - -import axios from "axios"; -import { SET_ERROR_MESSAGE, SET_ERROR_TRUE } from "./errorActions" -import { browserHistory } from "react-router" -const SERVER_URL = "http://localhost:3000"; - -export const GENERATE_USER = "GENERATE_USER"; -let generateUser = (dispatch) => { - return (email, password) => { - - let payload = { - email: email, - password: password - }; - - dispatch({ - type: GENERATE_USER, - payload: payload - }); - - let url = SERVER_URL + "/api/auth/signup"; - axios.post(url, { - email: email, - password: password - }) - .then((response) => { - dispatch(generateUserSuccess(response)); - let data = response.data - console.log(response.data) - - dispatch({ - type: SET_ERROR_TRUE, - }); - - dispatch({ - type: SET_ERROR_MESSAGE, - message: "Sign up successful, now login" - }); - - browserHistory.push("/login"); - }) - .catch((error) => { - dispatch(generateUserFailure(error, payload)); - console.log(error.response.data.error) - dispatch({ - type: SET_ERROR_TRUE, - }); - - dispatch({ - type: SET_ERROR_MESSAGE, - message: error.response.data.error - }); - }); - } -}; - -/* user success */ -export const GENERATE_USER_SUCCESS = "GENERATE_USER_SUCCESS"; -let generateUserSuccess = (response) => { - return { type: GENERATE_USER_SUCCESS, payload: response }; -}; - -/* user failure */ -export const GENERATE_USER_FAILURE = "GENERATE_USER_FAILURE"; -let generateUserFailure = (error, payload) => { - return { type: GENERATE_USER_FAILURE, error: error, payload: payload }; -}; - -export { - generateUser, - generateUserSuccess, - generateUserFailure -} diff --git a/src/routes/Login/modules/actions/index.js b/src/routes/Login/modules/actions/index.js index 8135e12..085c705 100644 --- a/src/routes/Login/modules/actions/index.js +++ b/src/routes/Login/modules/actions/index.js @@ -1,11 +1,9 @@ -import * as generateUserActions from "./generateUserActions" -import * as fetchUserActions from "./fetchUserActions" -import * as authActions from "./authActions" -import * as errorActions from "./errorActions" +import * as loginActions from "./loginActions" +import * as logoutActions from "./logoutActions" export { - generateUserActions, - fetchUserActions, - authActions, - errorActions -} \ No newline at end of file + loginActions, + logoutActions +} + + diff --git a/src/routes/Auth/modules/actions/loginActions.js b/src/routes/Login/modules/actions/loginActions.js similarity index 85% rename from src/routes/Auth/modules/actions/loginActions.js rename to src/routes/Login/modules/actions/loginActions.js index c971bf8..e18351a 100644 --- a/src/routes/Auth/modules/actions/loginActions.js +++ b/src/routes/Login/modules/actions/loginActions.js @@ -12,14 +12,13 @@ let login = (dispatch) => { return (email, password) => { let payload = {email: email, password: password} + console.log(payload); + /* first dispatch an action so we know that user is logging in*/ dispatch({type: LOGIN, payload: null}) let url = SERVER_URL + '/api/auth/login' - axios.post(url, { - email: email, - password: password - }) + axios.post(url, payload) .then((response) => { /* this is the jwt token */ const token = response.data.token @@ -36,6 +35,7 @@ let login = (dispatch) => { dispatch(authenticationActions.authenticationSuccess(token)) }) .catch((error) => { + console.log("got here"); dispatch(loginFailure(error, payload)) }) } @@ -44,10 +44,16 @@ let login = (dispatch) => { /* user failure */ export const LOGIN_FAILURE = 'LOGIN_FAILURE' let loginFailure = (error, payload) => { - return {type: LOGIN_FAILURE, error: error, payload: payload} + return {type: LOGIN_FAILURE, payload: payload} } -export const LOGIN_SUCCESS = 'LOGIN_FAILURE' +export const LOGIN_SUCCESS = 'LOGIN_SUCCESS' let loginSuccess = (error, payload) => { return {type: LOGIN_SUCCESS, error: error, payload: payload} } + +export { + login, + loginSuccess, + loginFailure +} diff --git a/src/routes/Auth/modules/actions/logoutActions.js b/src/routes/Login/modules/actions/logoutActions.js similarity index 100% rename from src/routes/Auth/modules/actions/logoutActions.js rename to src/routes/Login/modules/actions/logoutActions.js diff --git a/src/routes/Auth/modules/reducers/actionHandlers/index.js b/src/routes/Login/modules/reducer/actionHandlers/index.js similarity index 100% rename from src/routes/Auth/modules/reducers/actionHandlers/index.js rename to src/routes/Login/modules/reducer/actionHandlers/index.js diff --git a/src/routes/Auth/modules/reducers/actionHandlers/loginActionsHandlers.js b/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js similarity index 87% rename from src/routes/Auth/modules/reducers/actionHandlers/loginActionsHandlers.js rename to src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js index e0ef0bb..388aa00 100644 --- a/src/routes/Auth/modules/reducers/actionHandlers/loginActionsHandlers.js +++ b/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js @@ -10,5 +10,6 @@ let handleLoginSuccess = (state, payload) => { } export { - handleLogin + handleLogin, + handleLoginSuccess } \ No newline at end of file diff --git a/src/routes/Login/modules/reducer/index.js b/src/routes/Login/modules/reducer/index.js new file mode 100644 index 0000000..d472a0d --- /dev/null +++ b/src/routes/Login/modules/reducer/index.js @@ -0,0 +1,3 @@ +import reducer from "./reducer" + +export default reducer \ No newline at end of file diff --git a/src/routes/Auth/modules/reducers/reducer.js b/src/routes/Login/modules/reducer/reducer.js similarity index 71% rename from src/routes/Auth/modules/reducers/reducer.js rename to src/routes/Login/modules/reducer/reducer.js index 4e47443..b58012d 100644 --- a/src/routes/Auth/modules/reducers/reducer.js +++ b/src/routes/Login/modules/reducer/reducer.js @@ -1,12 +1,9 @@ import { Map, List } from 'immutable' import * as Actions from '../actions' -const initialState = Map({ - jwtToken: localStorage.getItem('jwtToken') || null, - authenticating: false, -}) +const initialState = Map({ }) -export default (state = initialState, action) => { +export default function(state = initialState, action) { switch (action.type) { case(Actions.loginActions.LOGIN): return state diff --git a/src/routes/Login/modules/reducers/actionHandlers/authActionsHandlers.js b/src/routes/Login/modules/reducers/actionHandlers/authActionsHandlers.js deleted file mode 100644 index 659607a..0000000 --- a/src/routes/Login/modules/reducers/actionHandlers/authActionsHandlers.js +++ /dev/null @@ -1,12 +0,0 @@ -import isEmpty from 'lodash/isEmpty'; - -let handleSetCurrentUser = (state, user) => { - return Object.assign({}, state, { - isAuthenticated: !isEmpty(user), - user: user - }); -}; - -export { - handleSetCurrentUser -} \ No newline at end of file diff --git a/src/routes/Login/modules/reducers/actionHandlers/errorActionsHandlers.js b/src/routes/Login/modules/reducers/actionHandlers/errorActionsHandlers.js deleted file mode 100644 index 375841e..0000000 --- a/src/routes/Login/modules/reducers/actionHandlers/errorActionsHandlers.js +++ /dev/null @@ -1,35 +0,0 @@ -let handleErrorDisplay = (state, bool) => { - return state; -}; - -let handleErrorTrue = (state) => { - return Object.assign({}, state, { - errorDisplay: true - }); -}; - -let handleErrorFalse = (state) => { - return Object.assign({}, state, { - errorDisplay: false - }); -} - -let handleErrorMessage = (state, payload) => { - return Object.assign({}, state, { - errorMessage: payload - }); -}; - -let handleErrorColor = (state, payload) => { - return Object.assign({}, state, { - color: payload - }); -}; - -export { - handleErrorTrue, - handleErrorFalse, - handleErrorMessage, - handleErrorDisplay, - handleErrorColor -} diff --git a/src/routes/Login/modules/reducers/actionHandlers/fetchUserActionsHandler.js b/src/routes/Login/modules/reducers/actionHandlers/fetchUserActionsHandler.js deleted file mode 100644 index d610d26..0000000 --- a/src/routes/Login/modules/reducers/actionHandlers/fetchUserActionsHandler.js +++ /dev/null @@ -1,35 +0,0 @@ -let handleFetchUser = (state, payload) => { - return Object.assign({}, state, { - loginState: "fetching user", - response: {}, - login: {}, - state: "waiting" - }); -}; -let handleFetchUserSuccess = (state, payload) => { - if(!payload.data.message) { - payload.data.message = "logged in" - } - state.login = payload.data; - state.Loginstate = "fetch success" - return Object.assign({}, state, { - login: payload.data, - loginState: "fetching success", - response: {}, - state: "waiting" - }); -}; -let handleFetchUserFailure = (state, payload) => { - state.login = payload.data; - state.loginState = "generation failure" - return Object.assign({}, state, { - login: {}, - loginState: "fetching failure" - }); -}; - -export { - handleFetchUser, - handleFetchUserSuccess, - handleFetchUserFailure -} diff --git a/src/routes/Login/modules/reducers/actionHandlers/generateUserActionsHandlers.js b/src/routes/Login/modules/reducers/actionHandlers/generateUserActionsHandlers.js deleted file mode 100644 index f660331..0000000 --- a/src/routes/Login/modules/reducers/actionHandlers/generateUserActionsHandlers.js +++ /dev/null @@ -1,28 +0,0 @@ -let handleGenerateUser = (state, payload) => { - return Object.assign({}, state, { - state: "generating user", - response: {} - }); -}; -let handleGenerateUserSuccess = (state, payload) => { - state.response = payload.data; - state.state = "generation success" - return Object.assign({}, state, { - response: payload.data, - state: "generation success" - }); -}; -let handleGenerateUserFailure = (state, payload) => { - state.response = payload.data; - state.state = "generation failure" - return Object.assign({}, state, { - response: {}, - state: "generation failure" - }); -}; - -export { - handleGenerateUser, - handleGenerateUserSuccess, - handleGenerateUserFailure -} diff --git a/src/routes/Login/modules/reducers/actionHandlers/index.js b/src/routes/Login/modules/reducers/actionHandlers/index.js deleted file mode 100644 index eabbaa7..0000000 --- a/src/routes/Login/modules/reducers/actionHandlers/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import * as fetchUserActionsHandlers from "./fetchUserActionsHandler" -import * as generateUserActionsHandlers from "./generateUserActionsHandlers" -import * as authActionsHandlers from "./authActionsHandlers" -import * as errorActionsHandlers from "./errorActionsHandlers" - - -export { - generateUserActionsHandlers, - fetchUserActionsHandlers, - authActionsHandlers, - errorActionsHandlers -} \ No newline at end of file diff --git a/src/routes/Login/modules/reducers/index.js b/src/routes/Login/modules/reducers/index.js deleted file mode 100644 index 6c10011..0000000 --- a/src/routes/Login/modules/reducers/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import reducer from "reducer" - -export default reducer \ No newline at end of file diff --git a/src/routes/Login/modules/reducers/reducer.js b/src/routes/Login/modules/reducers/reducer.js deleted file mode 100644 index fd13983..0000000 --- a/src/routes/Login/modules/reducers/reducer.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Created by Joseph on 5/11/17. - */ -import * as Actions from "../actions" -import * as ActionsHandlers from "./actionHandlers" - -const initialState = { - response: { success: "", message: ""}, - state: "waiting", - login: { success: "", message: ""}, - loginState: "waiting", - isAuthenticated: false, - user: {}, - errorDisplay: false, - errorMessage: "", - errorColor: "" -}; - -export default function activityReducer (state = initialState, action) { - switch(action.type) { - - // reduce error messages - case Actions.errorActions.SET_ERROR_MESSAGE: - return ActionsHandlers.errorActionsHandlers.handleErrorMessage(state, action.message); - case Actions.errorActions.SET_ERROR_DISPLAY: - return ActionsHandlers.errorActionsHandlers.handleErrorDisplay(state, action.bool); - case Actions.errorActions.SET_ERROR_TRUE: - return ActionsHandlers.errorActionsHandlers.handleErrorTrue(state); - case Actions.errorActions.SET_ERROR_FALSE: - return ActionsHandlers.errorActionsHandlers.handleErrorFalse(state); - case Actions.errorActions.SET_ERROR_COLOR: - return ActionHandlers.errorActionsHandlers.handleErrorColor(state, action.payload) - - // set current user - case Actions.authActions.SET_CURRENT_USER: - return ActionsHandlers.authActionsHandlers.handleSetCurrentUser(state, action.user); - - // reduce login actions - case Actions.fetchUserActions.GENERATE_USER: - return ActionsHandlers.fetchUserActionsHandlers.handleFetchUser(state, action.payload); - case Actions.fetchUserActions.FETCH_USER_SUCCESS: - return ActionsHandlers.fetchUserActionsHandlers.handleFetchUserSuccess(state, action.payload); - case Actions.fetchUserActions.FETCH_USER_FAILURE: - return ActionsHandlers.fetchUserActionsHandlers.handleFetchUserFailure(state, action.payload); - - /* reduce group assignment actions */ - case Actions.generateUserActions.GENERATE_USER: - return ActionsHandlers.generateUserActionsHandlers.handleGenerateUser(state, action.payload); - case Actions.generateUserActions.GENERATE_USER_SUCCESS: - return ActionsHandlers.generateUserActionsHandlers.handleGenerateUserSuccess(state, action.payload); - case Actions.generateUserActions.GENERATE_USER_FAILURE: - return ActionsHandlers.generateUserActionsHandlers.handleGenerateUserFailure(state, action.payload); - default: - return state; - } -}; diff --git a/src/routes/Auth/modules/utils/index.js b/src/routes/Login/modules/utils/index.js similarity index 100% rename from src/routes/Auth/modules/utils/index.js rename to src/routes/Login/modules/utils/index.js diff --git a/src/routes/Survey/components/QuestionView/Questions/testQuestionView.js b/src/routes/Survey/components/QuestionView/Questions/testQuestionView.js index b9d8c4d..7d03af1 100644 --- a/src/routes/Survey/components/QuestionView/Questions/testQuestionView.js +++ b/src/routes/Survey/components/QuestionView/Questions/testQuestionView.js @@ -9,7 +9,7 @@ import {Map, List, Set, OrderedSet} from 'immutable'; import jwt from 'jsonwebtoken'; import axios from 'axios' import setAuthorizationToken from '../../../../../components/utils/setAuthorizationToken'; -import { setCurrentUser } from "../../../../../routes/Login/modules/actions/authActions" +//import { setCurrentUser } from "../../../../../routes/Login/modules/actions/authActions" const SERVER_URL = "http://localhost:3000"; diff --git a/src/routes/Welcome/containers/WelcomeContainer.js b/src/routes/Welcome/containers/WelcomeContainer.js index 38b517a..57e0924 100644 --- a/src/routes/Welcome/containers/WelcomeContainer.js +++ b/src/routes/Welcome/containers/WelcomeContainer.js @@ -5,33 +5,14 @@ import {connect} from 'react-redux' wiring in the actions and state necessary to render a presentational component - in this case, the counter: */ -import Welcome from './Welcome' -import * as Actions from '../modules/actions' +import Welcome from '../components/WelcomeView' const mapDispatchToProps = (dispatch) => ({ - generateUser: Actions.generateUserActions.generateUser(dispatch), - fetchUser: Actions.fetchUserActions.fetchUser(dispatch), - logout: Actions.fetchUserActions.logout(dispatch), - setErrorDisplay: Actions.errorActions.setErrorDisplay(dispatch), - setErrorMessage: Actions.errorActions.setErrorMessage(dispatch), - setErrorColor: Actions.errorActions.setErrorColor(dispatch) }); -const mapStateToProps = (state, ownProps) => { - console.log(state) - return { - state: state.welcome.state, - response: state.welcome.response, - loginState: state.welcome.loginState, - login: state.welcome.login, - user: state.welcome.user, - auth: state.welcome.isAuthenticated, - errorDisplay: state.welcome.errorDisplay, - errorMessage: state.welcome.errorMessage, - errorColor: state.welcome.errorColor - } -}; +const mapStateToProps = (state, ownProps) => ( { + }) export default connect(mapStateToProps, mapDispatchToProps)(Welcome) diff --git a/src/routes/Welcome/modules/actions/authActions.js b/src/routes/Welcome/modules/actions/authActions.js deleted file mode 100644 index bfec32d..0000000 --- a/src/routes/Welcome/modules/actions/authActions.js +++ /dev/null @@ -1,8 +0,0 @@ -export const SET_CURRENT_USER = "SET_CURRENT_USER"; -let setCurrentUser = (user) => { - return { type: SET_CURRENT_USER, user: user }; -}; - -export { - setCurrentUser -} diff --git a/src/routes/Welcome/modules/actions/errorActions.js b/src/routes/Welcome/modules/actions/errorActions.js deleted file mode 100644 index 9a524dc..0000000 --- a/src/routes/Welcome/modules/actions/errorActions.js +++ /dev/null @@ -1,46 +0,0 @@ -export const SET_ERROR_DISPLAY = "SET_ERROR_DISPLAY"; -let setErrorDisplay = (dispatch) => { - return (bool) => { - dispatch({ - type: SET_ERROR_DISPLAY, - bool: bool - }); - - if(bool) { - dispatch(setErrorTrue()); - } else { - dispatch(setErrorFalse()); - } - - }; -}; - -export const SET_ERROR_FALSE = "SET_ERROR_FALSE"; -let setErrorFalse = () => { - return { type: SET_ERROR_FALSE}; -}; - -export const SET_ERROR_TRUE = "SET_ERROR_TRUE"; -let setErrorTrue = () => { - return { type: SET_ERROR_TRUE}; -}; - -export const SET_ERROR_MESSAGE = "SET_ERROR_MESSAGE"; -let setErrorMessage = (dispatch) => { - return (message) => { - dispatch({type: SET_ERROR_MESSAGE, message: message }); - } -}; - -export const SET_ERROR_COLOR = "SET_ERROR_COLOR"; -let setErrorColor = (color) => { - return { type: SET_ERROR_COLOR, payload: color}; -}; - -export { - setErrorFalse, - setErrorTrue, - setErrorMessage, - setErrorDisplay, - setErrorColor -} diff --git a/src/routes/Welcome/modules/actions/fetchUserActions.js b/src/routes/Welcome/modules/actions/fetchUserActions.js deleted file mode 100644 index 18ac700..0000000 --- a/src/routes/Welcome/modules/actions/fetchUserActions.js +++ /dev/null @@ -1,75 +0,0 @@ -// created by Joseph 5/11/17 - -import axios from "axios"; -import jwt from 'jsonwebtoken'; -import setAuthorizationToken from '../../../../components/utils/setAuthorizationToken'; -const SERVER_URL = "http://localhost:3000"; -import { setCurrentUser } from "./authActions" -import { SET_ERROR_MESSAGE } from "./errorActions" - -export const FETCH_USER = "FETCH_USER"; -let fetchUser = (dispatch) => { - return (email, password) => { - let payload = { - email: email, - password: password - }; - - dispatch({ - type: FETCH_USER, - payload: payload - }); - - let url = SERVER_URL + "/api/auth/login"; - axios.post(url, { - email: email, - password: password - }) - .then((response) => { - dispatch(fetchUserSuccess(response)); - - let data = response.data - const token = data.token; - localStorage.setItem('jwtToken', token); - setAuthorizationToken(token); - dispatch(setCurrentUser(token)); - - dispatch({ - type: SET_ERROR_MESSAGE, - message: data.message - }); - }) - .catch((error) => { - dispatch(fetchUserFailure(error, payload)); - console.log(error) - }); - } -}; - -/* user success */ -export const FETCH_USER_SUCCESS = "FETCH_USER_SUCCESS"; -let fetchUserSuccess = (response) => { - return { type: FETCH_USER_SUCCESS, payload: response }; -}; - -/* user failure */ -export const FETCH_USER_FAILURE = "FETCH_USER_FAILURE"; -let fetchUserFailure = (error, payload) => { - return { type: FETCH_USER_FAILURE, error: error, payload: payload }; -}; - -export const LOGOUT = "LOGOUT"; -let logout = (dispatch) => { - return () => { - localStorage.removeItem('jwtToken'); - setAuthorizationToken(false); - dispatch(setCurrentUser({})); - } -}; - -export { - fetchUser, - fetchUserSuccess, - fetchUserFailure, - logout -} diff --git a/src/routes/Welcome/modules/actions/generateUserActions.js b/src/routes/Welcome/modules/actions/generateUserActions.js deleted file mode 100644 index eb094e5..0000000 --- a/src/routes/Welcome/modules/actions/generateUserActions.js +++ /dev/null @@ -1,64 +0,0 @@ -// created by Joseph 5/11/17 - -import axios from "axios"; -import { SET_ERROR_MESSAGE, SET_ERROR_TRUE } from "./errorActions" -const SERVER_URL = "http://localhost:3000"; - -export const GENERATE_USER = "GENERATE_USER"; -let generateUser = (dispatch) => { - return (email, password) => { - - let payload = { - email: email, - password: password - }; - - dispatch({ - type: GENERATE_USER, - payload: payload - }); - - let url = SERVER_URL + "/api/auth/signup"; - axios.post(url, { - email: email, - password: password - }) - .then((response) => { - dispatch(generateUserSuccess(response)); - let data = response.data - console.log(data.message) - - dispatch({ - type: SET_ERROR_TRUE, - }); - - dispatch({ - type: SET_ERROR_MESSAGE, - message: data.message - }); - - }) - .catch((error) => { - dispatch(generateUserFailure(error, payload)); - console.log(error) - }); - } -}; - -/* user success */ -export const GENERATE_USER_SUCCESS = "GENERATE_USER_SUCCESS"; -let generateUserSuccess = (response) => { - return { type: GENERATE_USER_SUCCESS, payload: response }; -}; - -/* user failure */ -export const GENERATE_USER_FAILURE = "GENERATE_USER_FAILURE"; -let generateUserFailure = (error, payload) => { - return { type: GENERATE_USER_FAILURE, error: error, payload: payload }; -}; - -export { - generateUser, - generateUserSuccess, - generateUserFailure -} diff --git a/src/routes/Welcome/modules/actions/index.js b/src/routes/Welcome/modules/actions/index.js deleted file mode 100644 index 8135e12..0000000 --- a/src/routes/Welcome/modules/actions/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import * as generateUserActions from "./generateUserActions" -import * as fetchUserActions from "./fetchUserActions" -import * as authActions from "./authActions" -import * as errorActions from "./errorActions" - -export { - generateUserActions, - fetchUserActions, - authActions, - errorActions -} \ No newline at end of file diff --git a/src/routes/Welcome/modules/reducers/actionHandlers/authActionsHandlers.js b/src/routes/Welcome/modules/reducers/actionHandlers/authActionsHandlers.js deleted file mode 100644 index 659607a..0000000 --- a/src/routes/Welcome/modules/reducers/actionHandlers/authActionsHandlers.js +++ /dev/null @@ -1,12 +0,0 @@ -import isEmpty from 'lodash/isEmpty'; - -let handleSetCurrentUser = (state, user) => { - return Object.assign({}, state, { - isAuthenticated: !isEmpty(user), - user: user - }); -}; - -export { - handleSetCurrentUser -} \ No newline at end of file diff --git a/src/routes/Welcome/modules/reducers/actionHandlers/errorActionsHandlers.js b/src/routes/Welcome/modules/reducers/actionHandlers/errorActionsHandlers.js deleted file mode 100644 index 375841e..0000000 --- a/src/routes/Welcome/modules/reducers/actionHandlers/errorActionsHandlers.js +++ /dev/null @@ -1,35 +0,0 @@ -let handleErrorDisplay = (state, bool) => { - return state; -}; - -let handleErrorTrue = (state) => { - return Object.assign({}, state, { - errorDisplay: true - }); -}; - -let handleErrorFalse = (state) => { - return Object.assign({}, state, { - errorDisplay: false - }); -} - -let handleErrorMessage = (state, payload) => { - return Object.assign({}, state, { - errorMessage: payload - }); -}; - -let handleErrorColor = (state, payload) => { - return Object.assign({}, state, { - color: payload - }); -}; - -export { - handleErrorTrue, - handleErrorFalse, - handleErrorMessage, - handleErrorDisplay, - handleErrorColor -} diff --git a/src/routes/Welcome/modules/reducers/actionHandlers/fetchUserActionsHandler.js b/src/routes/Welcome/modules/reducers/actionHandlers/fetchUserActionsHandler.js deleted file mode 100644 index d610d26..0000000 --- a/src/routes/Welcome/modules/reducers/actionHandlers/fetchUserActionsHandler.js +++ /dev/null @@ -1,35 +0,0 @@ -let handleFetchUser = (state, payload) => { - return Object.assign({}, state, { - loginState: "fetching user", - response: {}, - login: {}, - state: "waiting" - }); -}; -let handleFetchUserSuccess = (state, payload) => { - if(!payload.data.message) { - payload.data.message = "logged in" - } - state.login = payload.data; - state.Loginstate = "fetch success" - return Object.assign({}, state, { - login: payload.data, - loginState: "fetching success", - response: {}, - state: "waiting" - }); -}; -let handleFetchUserFailure = (state, payload) => { - state.login = payload.data; - state.loginState = "generation failure" - return Object.assign({}, state, { - login: {}, - loginState: "fetching failure" - }); -}; - -export { - handleFetchUser, - handleFetchUserSuccess, - handleFetchUserFailure -} diff --git a/src/routes/Welcome/modules/reducers/actionHandlers/generateUserActionsHandlers.js b/src/routes/Welcome/modules/reducers/actionHandlers/generateUserActionsHandlers.js deleted file mode 100644 index f660331..0000000 --- a/src/routes/Welcome/modules/reducers/actionHandlers/generateUserActionsHandlers.js +++ /dev/null @@ -1,28 +0,0 @@ -let handleGenerateUser = (state, payload) => { - return Object.assign({}, state, { - state: "generating user", - response: {} - }); -}; -let handleGenerateUserSuccess = (state, payload) => { - state.response = payload.data; - state.state = "generation success" - return Object.assign({}, state, { - response: payload.data, - state: "generation success" - }); -}; -let handleGenerateUserFailure = (state, payload) => { - state.response = payload.data; - state.state = "generation failure" - return Object.assign({}, state, { - response: {}, - state: "generation failure" - }); -}; - -export { - handleGenerateUser, - handleGenerateUserSuccess, - handleGenerateUserFailure -} diff --git a/src/routes/Welcome/modules/reducers/actionHandlers/index.js b/src/routes/Welcome/modules/reducers/actionHandlers/index.js deleted file mode 100644 index eabbaa7..0000000 --- a/src/routes/Welcome/modules/reducers/actionHandlers/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import * as fetchUserActionsHandlers from "./fetchUserActionsHandler" -import * as generateUserActionsHandlers from "./generateUserActionsHandlers" -import * as authActionsHandlers from "./authActionsHandlers" -import * as errorActionsHandlers from "./errorActionsHandlers" - - -export { - generateUserActionsHandlers, - fetchUserActionsHandlers, - authActionsHandlers, - errorActionsHandlers -} \ No newline at end of file diff --git a/src/routes/Welcome/modules/reducers/index.js b/src/routes/Welcome/modules/reducers/index.js deleted file mode 100644 index 6c10011..0000000 --- a/src/routes/Welcome/modules/reducers/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import reducer from "reducer" - -export default reducer \ No newline at end of file diff --git a/src/routes/Welcome/modules/reducers/reducer.js b/src/routes/Welcome/modules/reducers/reducer.js deleted file mode 100644 index fd13983..0000000 --- a/src/routes/Welcome/modules/reducers/reducer.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Created by Joseph on 5/11/17. - */ -import * as Actions from "../actions" -import * as ActionsHandlers from "./actionHandlers" - -const initialState = { - response: { success: "", message: ""}, - state: "waiting", - login: { success: "", message: ""}, - loginState: "waiting", - isAuthenticated: false, - user: {}, - errorDisplay: false, - errorMessage: "", - errorColor: "" -}; - -export default function activityReducer (state = initialState, action) { - switch(action.type) { - - // reduce error messages - case Actions.errorActions.SET_ERROR_MESSAGE: - return ActionsHandlers.errorActionsHandlers.handleErrorMessage(state, action.message); - case Actions.errorActions.SET_ERROR_DISPLAY: - return ActionsHandlers.errorActionsHandlers.handleErrorDisplay(state, action.bool); - case Actions.errorActions.SET_ERROR_TRUE: - return ActionsHandlers.errorActionsHandlers.handleErrorTrue(state); - case Actions.errorActions.SET_ERROR_FALSE: - return ActionsHandlers.errorActionsHandlers.handleErrorFalse(state); - case Actions.errorActions.SET_ERROR_COLOR: - return ActionHandlers.errorActionsHandlers.handleErrorColor(state, action.payload) - - // set current user - case Actions.authActions.SET_CURRENT_USER: - return ActionsHandlers.authActionsHandlers.handleSetCurrentUser(state, action.user); - - // reduce login actions - case Actions.fetchUserActions.GENERATE_USER: - return ActionsHandlers.fetchUserActionsHandlers.handleFetchUser(state, action.payload); - case Actions.fetchUserActions.FETCH_USER_SUCCESS: - return ActionsHandlers.fetchUserActionsHandlers.handleFetchUserSuccess(state, action.payload); - case Actions.fetchUserActions.FETCH_USER_FAILURE: - return ActionsHandlers.fetchUserActionsHandlers.handleFetchUserFailure(state, action.payload); - - /* reduce group assignment actions */ - case Actions.generateUserActions.GENERATE_USER: - return ActionsHandlers.generateUserActionsHandlers.handleGenerateUser(state, action.payload); - case Actions.generateUserActions.GENERATE_USER_SUCCESS: - return ActionsHandlers.generateUserActionsHandlers.handleGenerateUserSuccess(state, action.payload); - case Actions.generateUserActions.GENERATE_USER_FAILURE: - return ActionsHandlers.generateUserActionsHandlers.handleGenerateUserFailure(state, action.payload); - default: - return state; - } -}; diff --git a/src/routes/index.js b/src/routes/index.js index 739c4e6..5e9ccae 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,29 +1,24 @@ // We only need to import the modules necessary for initial render import CoreLayout from '../layouts/CoreLayout' -import LoginRoute from './Login' import ActivityRoute from './Activity' -import WelcomeRoute from './Welcome' import Dashboard from './Dashboard' import Survey from './Survey' -import AuthRoute from './Auth' +import LoginRoute from './Login' import PageNotFound from './PageNotFound' -import { createStore, combineReducers, applyMiddleware, compose } from 'redux' -import { Router, Route, IndexRoute, browserHistory } from 'react-router' -import { routerReducer, syncHistoryWithStore, routerActions, routerMiddleware } from 'react-router-redux' + +/*home route*/ +import WelcomeRoute from './Welcome' /* Note: Instead of using JSX, we recommend using react-router PlainRoute objects to build route definitions. */ export const createRoutes = (store) => { - const history = syncHistoryWithStore(browserHistory, store) return { path: '/', - history: history, component: CoreLayout, indexRoute: WelcomeRoute, childRoutes: [ ActivityRoute(store), LoginRoute(store), - AuthRoute(store), Dashboard(store), Survey(store), PageNotFound(store), diff --git a/src/store/authentication/reducer/index.js b/src/store/authentication/reducer/index.js index 73cd742..be4bb68 100644 --- a/src/store/authentication/reducer/index.js +++ b/src/store/authentication/reducer/index.js @@ -5,9 +5,9 @@ import { Map, List } from 'immutable' import * as Actions from '../actions' import * as ActionsHandlers from './actionHandlers' -const initialState = { +const initialState = Map({ jwtToken: localStorage.getItem('jwtToken') || null -} +}) export default (state = initialState, action) => { switch (action.type) { diff --git a/src/store/createStore.js b/src/store/createStore.js index 2d7b223..4c78404 100644 --- a/src/store/createStore.js +++ b/src/store/createStore.js @@ -5,9 +5,6 @@ import makeRootReducer from './reducers' import {updateLocation} from './location' import { routerReducer, syncHistoryWithStore, routerActions, routerMiddleware } from 'react-router-redux' - -import generateUsers from "../routes/Activity/modules/UserGenerator" - export default (initialState = {}) => { // ====================================================== // Middleware Configuration @@ -19,10 +16,7 @@ export default (initialState = {}) => { // ====================================================== const routingMiddleware = routerMiddleware(browserHistory); - const routingEnhancer = compose( - // Middleware you want to use in development: - applyMiddleware(routingMiddleware), - ) + const routingEnhancer = applyMiddleware(routingMiddleware); const enhancers = [routingEnhancer]; From ac95649387b65c6239c6cf93d59862904b1fe51c Mon Sep 17 00:00:00 2001 From: lightertu Date: Sat, 3 Jun 2017 23:49:36 -0700 Subject: [PATCH 05/23] weird bug --- .../{Login => LoginWeird}/components/LoginView.js | 11 ++--------- .../containers/loginContainer.js | 4 ++-- src/routes/{Login => LoginWeird}/index.js | 12 +++++++++--- .../{Login => LoginWeird}/modules/actions/index.js | 0 .../modules/actions/loginActions.js | 8 ++++---- .../modules/actions/logoutActions.js | 0 .../modules/reducer/actionHandlers/index.js | 0 .../reducer/actionHandlers/loginActionsHandlers.js | 0 .../{Login => LoginWeird}/modules/reducer/index.js | 0 .../{Login => LoginWeird}/modules/reducer/reducer.js | 6 +++--- .../{Login => LoginWeird}/modules/utils/index.js | 0 src/routes/index.js | 2 +- src/store/createStore.js | 11 ++++++----- 13 files changed, 27 insertions(+), 27 deletions(-) rename src/routes/{Login => LoginWeird}/components/LoginView.js (91%) rename src/routes/{Login => LoginWeird}/containers/loginContainer.js (88%) rename src/routes/{Login => LoginWeird}/index.js (83%) rename src/routes/{Login => LoginWeird}/modules/actions/index.js (100%) rename src/routes/{Login => LoginWeird}/modules/actions/loginActions.js (88%) rename src/routes/{Login => LoginWeird}/modules/actions/logoutActions.js (100%) rename src/routes/{Login => LoginWeird}/modules/reducer/actionHandlers/index.js (100%) rename src/routes/{Login => LoginWeird}/modules/reducer/actionHandlers/loginActionsHandlers.js (100%) rename src/routes/{Login => LoginWeird}/modules/reducer/index.js (100%) rename src/routes/{Login => LoginWeird}/modules/reducer/reducer.js (80%) rename src/routes/{Login => LoginWeird}/modules/utils/index.js (100%) diff --git a/src/routes/Login/components/LoginView.js b/src/routes/LoginWeird/components/LoginView.js similarity index 91% rename from src/routes/Login/components/LoginView.js rename to src/routes/LoginWeird/components/LoginView.js index 072023c..9efee93 100644 --- a/src/routes/Login/components/LoginView.js +++ b/src/routes/LoginWeird/components/LoginView.js @@ -2,21 +2,13 @@ import React, { Component, PropTypes } from 'react' import { Button, Form, Grid, Header, Image, Input, Message, Segment } from 'semantic-ui-react' -function select (state, ownProps) { - const isAuthenticated = state.authentication.jwtToken !== null - const redirect = ownProps.location.query.redirect || '/dashboard' - return { - isAuthenticated, - redirect - } -} - class LoginView extends Component { constructor (props) { super(props) this.state = {email: '', password: ''} } + /* static propTypes = { login: PropTypes.func.isRequired, replace: PropTypes.func.isRequired @@ -39,6 +31,7 @@ class LoginView extends Component { replace(redirect) } } + */ handleChange = (e, {name, value}) => this.setState({[name]: value}) diff --git a/src/routes/Login/containers/loginContainer.js b/src/routes/LoginWeird/containers/loginContainer.js similarity index 88% rename from src/routes/Login/containers/loginContainer.js rename to src/routes/LoginWeird/containers/loginContainer.js index ed7e3db..90a7340 100644 --- a/src/routes/Login/containers/loginContainer.js +++ b/src/routes/LoginWeird/containers/loginContainer.js @@ -7,7 +7,7 @@ import { routerActions } from 'react-router-redux' wiring in the actions and state necessary to render a presentational component - in this case, the counter: */ -import authView from '../components/LoginView' +import LoginView from '../components/LoginView' import * as Actions from '../modules/actions' const mapDispatchToProps = (dispatch) => ({ @@ -25,4 +25,4 @@ const mapStateToProps = (state, ownProps) => { } } -export default connect(mapStateToProps, mapDispatchToProps)(authView) +export default connect(mapStateToProps, mapDispatchToProps)(LoginView) diff --git a/src/routes/Login/index.js b/src/routes/LoginWeird/index.js similarity index 83% rename from src/routes/Login/index.js rename to src/routes/LoginWeird/index.js index d24e48c..0391e50 100644 --- a/src/routes/Login/index.js +++ b/src/routes/LoginWeird/index.js @@ -2,7 +2,9 @@ import { injectReducer } from '../../store/reducers' import { Map, List } from 'immutable' import * as Actions from './modules/actions' -const initialState = Map({ }) +const initialState = Map({ + isLoginSuccess: false, +}) const reducer = (state = initialState, action) => { switch (action.type) { @@ -13,7 +15,7 @@ const reducer = (state = initialState, action) => { return state case(Actions.loginActions.LOGIN_FAILURE): - return state + return state.set("isLoginSuccess", true); case(Actions.logoutActions.LOGOUT): return state @@ -21,6 +23,8 @@ const reducer = (state = initialState, action) => { return state } + + export default (store) => ({ path: 'login', /* Async getComponent is only invoked when route matches */ @@ -32,8 +36,10 @@ export default (store) => ({ dependencies for bundling */ const Login = require('./containers/loginContainer').default const loginReducer = require('./modules/reducer').default + console.log(loginReducer); + console.log(reducer); /* The reducer is merged with global reducer */ - injectReducer(store, {key: 'login', reducer}) + injectReducer(store, {key: 'login', loginReducer}) /* Return getComponent */ cb(null, Login) diff --git a/src/routes/Login/modules/actions/index.js b/src/routes/LoginWeird/modules/actions/index.js similarity index 100% rename from src/routes/Login/modules/actions/index.js rename to src/routes/LoginWeird/modules/actions/index.js diff --git a/src/routes/Login/modules/actions/loginActions.js b/src/routes/LoginWeird/modules/actions/loginActions.js similarity index 88% rename from src/routes/Login/modules/actions/loginActions.js rename to src/routes/LoginWeird/modules/actions/loginActions.js index e18351a..fe4c34f 100644 --- a/src/routes/Login/modules/actions/loginActions.js +++ b/src/routes/LoginWeird/modules/actions/loginActions.js @@ -43,13 +43,13 @@ let login = (dispatch) => { /* user failure */ export const LOGIN_FAILURE = 'LOGIN_FAILURE' -let loginFailure = (error, payload) => { - return {type: LOGIN_FAILURE, payload: payload} +let loginFailure = (error) => { + return {type: LOGIN_FAILURE, error: error} } export const LOGIN_SUCCESS = 'LOGIN_SUCCESS' -let loginSuccess = (error, payload) => { - return {type: LOGIN_SUCCESS, error: error, payload: payload} +let loginSuccess = (payload) => { + return {type: LOGIN_SUCCESS, payload: payload} } export { diff --git a/src/routes/Login/modules/actions/logoutActions.js b/src/routes/LoginWeird/modules/actions/logoutActions.js similarity index 100% rename from src/routes/Login/modules/actions/logoutActions.js rename to src/routes/LoginWeird/modules/actions/logoutActions.js diff --git a/src/routes/Login/modules/reducer/actionHandlers/index.js b/src/routes/LoginWeird/modules/reducer/actionHandlers/index.js similarity index 100% rename from src/routes/Login/modules/reducer/actionHandlers/index.js rename to src/routes/LoginWeird/modules/reducer/actionHandlers/index.js diff --git a/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js b/src/routes/LoginWeird/modules/reducer/actionHandlers/loginActionsHandlers.js similarity index 100% rename from src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js rename to src/routes/LoginWeird/modules/reducer/actionHandlers/loginActionsHandlers.js diff --git a/src/routes/Login/modules/reducer/index.js b/src/routes/LoginWeird/modules/reducer/index.js similarity index 100% rename from src/routes/Login/modules/reducer/index.js rename to src/routes/LoginWeird/modules/reducer/index.js diff --git a/src/routes/Login/modules/reducer/reducer.js b/src/routes/LoginWeird/modules/reducer/reducer.js similarity index 80% rename from src/routes/Login/modules/reducer/reducer.js rename to src/routes/LoginWeird/modules/reducer/reducer.js index b58012d..9d9167b 100644 --- a/src/routes/Login/modules/reducer/reducer.js +++ b/src/routes/LoginWeird/modules/reducer/reducer.js @@ -3,7 +3,7 @@ import * as Actions from '../actions' const initialState = Map({ }) -export default function(state = initialState, action) { +export default function reducer (state = initialState, action) { switch (action.type) { case(Actions.loginActions.LOGIN): return state @@ -16,7 +16,7 @@ export default function(state = initialState, action) { case(Actions.logoutActions.LOGOUT): return state + default: + return state } - - return state } diff --git a/src/routes/Login/modules/utils/index.js b/src/routes/LoginWeird/modules/utils/index.js similarity index 100% rename from src/routes/Login/modules/utils/index.js rename to src/routes/LoginWeird/modules/utils/index.js diff --git a/src/routes/index.js b/src/routes/index.js index 5e9ccae..4b1535f 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -3,7 +3,7 @@ import CoreLayout from '../layouts/CoreLayout' import ActivityRoute from './Activity' import Dashboard from './Dashboard' import Survey from './Survey' -import LoginRoute from './Login' +import LoginRoute from './LoginWeird' import PageNotFound from './PageNotFound' /*home route*/ diff --git a/src/store/createStore.js b/src/store/createStore.js index 4c78404..f444d27 100644 --- a/src/store/createStore.js +++ b/src/store/createStore.js @@ -3,22 +3,23 @@ import thunk from 'redux-thunk' import {browserHistory} from 'react-router' import makeRootReducer from './reducers' import {updateLocation} from './location' -import { routerReducer, syncHistoryWithStore, routerActions, routerMiddleware } from 'react-router-redux' +import { routerMiddleware } from 'react-router-redux' export default (initialState = {}) => { // ====================================================== // Middleware Configuration // ====================================================== - const middleware = [thunk]; // ====================================================== // Store Enhancers // ====================================================== - const routingMiddleware = routerMiddleware(browserHistory); - const routingEnhancer = applyMiddleware(routingMiddleware); + /* create routing middleware */ + const baseHistory = browserHistory; + const routingMiddleware = routerMiddleware(baseHistory); - const enhancers = [routingEnhancer]; + const middleware = [thunk,routingMiddleware]; + const enhancers = []; let composeEnhancers = compose; From e45bba40d546b0dd195980c737c3dfcc76e1bbe6 Mon Sep 17 00:00:00 2001 From: lightertu Date: Sun, 4 Jun 2017 00:05:14 -0700 Subject: [PATCH 06/23] changing name --- src/routes/{LoginWeird => Login}/components/LoginView.js | 2 -- src/routes/{LoginWeird => Login}/containers/loginContainer.js | 0 src/routes/{LoginWeird => Login}/index.js | 2 +- src/routes/{LoginWeird => Login}/modules/actions/index.js | 0 .../{LoginWeird => Login}/modules/actions/loginActions.js | 0 .../{LoginWeird => Login}/modules/actions/logoutActions.js | 0 .../modules/reducer/actionHandlers/index.js | 0 .../modules/reducer/actionHandlers/loginActionsHandlers.js | 0 src/routes/{LoginWeird => Login}/modules/reducer/index.js | 0 src/routes/{LoginWeird => Login}/modules/reducer/reducer.js | 0 src/routes/{LoginWeird => Login}/modules/utils/index.js | 0 src/routes/index.js | 2 +- 12 files changed, 2 insertions(+), 4 deletions(-) rename src/routes/{LoginWeird => Login}/components/LoginView.js (99%) rename src/routes/{LoginWeird => Login}/containers/loginContainer.js (100%) rename src/routes/{LoginWeird => Login}/index.js (95%) rename src/routes/{LoginWeird => Login}/modules/actions/index.js (100%) rename src/routes/{LoginWeird => Login}/modules/actions/loginActions.js (100%) rename src/routes/{LoginWeird => Login}/modules/actions/logoutActions.js (100%) rename src/routes/{LoginWeird => Login}/modules/reducer/actionHandlers/index.js (100%) rename src/routes/{LoginWeird => Login}/modules/reducer/actionHandlers/loginActionsHandlers.js (100%) rename src/routes/{LoginWeird => Login}/modules/reducer/index.js (100%) rename src/routes/{LoginWeird => Login}/modules/reducer/reducer.js (100%) rename src/routes/{LoginWeird => Login}/modules/utils/index.js (100%) diff --git a/src/routes/LoginWeird/components/LoginView.js b/src/routes/Login/components/LoginView.js similarity index 99% rename from src/routes/LoginWeird/components/LoginView.js rename to src/routes/Login/components/LoginView.js index 9efee93..414100a 100644 --- a/src/routes/LoginWeird/components/LoginView.js +++ b/src/routes/Login/components/LoginView.js @@ -8,7 +8,6 @@ class LoginView extends Component { this.state = {email: '', password: ''} } - /* static propTypes = { login: PropTypes.func.isRequired, replace: PropTypes.func.isRequired @@ -31,7 +30,6 @@ class LoginView extends Component { replace(redirect) } } - */ handleChange = (e, {name, value}) => this.setState({[name]: value}) diff --git a/src/routes/LoginWeird/containers/loginContainer.js b/src/routes/Login/containers/loginContainer.js similarity index 100% rename from src/routes/LoginWeird/containers/loginContainer.js rename to src/routes/Login/containers/loginContainer.js diff --git a/src/routes/LoginWeird/index.js b/src/routes/Login/index.js similarity index 95% rename from src/routes/LoginWeird/index.js rename to src/routes/Login/index.js index 0391e50..5d08928 100644 --- a/src/routes/LoginWeird/index.js +++ b/src/routes/Login/index.js @@ -39,7 +39,7 @@ export default (store) => ({ console.log(loginReducer); console.log(reducer); /* The reducer is merged with global reducer */ - injectReducer(store, {key: 'login', loginReducer}) + injectReducer(store, {key: 'login', reducer: loginReducer}) /* Return getComponent */ cb(null, Login) diff --git a/src/routes/LoginWeird/modules/actions/index.js b/src/routes/Login/modules/actions/index.js similarity index 100% rename from src/routes/LoginWeird/modules/actions/index.js rename to src/routes/Login/modules/actions/index.js diff --git a/src/routes/LoginWeird/modules/actions/loginActions.js b/src/routes/Login/modules/actions/loginActions.js similarity index 100% rename from src/routes/LoginWeird/modules/actions/loginActions.js rename to src/routes/Login/modules/actions/loginActions.js diff --git a/src/routes/LoginWeird/modules/actions/logoutActions.js b/src/routes/Login/modules/actions/logoutActions.js similarity index 100% rename from src/routes/LoginWeird/modules/actions/logoutActions.js rename to src/routes/Login/modules/actions/logoutActions.js diff --git a/src/routes/LoginWeird/modules/reducer/actionHandlers/index.js b/src/routes/Login/modules/reducer/actionHandlers/index.js similarity index 100% rename from src/routes/LoginWeird/modules/reducer/actionHandlers/index.js rename to src/routes/Login/modules/reducer/actionHandlers/index.js diff --git a/src/routes/LoginWeird/modules/reducer/actionHandlers/loginActionsHandlers.js b/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js similarity index 100% rename from src/routes/LoginWeird/modules/reducer/actionHandlers/loginActionsHandlers.js rename to src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js diff --git a/src/routes/LoginWeird/modules/reducer/index.js b/src/routes/Login/modules/reducer/index.js similarity index 100% rename from src/routes/LoginWeird/modules/reducer/index.js rename to src/routes/Login/modules/reducer/index.js diff --git a/src/routes/LoginWeird/modules/reducer/reducer.js b/src/routes/Login/modules/reducer/reducer.js similarity index 100% rename from src/routes/LoginWeird/modules/reducer/reducer.js rename to src/routes/Login/modules/reducer/reducer.js diff --git a/src/routes/LoginWeird/modules/utils/index.js b/src/routes/Login/modules/utils/index.js similarity index 100% rename from src/routes/LoginWeird/modules/utils/index.js rename to src/routes/Login/modules/utils/index.js diff --git a/src/routes/index.js b/src/routes/index.js index 4b1535f..5e9ccae 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -3,7 +3,7 @@ import CoreLayout from '../layouts/CoreLayout' import ActivityRoute from './Activity' import Dashboard from './Dashboard' import Survey from './Survey' -import LoginRoute from './LoginWeird' +import LoginRoute from './Login' import PageNotFound from './PageNotFound' /*home route*/ From e6cc335fabc0ef6ed6f33d6be120a467d99fb30e Mon Sep 17 00:00:00 2001 From: lightertu Date: Sun, 4 Jun 2017 00:28:48 -0700 Subject: [PATCH 07/23] fixed immutable get data bug --- src/routes/Login/index.js | 20 -------------------- src/routes/UserIsAuthenticated.js | 9 ++++++++- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/routes/Login/index.js b/src/routes/Login/index.js index 5d08928..25b0746 100644 --- a/src/routes/Login/index.js +++ b/src/routes/Login/index.js @@ -6,24 +6,6 @@ const initialState = Map({ isLoginSuccess: false, }) -const reducer = (state = initialState, action) => { - switch (action.type) { - case(Actions.loginActions.LOGIN): - return state - - case(Actions.loginActions.LOGIN_SUCCESS): - return state - - case(Actions.loginActions.LOGIN_FAILURE): - return state.set("isLoginSuccess", true); - - case(Actions.logoutActions.LOGOUT): - return state - } - - return state -} - export default (store) => ({ path: 'login', @@ -36,8 +18,6 @@ export default (store) => ({ dependencies for bundling */ const Login = require('./containers/loginContainer').default const loginReducer = require('./modules/reducer').default - console.log(loginReducer); - console.log(reducer); /* The reducer is merged with global reducer */ injectReducer(store, {key: 'login', reducer: loginReducer}) diff --git a/src/routes/UserIsAuthenticated.js b/src/routes/UserIsAuthenticated.js index 00bbca5..37daf41 100644 --- a/src/routes/UserIsAuthenticated.js +++ b/src/routes/UserIsAuthenticated.js @@ -4,8 +4,15 @@ import { routerActions } from 'react-router-redux' import { UserAuthWrapper } from 'redux-auth-wrapper' + +function selector(state) { + console.log(state); + return state.authentication.jwtToken; +} + export default UserAuthWrapper({ - authSelector: state => state.authentication.jwtToken, + /* state.authentication is implemented using immutable */ + authSelector: state => state.authentication.get("jwtToken"), redirectAction: routerActions.replace, wrapperDisplayName: 'UserIsAuthenticated' }) From c82e451464a65ac38aa76445a9dcc130e0295ce9 Mon Sep 17 00:00:00 2001 From: lightertu Date: Sun, 4 Jun 2017 03:15:54 -0700 Subject: [PATCH 08/23] inifinte routing loop --- .../login/controllers/loginControllers.js | 1 - src/containers/AppContainer.js | 2 +- src/main.js | 14 +++++++--- .../ParticipantTrash.js | 9 +------ .../Dashboard/components/DashboardView.js | 1 + .../containers/DashboardContainer.js | 4 ++- src/routes/Dashboard/index.js | 8 +++--- src/routes/Login/components/LoginView.js | 9 ++++--- src/routes/Login/containers/loginContainer.js | 2 +- src/routes/Login/index.js | 10 +++---- .../Login/modules/actions/loginActions.js | 6 +++++ src/routes/Login/modules/reducer/reducer.js | 7 +++-- src/routes/UserIsAuthenticated.js | 7 +---- src/store/baseHistory.js | 9 +++++++ src/store/createStore.js | 27 ++++++++++--------- 15 files changed, 66 insertions(+), 50 deletions(-) create mode 100644 src/store/baseHistory.js diff --git a/server/routes/auth/login/controllers/loginControllers.js b/server/routes/auth/login/controllers/loginControllers.js index c9f711e..1f6117b 100644 --- a/server/routes/auth/login/controllers/loginControllers.js +++ b/server/routes/auth/login/controllers/loginControllers.js @@ -17,7 +17,6 @@ const properties = ['email', 'password']; function validateInput(payload, properties) { - console.log(payload) return validateFormat(payload, properties) && UserLoginInfoValidator(payload.email, payload.password); } diff --git a/src/containers/AppContainer.js b/src/containers/AppContainer.js index ef83731..3d3731b 100644 --- a/src/containers/AppContainer.js +++ b/src/containers/AppContainer.js @@ -19,7 +19,7 @@ class AppContainer extends Component { return (
- +
diff --git a/src/main.js b/src/main.js index 269f708..4cd7a8d 100644 --- a/src/main.js +++ b/src/main.js @@ -7,18 +7,21 @@ import AppContainer from './containers/AppContainer' import setAuthorizationToken from './components/utils/setAuthorizationToken' import { applyMiddleware, compose } from 'redux' - // imports for web auth import jwt from 'jsonwebtoken' +import { Provider } from 'react-redux' +import { Router } from 'react-router' +import baseHistory from "./store/baseHistory" +import { syncHistoryWithStore } from 'react-router-redux' // ======================================================== // Store Instantiation // ======================================================== const initialState = window.__INITIAL_STATE__ - const store = createStore(initialState) +const history = syncHistoryWithStore(baseHistory, store) // set auth token // ======================================================== @@ -30,7 +33,12 @@ let render = () => { const routes = require('./routes/index').default(store) ReactDOM.render( - + +
+ + +
+
, MOUNT_NODE ) } diff --git a/src/routes/Activity/components/ParticipantListSidebar/ParticipantTrash.js b/src/routes/Activity/components/ParticipantListSidebar/ParticipantTrash.js index 1bfae0d..a045ba7 100644 --- a/src/routes/Activity/components/ParticipantListSidebar/ParticipantTrash.js +++ b/src/routes/Activity/components/ParticipantListSidebar/ParticipantTrash.js @@ -4,7 +4,6 @@ import React from 'react' import {Segment, Image, List, Button, Header, Icon, Label} from 'semantic-ui-react' -import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup' import PropTypes from "prop-types" import {DragSource, DropTarget} from 'react-dnd'; import {ParticipantTypes} from "../../constants/ParticipantTypes" @@ -58,13 +57,7 @@ class ParticipantTrash extends React.Component { return connectDropTarget(
- - {display} - -
+
) } } diff --git a/src/routes/Dashboard/components/DashboardView.js b/src/routes/Dashboard/components/DashboardView.js index cea06ae..9007b0f 100644 --- a/src/routes/Dashboard/components/DashboardView.js +++ b/src/routes/Dashboard/components/DashboardView.js @@ -4,6 +4,7 @@ import DashboardSideMenu from "./DashboardSideMenu/DashboardSideMenu"; import ActivitiesView from "./ActivitiesView"; import SurveysView from "./SurveysView"; import AccountSettingView from "./AccountSettingView"; +import UserIsAuthenticated from '../../UserIsAuthenticated' const _DashboardContentWrapper = (props) => (
{ Selectors are composable. They can be used as input to other selectors. https://github.com/reactjs/reselect */ -export default connect(mapStateToProps, mapDispatchToProps)(DashboardView) +export default UserIsAuthenticated(connect(mapStateToProps, mapDispatchToProps)(DashboardView)) + diff --git a/src/routes/Dashboard/index.js b/src/routes/Dashboard/index.js index 0360ee2..1b77b66 100644 --- a/src/routes/Dashboard/index.js +++ b/src/routes/Dashboard/index.js @@ -1,5 +1,7 @@ import {injectReducer} from '../../store/reducers' -import UserIsAuthenticated from "../UserIsAuthenticated" +import UserIsAuthenticated from '../UserIsAuthenticated' + +const Dashboard = require('./containers/DashboardContainer').default; export default (store) => ({ path: 'dashboard', @@ -10,15 +12,13 @@ export default (store) => ({ require.ensure([], (require) => { /* Webpack - use require callback to define dependencies for bundling */ - const Dashboard = require('./containers/DashboardContainer').default; - const securedDashboard = UserIsAuthenticated(Dashboard); const reducer = require('./modules/reducer/reducer').default; /* Add the reducer to the store on key 'counter' */ injectReducer(store, {key: 'dashboard', reducer}); /* Return getComponent */ - cb(null, securedDashboard) + cb(null, Dashboard) /* Webpack named bundle */ }, 'dashboard') diff --git a/src/routes/Login/components/LoginView.js b/src/routes/Login/components/LoginView.js index 414100a..3579d10 100644 --- a/src/routes/Login/components/LoginView.js +++ b/src/routes/Login/components/LoginView.js @@ -1,6 +1,7 @@ import React, { Component, PropTypes } from 'react' import { Button, Form, Grid, Header, Image, Input, Message, Segment } from 'semantic-ui-react' +import { browserHistory } from 'react-router' class LoginView extends Component { constructor (props) { @@ -16,20 +17,22 @@ class LoginView extends Component { componentWillMount () { const {isAuthenticated, replace, redirect} = this.props if (isAuthenticated) { - console.log(redirect); - replace(redirect) + browserHistory.push("/dashboard"); } } + /* componentWillReceiveProps (nextProps) { const {isAuthenticated, replace, redirect} = nextProps const {isAuthenticated: wasAuthenticated} = this.props + console.log("logged in"); + if (!wasAuthenticated && isAuthenticated) { - console.log("logged in"); replace(redirect) } } + */ handleChange = (e, {name, value}) => this.setState({[name]: value}) diff --git a/src/routes/Login/containers/loginContainer.js b/src/routes/Login/containers/loginContainer.js index 90a7340..c424358 100644 --- a/src/routes/Login/containers/loginContainer.js +++ b/src/routes/Login/containers/loginContainer.js @@ -14,7 +14,7 @@ const mapDispatchToProps = (dispatch) => ({ login: Actions.loginActions.login(dispatch), /* not sure what does it do, but it is quite important*/ /* https://github.com/mjrussell/redux-auth-wrapper/blob/master/examples/localStorage/components/Login.js */ - replace: routerActions.replace, + replace: (newLocation) => { dispatch(routerActions.replace(newLocation)) }, logout: Actions.logoutActions.logout(dispatch), }) diff --git a/src/routes/Login/index.js b/src/routes/Login/index.js index 25b0746..bde0b61 100644 --- a/src/routes/Login/index.js +++ b/src/routes/Login/index.js @@ -2,10 +2,7 @@ import { injectReducer } from '../../store/reducers' import { Map, List } from 'immutable' import * as Actions from './modules/actions' -const initialState = Map({ - isLoginSuccess: false, -}) - +const Login = require('./containers/loginContainer').default export default (store) => ({ path: 'login', @@ -16,10 +13,9 @@ export default (store) => ({ require.ensure([], (require) => { /* Webpack - use require callback to define dependencies for bundling */ - const Login = require('./containers/loginContainer').default - const loginReducer = require('./modules/reducer').default + const reducer = require('./modules/reducer').default /* The reducer is merged with global reducer */ - injectReducer(store, {key: 'login', reducer: loginReducer}) + injectReducer(store, {key: 'login', reducer}) /* Return getComponent */ cb(null, Login) diff --git a/src/routes/Login/modules/actions/loginActions.js b/src/routes/Login/modules/actions/loginActions.js index fe4c34f..cc5f133 100644 --- a/src/routes/Login/modules/actions/loginActions.js +++ b/src/routes/Login/modules/actions/loginActions.js @@ -4,10 +4,14 @@ import axios from 'axios' import { authenticationActions } from '../../../../store/authentication/actions' +import { browserHistory } from 'react-router' +import {routerActions } from 'react-router-redux' const SERVER_URL = 'http://localhost:3000' export const LOGIN = 'LOGIN' + + let login = (dispatch) => { return (email, password) => { let payload = {email: email, password: password} @@ -26,6 +30,8 @@ let login = (dispatch) => { /* store token in the local storage*/ localStorage.setItem('jwtToken', token) + dispatch(routerActions.replace("/dashboard")) + /* this will set the the authorization token in all axios requests. */ axios.defaults.headers.common['Authorization'] = token; diff --git a/src/routes/Login/modules/reducer/reducer.js b/src/routes/Login/modules/reducer/reducer.js index 9d9167b..9cdd592 100644 --- a/src/routes/Login/modules/reducer/reducer.js +++ b/src/routes/Login/modules/reducer/reducer.js @@ -1,7 +1,10 @@ import { Map, List } from 'immutable' import * as Actions from '../actions' -const initialState = Map({ }) + +const initialState = Map({ + isLoginSuccess: false, +}) export default function reducer (state = initialState, action) { switch (action.type) { @@ -9,7 +12,7 @@ export default function reducer (state = initialState, action) { return state case(Actions.loginActions.LOGIN_SUCCESS): - return state + return state.set("isLoginSuccess", true); case(Actions.loginActions.LOGIN_FAILURE): return state diff --git a/src/routes/UserIsAuthenticated.js b/src/routes/UserIsAuthenticated.js index 37daf41..b9448fb 100644 --- a/src/routes/UserIsAuthenticated.js +++ b/src/routes/UserIsAuthenticated.js @@ -4,15 +4,10 @@ import { routerActions } from 'react-router-redux' import { UserAuthWrapper } from 'redux-auth-wrapper' - -function selector(state) { - console.log(state); - return state.authentication.jwtToken; -} - export default UserAuthWrapper({ /* state.authentication is implemented using immutable */ authSelector: state => state.authentication.get("jwtToken"), redirectAction: routerActions.replace, + failureRedirectPath: '/login', wrapperDisplayName: 'UserIsAuthenticated' }) diff --git a/src/store/baseHistory.js b/src/store/baseHistory.js new file mode 100644 index 0000000..3826720 --- /dev/null +++ b/src/store/baseHistory.js @@ -0,0 +1,9 @@ +/** + * Created by rui on 6/4/17. + */ + +import { browserHistory } from 'react-router' + +const baseHistory = browserHistory; + +export default baseHistory \ No newline at end of file diff --git a/src/store/createStore.js b/src/store/createStore.js index f444d27..1c1f33b 100644 --- a/src/store/createStore.js +++ b/src/store/createStore.js @@ -1,9 +1,10 @@ -import {applyMiddleware, compose, createStore} from 'redux' +import { applyMiddleware, compose, createStore } from 'redux' import thunk from 'redux-thunk' -import {browserHistory} from 'react-router' +import baseHistory from './baseHistory' import makeRootReducer from './reducers' -import {updateLocation} from './location' +import { updateLocation } from './location' import { routerMiddleware } from 'react-router-redux' +import { browserHistory } from 'react-router' export default (initialState = {}) => { // ====================================================== @@ -15,16 +16,15 @@ export default (initialState = {}) => { // ====================================================== /* create routing middleware */ - const baseHistory = browserHistory; - const routingMiddleware = routerMiddleware(baseHistory); + const routingMiddleware = routerMiddleware(baseHistory) - const middleware = [thunk,routingMiddleware]; - const enhancers = []; + const middleware = [thunk] + const enhancers = [] - let composeEnhancers = compose; + let composeEnhancers = compose if (__DEV__) { - const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; + const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ if (typeof composeWithDevToolsExtension === 'function') { composeEnhancers = composeWithDevToolsExtension } @@ -37,19 +37,20 @@ export default (initialState = {}) => { makeRootReducer(), initialState, composeEnhancers( + applyMiddleware(routingMiddleware), applyMiddleware(...middleware), ...enhancers ) - ); + ) - store.asyncReducers = {}; + store.asyncReducers = {} // To unsubscribe, invoke `store.unsubscribeHistory()` anytime - store.unsubscribeHistory = browserHistory.listen(updateLocation(store)); + // store.unsubscribeHistory = browserHistory.listen(updateLocation(store)) if (module.hot) { module.hot.accept('./reducers', () => { - const reducers = require('./reducers').default; + const reducers = require('./reducers').default store.replaceReducer(reducers(store.asyncReducers)) }) } From 6120e862320dec6543bb84732f78c28722745f4c Mon Sep 17 00:00:00 2001 From: Matt Almenshad Date: Sun, 4 Jun 2017 06:52:42 -0700 Subject: [PATCH 09/23] Commiting all the Dashboard/Surveys word. Cleaning up some messes, prepping to fix activity --- package.json | 5 +- server/config/main.js | 2 +- server/models/Participant.js | 2 - server/models/User.js | 2 +- .../createParticipantController.js | 4 +- .../getSurveyForParticipantsController.js | 6 +- .../controllers/createSurveyController.js | 11 +- .../Activity/components/ActivityView.js | 63 +- .../components/FilterMenu/FilterMenu.js | 14 +- .../components/GroupCard/GroupCard.js | 343 ++++----- .../ParticipantListSidebar.js | 153 ++-- .../Activity/containers/ActivityContainer.js | 4 +- .../actions/filterParticipantsActions.js | 11 + src/routes/Activity/modules/actions/index.js | 4 +- .../modules/actions/userMatchingActions.js | 2 +- .../filterParticipantsActionsHandlers.js | 11 + .../modules/reducer/actionsHandlers/index.js | 4 +- .../Activity/modules/reducer/reducer.js | 4 + .../components/ActivityCard/ActivityCard.js | 15 +- .../DeleteActivityModal.js | 2 - .../EditActivityInfoModal.js | 2 +- .../CreateActivityCard/CreateActivityCard.js | 1 + .../CreateActivityModal.js | 28 +- .../components/SurveysView/SurveysView.js | 2 +- .../CreateSurveyModal/CreateSurveyModal.js | 66 +- .../DeleteSurveyModal/DeleteSurveyModal.js | 2 - .../EditSurveyInfoModal.js | 2 - .../components/SurveyCard/SurveyCard.js | 17 +- .../SurveyInfoForm/SurveyInfoForm.js | 35 +- .../SurveyInfoForm/SurveyQuestionTable.js | 44 +- .../modules/actions/createActivityActions.js | 2 +- .../modules/actions/createSurveyActions.js | 2 +- .../modules/actions/deleteActivityActions.js | 2 +- .../modules/actions/deleteSurveyActions.js | 2 +- .../actions/fetchActivityListActions.js | 2 +- .../modules/actions/fetchSurveyListActions.js | 3 +- .../modules/actions/updateActivityActions.js | 2 +- .../modules/actions/updateSurveyActions.js | 2 +- .../actions/updateUserProfileActions.js | 2 +- .../createActivityActionHandlers.js | 1 + .../fetchSurveyListActionHandlers.js | 1 + .../updateActivityHolderActionHandlers.js | 11 +- .../updateSurveyHolderActionHandlers.js | 4 +- .../Dashboard/modules/reducer/reducer.js | 30 +- .../components/QuestionView/QuestionView.js | 86 +-- .../Questions/CircleSelectionQuestionView.js | 88 ++- .../Questions/CircleSelectionQuestionView_.js | 52 ++ .../Constants/PROGRAMMING_LANGUAGES.js | 693 ++++++++++++++++++ .../QuestionView/Questions/Constants/index.js | 3 + .../Questions/EmailQuestionView.js | 34 + .../MultiInputTextFieldQuestionView.js | 58 +- .../MultiInputTextFieldQuestionView_.js | 36 + .../Questions/NameQuestionView.js | 34 + .../ProgrammingLanguagesQuestionView.js | 54 ++ .../SingleInputTextFieldQuestionView_.js | 32 + .../Questions/TimeAvailabilityQuestionView.js | 66 ++ .../QuestionView/Questions/index.js | 21 +- .../Questions/testQuestionView_.js | 141 ++++ src/routes/Survey/components/SurveyView.js | 191 ++++- .../Survey/containers/SurveyContainer.js | 52 +- src/routes/Survey/index.js | 2 +- .../modules/actions/fetchSurveyActions.js | 40 + src/routes/Survey/modules/actions/index.js | 65 +- .../modules/actions/submitSurveyActions.js | 84 +++ .../actions/updateSurveyQuestionActions.js | 56 ++ .../fetchSurveyActionHandlers.js | 55 ++ .../modules/reducer/actionsHandlers/index.js | 70 +- .../submitSurveyActionHandlers.js | 60 ++ .../updateSurveyQuestionActionHandlers.js | 62 ++ src/routes/Survey/modules/reducer/reducer.js | 143 ++-- 70 files changed, 2431 insertions(+), 774 deletions(-) create mode 100644 src/routes/Activity/modules/actions/filterParticipantsActions.js create mode 100644 src/routes/Activity/modules/reducer/actionsHandlers/filterParticipantsActionsHandlers.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/CircleSelectionQuestionView_.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/Constants/PROGRAMMING_LANGUAGES.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/Constants/index.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/EmailQuestionView.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/MultiInputTextFieldQuestionView_.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/NameQuestionView.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/ProgrammingLanguagesQuestionView.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/SingleInputTextFieldQuestionView_.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/TimeAvailabilityQuestionView.js create mode 100644 src/routes/Survey/components/QuestionView/Questions/testQuestionView_.js create mode 100644 src/routes/Survey/modules/actions/fetchSurveyActions.js create mode 100644 src/routes/Survey/modules/actions/submitSurveyActions.js create mode 100644 src/routes/Survey/modules/actions/updateSurveyQuestionActions.js create mode 100644 src/routes/Survey/modules/reducer/actionsHandlers/fetchSurveyActionHandlers.js create mode 100644 src/routes/Survey/modules/reducer/actionsHandlers/submitSurveyActionHandlers.js create mode 100644 src/routes/Survey/modules/reducer/actionsHandlers/updateSurveyQuestionActionHandlers.js diff --git a/package.json b/package.json index 0b26bc8..20985ad 100644 --- a/package.json +++ b/package.json @@ -112,8 +112,9 @@ "postcss-loader": "^1.1.0", "prop-types": "^15.5.8", "randomcolor": "^0.5.1", - "react": "^15.4.2", + "react": "^15.5.4", "react-bootstrap": "^0.30.8", + "react-copy-to-clipboard": "^5.0.0", "react-dnd": "^2.3.0", "react-dnd-html5-backend": "^2.3.0", "react-dom": "^15.5.4", @@ -132,9 +133,9 @@ "semantic-ui-react": "^0.68", "style-loader": "^0.13.1", "url-loader": "^0.5.6", + "validator": "^7.0.0", "webpack": "^1.15.0", "webpack-hot-middleware": "^2.18.0", - "validator": "^7.0.0", "yargs": "^6.3.0" }, "devDependencies": { diff --git a/server/config/main.js b/server/config/main.js index 5db035e..c108ffe 100644 --- a/server/config/main.js +++ b/server/config/main.js @@ -6,6 +6,6 @@ const passport = require('passport'); module.exports = { 'secret': 'asdawldjal', - databaseUrl: 'mongodb://teamdivider:CIS4222017@ds137101.mlab.com:37101/teamdivider', + databaseUrl: 'mongodb://localhost:27017/teamdivider', authenticationMiddleware: passport.authenticate('jwt', { session: false }), }; diff --git a/server/models/Participant.js b/server/models/Participant.js index 6d4ff30..5896f9e 100644 --- a/server/models/Participant.js +++ b/server/models/Participant.js @@ -16,9 +16,7 @@ const ParticipantSchema = new Schema({ email: { type: String, lowercase: true, - unique: true, required: true, - default: "" }, // _creator: { diff --git a/server/models/User.js b/server/models/User.js index 45015b3..d73d410 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -17,8 +17,8 @@ let UserSchema = Schema({ email: { type: String, - lowercase: true, unique: true, + lowercase: true, required: true, default: "" }, diff --git a/server/routes/activities/participants/controllers/createParticipantController.js b/server/routes/activities/participants/controllers/createParticipantController.js index defddb9..ad20bb0 100644 --- a/server/routes/activities/participants/controllers/createParticipantController.js +++ b/server/routes/activities/participants/controllers/createParticipantController.js @@ -43,7 +43,9 @@ module.exports = function (req, res, next) { const payload = req.body; const activityId = req.params.activityId; - + + console.log(payload); + console.log(payload.surveyResponses); // check if the activity is full. If so, then no other one can participate in Activity.findOne({_id: activityId, isDeleted: false}) diff --git a/server/routes/activities/participants/controllers/getSurveyForParticipantsController.js b/server/routes/activities/participants/controllers/getSurveyForParticipantsController.js index f20e75d..58022ea 100644 --- a/server/routes/activities/participants/controllers/getSurveyForParticipantsController.js +++ b/server/routes/activities/participants/controllers/getSurveyForParticipantsController.js @@ -30,12 +30,12 @@ module.exports = function (req, res, next) { { _id: req.params.activityId, isDeleted: false, survey: {'$ne': []} }) .exec() .then(function (activity) { - if (activity !== null && activity.survey.length === 1) { + if (activity !== null) { return res.json({ - survey: activity.survey[0].getPublicFields() + survey: activity.survey.getPublicFields() }); } else { - const errorMessage = "Cannot find an activity has id " + req.params.activityId + ", or it doesn't contain a survey"; + const errorMessage = "Cannot find an activity has id " + req.params.activityId; return createErrorHandler(res, HttpStatus.NOT_FOUND)(errorMessage); } }) diff --git a/server/routes/surveys/controllers/createSurveyController.js b/server/routes/surveys/controllers/createSurveyController.js index 11b22bf..89bf5b6 100644 --- a/server/routes/surveys/controllers/createSurveyController.js +++ b/server/routes/surveys/controllers/createSurveyController.js @@ -26,17 +26,18 @@ function validateFormat(payload, properties){ module.exports = function (req, res, next) { - if (!validateInput(req)) { - const errorMessage = 'please give the correct payload'; - createErrorHandler(res, HttpStatus.BAD_REQUEST)(errorMessage); - return; - } const userId = req.user._id; const payload = req.body; console.log(payload); + if (!validateInput(req)) { + const errorMessage = 'please give the correct payload'; + createErrorHandler(res, HttpStatus.BAD_REQUEST)(errorMessage); + return; + } + const newSurvey = new Survey({ _creator: userId, title: payload.title, diff --git a/src/routes/Activity/components/ActivityView.js b/src/routes/Activity/components/ActivityView.js index 804d14b..d82c58e 100644 --- a/src/routes/Activity/components/ActivityView.js +++ b/src/routes/Activity/components/ActivityView.js @@ -36,19 +36,25 @@ export class ActivityCardViewWrapper extends React.Component { export class ActivityView extends React.Component { constructor(props) { super(props); - this.props.fetchParticipantList(this.props.activityId); this.state = ({filters: []}); - this.setFilterValues = this.setFilterValues.bind(this); this.toggleLock = this.toggleLock.bind(this); } + componentWillMount() { + this.props.fetchParticipantList(this.props.activityId); + } toggleLock(group) { this.props.toggleLock(group); } - setFilterValues(input, event) { + setFilterValues = (input, event) => { + console.log('---------------------------'); + console.log('SET FILTER VALUES'); + console.log(input); + console.log(event.target); + console.log('---------------------------'); let field = this.state[input]; if(event.target.getAttribute('class') === "delete icon") { let item = event.target.parentNode.getAttribute('value'); @@ -57,7 +63,7 @@ export class ActivityView extends React.Component { field.splice(index, 1); // remove item from filter } } else { - if(event.target.getAttribute('name') != "-search") { + if(event.target.getAttribute('name') !== "-search") { if(event.target.getAttribute('name') === null) { field.push(event.target.parentNode.getAttribute('name')); // add item to filter } else { @@ -68,14 +74,43 @@ export class ActivityView extends React.Component { this.setState({field:field}); } - setCurrentlySelected(id) { - this.props.filterParticipantsMatch(id); - } + setCurrentlySelected(id) { this.props.filterParticipantsMatch(id); } render() { const itemsPerRow = 10; const cardsPerRow = 1; let numOfGroups = this.props.totalCapacity / this.props.groupCapacity; + const refilterParticipants = (participants) => { + const hasSkills = (filterSkills, skills) => { + skills = skills.map( (skill) => (skill.name)); + + let result = true; + for (let i = 0; i < filterSkills.length; i++) { + result &= skills.includes(filterSkills[i]); + } + return result; + } + + const hasFilterValues = (filter, participant) => { + if (filter.length === 0) { + return true; + } + + const skills = participant.skills, + availiblity = participant.availability; + + return hasSkills(filter, skills); + } + + return participants.filter( + (participant) => { + return hasFilterValues(this.props.filter, participant); + } + ) + } + + /* the master participants list is filtered here it is just a hacky implementation*/ + let participants = refilterParticipants(this.props.participants); let separateIntoGroups = (participants) => { let groups = []; @@ -96,7 +131,7 @@ export class ActivityView extends React.Component { return groups; }; - let dragging = (this.props.matching.get("current").length > 0) ? true : false; + let dragging = (this.props.matching.get("current").length > 0); let getGroupCards = (groups) => { return ( @@ -115,7 +150,9 @@ export class ActivityView extends React.Component { draggedUser={ this.props.matching.get("current") } group={ i } unlocked={ this.props.unlocked.get(i) } - filters={ this.state.filters }/> + filters={ this.state.filters } + dragging={dragging} + /> ) ) @@ -124,7 +161,7 @@ export class ActivityView extends React.Component { return (
- + setFilterValues={ this.setFilterValues } + filterParticipants = { this.props.filterParticipants } + /> } - { getGroupCards(separateIntoGroups(this.props.participants)) } + { getGroupCards(separateIntoGroups(participants)) }
diff --git a/src/routes/Activity/components/FilterMenu/FilterMenu.js b/src/routes/Activity/components/FilterMenu/FilterMenu.js index 507fba3..a23cf02 100644 --- a/src/routes/Activity/components/FilterMenu/FilterMenu.js +++ b/src/routes/Activity/components/FilterMenu/FilterMenu.js @@ -11,14 +11,14 @@ class FilterMenu extends React.Component { constructor(props) { super(props); this.state = { - inputInverted: false + inputInverted: false, } } static propTypes = { generateGroupAssignment: PropTypes.func.isRequired, activityId: PropTypes.string.isRequired, - + filterValues: PropTypes.object.isRequired, }; generateGroupButtonHandlerMaker = (algorithmKey) => { @@ -43,6 +43,11 @@ class FilterMenu extends React.Component { this.setState({inputInverted: !this.state.inputInverted}); }; + handleChange = (e, { value }) => { + console.log(value); + this.props.filterParticipants(value); + } + render() { const filterMenuStyle = { position: "relative", @@ -96,8 +101,9 @@ class FilterMenu extends React.Component { options={options} multiple selection transparent - inverted={ this.state.inputInverted } - onChange={ this.props.setFilterValues.bind(this, "filters") } + //inverted={ this.state.inputInverted } + //onChange={ this.props.setFilterValues.bind(this, "filters") } + onChange={ this.handleChange } /> } diff --git a/src/routes/Activity/components/GroupCard/GroupCard.js b/src/routes/Activity/components/GroupCard/GroupCard.js index 1825fed..ab20dd2 100644 --- a/src/routes/Activity/components/GroupCard/GroupCard.js +++ b/src/routes/Activity/components/GroupCard/GroupCard.js @@ -3,15 +3,15 @@ * Additions made by Joseph 5/28/17 */ import React from 'react' -import PropTypes from 'prop-types'; -import {Icon, Card, Label, Segment, Image, Popup} from 'semantic-ui-react' -import ParticipantProfilePopup from "../ParticipantProfilePopup"; -import {DragSource, DropTarget} from 'react-dnd'; -import {AvailabilitySegment, SkillCountSegment} from "./MatchingStatusSegments" +import PropTypes from 'prop-types' +import { Icon, Card, Label, Segment, Image, Popup, Dimmer } from 'semantic-ui-react' +import ParticipantProfilePopup from '../ParticipantProfilePopup' +import { DragSource, DropTarget } from 'react-dnd' +import { AvailabilitySegment, SkillCountSegment } from './MatchingStatusSegments' -import {ParticipantTypes} from "../../constants/ParticipantTypes" +import { ParticipantTypes } from '../../constants/ParticipantTypes' -const transparentImage = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Transparent_square.svg/2000px-Transparent_square.svg.png"; +const transparentImage = 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Transparent_square.svg/2000px-Transparent_square.svg.png' const participantCardItemSource = { beginDrag(props) { @@ -19,9 +19,9 @@ const participantCardItemSource = { return { participantId: props.participant.participantId, oldGroupNumber: props.participant.groupNumber - }; + } } -}; +} @DragSource(ParticipantTypes.GROUPED_PARTICIPANT, participantCardItemSource, (connect, monitor) => ({ connectDragSource: connect.dragSource(), @@ -30,30 +30,12 @@ const participantCardItemSource = { class DraggableCard extends React.Component { static propTypes = { participant: PropTypes.object.isRequired - }; - - render() { - const {connectDragSource, isDragging, participant} = this.props; - - if(this.props.unlocked) { - return ( -
- } - position="top right" - offset={ 0 } - name={ participant.name } - image={ participant.image } - groupNumber={participant.groupNumber } - skills={ participant.skills } - availability={ participant.availability } - participantId={ participant.participantId }/> -
- ) - } + } - return connectDragSource( -
+ render () { + const {connectDragSource, isDragging, participant} = this.props + let participantCard = +
} position="top right" @@ -65,14 +47,19 @@ class DraggableCard extends React.Component { availability={ participant.availability } participantId={ participant.participantId }/>
- ) + + if (this.props.unlocked) { + return ( participantCard ) + } + + return connectDragSource(participantCard) } } const participantTarget = { drop(props, monitor) { - props.setCurrentlySelected(""); // resets curretly selected user - const participantDropped = monitor.getItem(); + props.setCurrentlySelected('') // resets curretly selected user + const participantDropped = monitor.getItem() if (props.groupNumber !== participantDropped.oldGroupNumber) { props.updateParticipantGroupNumber( props.activityId, @@ -81,7 +68,7 @@ const participantTarget = { props.groupNumber) } } -}; +} @DropTarget([ParticipantTypes.GROUPED_PARTICIPANT, ParticipantTypes.UNGROUPED_PARTICIPANT], participantTarget, (connect, monitor) => ({ @@ -97,212 +84,198 @@ class GroupCard extends React.Component { groupNumber: PropTypes.number.isRequired, itemsPerRow: PropTypes.number.isRequired, updateParticipantGroupNumber: PropTypes.func.isRequired - }; - - constructor(props) { - super(props); - this.state = { - matchingStatusOpen: true, availability: [], skills: [] - }; - } - toggleMatchingStatus = () => { - // this.setState({matchingStatusOpen: !this.state.matchingStatusOpen}); - }; + constructor (props) { + super(props) + /* + this.state = { + matchingStatusOpen: true, availability: [], skills: [] + } + */ + } - render() { - const {connectDropTarget, isOver} = this.props; + render () { + const {connectDropTarget, isOver} = this.props let generateEmptySpots = () => { - let emptyNum = this.props.capacity - this.props.participants.length; - let result = []; + let emptyNum = this.props.capacity - this.props.participants.length + let result = [] for (let i = 0; i < emptyNum; i++) { result.push( ) } - return result; - }; - let pickLabelColor = (size, capacity) => { + return result + } + let pickCapacityLabelColor = (size, capacity) => { if (size === capacity) - return "green"; + return 'green' else if (size > capacity) - return "red"; + return 'red' else - return null; - }; + return null + } let overAllAvailability = (participants) => { if (participants.length <= 0) { - return [false, false, false, false, false, false, false]; + return [false, false, false, false, false, false, false] } return participants.reduce((acc, participant) => { - for (let i = 0; i < 7; i++) { - acc[i] = acc[i] && participant.availability[i]; + for (let i = 0; i < 7; i++) { + acc[i] = acc[i] && participant.availability[i] } - return acc; - }, [true, true, true, true, true, true, true]); - }; + return acc + }, [true, true, true, true, true, true, true]) + } let generateSkillCountMap = (participants) => { - let skillCountMap = {}; + let skillCountMap = {} for (let i = 0; i < participants.length; i++) { - let skills = participants[i].skills; + let skills = participants[i].skills for (let j = 0; j < skills.length; j++) { - let skillName = skills[j].name; + let skillName = skills[j].name if (!(skillName in skillCountMap)) { - skillCountMap[skillName] = 1; + skillCountMap[skillName] = 1 } else { - skillCountMap[skillName]++; + skillCountMap[skillName]++ } } } - return skillCountMap; - }; + return skillCountMap + } - let skills = generateSkillCountMap(this.props.participants); + let skills = generateSkillCountMap(this.props.participants) let days = overAllAvailability(this.props.participants) - let numsTodays = {1: "monday", 2: "tuseday", 3: "wednesday", 4: "thursday", 5: "friday", 6: "saturday", 0: "sunday"}; - let daysToNums = {"monday": 1, "tuseday": 2, "wednesday": 3, "thursday": 4, "friday": 5, "saturday": 6, "sunday": 0} - let count = 0; - let color = ""; - let i; - let itemCount = this.props.matching.size; - let view = true; - let result = 0; - if(itemCount > 0) { - for(i = 0; i < days.length; i++) { - if(this.props.matching.has(numsTodays[i]) && days[i]) { - count++; + let numsTodays = { + 1: 'monday', + 2: 'tuseday', + 3: 'wednesday', + 4: 'thursday', + 5: 'friday', + 6: 'saturday', + 0: 'sunday' + } + let daysToNums = { + 'monday': 1, + 'tuseday': 2, + 'wednesday': 3, + 'thursday': 4, + 'friday': 5, + 'saturday': 6, + 'sunday': 0 + } + let count = 0 + let matchingColor = '' + let i + let itemCount = this.props.matching.size + let view = true + let result = 0 + if (itemCount > 0) { + for (i = 0; i < days.length; i++) { + if (this.props.matching.has(numsTodays[i]) && days[i]) { + count++ } } - let keys = Object.keys(skills); - for(i = 0; i < keys.length; i++) { - if(this.props.matching.has(keys[i])) { - count++; + let keys = Object.keys(skills) + for (i = 0; i < keys.length; i++) { + if (this.props.matching.has(keys[i])) { + count++ } } - result = Math.round((count/itemCount)*100)/100; + result = Math.round((count / itemCount) * 100) / 100 - if(result > .70 || this.props.participants.length == 0) { - color = "green"; - } else if(result > .45) { - color = "yellow"; + if (result > .70 || this.props.participants.length === 0) { + matchingColor = 'green' + } else if (result > .45) { + matchingColor = 'yellow' } else { - color = "red"; + matchingColor = 'red' } } - - for(i = 0; i < this.props.filters.length; i++) { - if(this.props.filters[i] in daysToNums) { - if(!days[daysToNums[this.props.filters[i]]]) { - view = false; - break; + + for (i = 0; i < this.props.filters.length; i++) { + if (this.props.filters[i] in daysToNums) { + if (!days[daysToNums[this.props.filters[i]]]) { + view = false + break } } else { - if(Object.keys(skills).indexOf(this.props.filters[i]) == -1) { - view = false; - break; + if (Object.keys(skills).indexOf(this.props.filters[i]) === -1) { + view = false + break } - } + } } - let background = ""; - if(this.props.participants.some((el) => el.participantId == this.props.draggedUser)) { - background = "black"; + let background = '' + if (this.props.participants.some((el) => el.participantId === this.props.draggedUser)) { + background = 'black' } - let lockIcon = "lock"; - let popup = "click to lock in this group"; - if(this.props.unlocked) { - lockIcon = "unlock"; - popup = "click to unlock in this group"; - color = "grey"; + if (this.props.unlocked) { + matchingColor = 'grey' } - // - let test = { - top: 0, - left: 0, - marginTop: -24, - marginLeft: -24, - marginRight: 0, - paddingRight: 0, - marginBottom: 10 - } - let display; - if(view) { - display = ( - - -
- - - -
- - { - this.props.participants.map((participant) => - - ) - } - { generateEmptySpots() } - - - -
+ let display = ( +
+ + + + + { + this.props.participants.map((participant) => + + ) + } + { generateEmptySpots() } + - { (this.props.participants.length > 0 && this.state.matchingStatusOpen ) && - } - - ); - } + + - if(this.props.unlocked) { // if locked nothing can be dragged into it - return ( -
- {display} -
- ) - } + { (this.props.participants.length > 0 ) && + } - return connectDropTarget( -
- {display} + { (this.props.participants.length > 0 ) && + } +
) + + return (this.props.unlocked) ? display : connectDropTarget(display) + } } -export default GroupCard; +export default GroupCard diff --git a/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js b/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js index 3e66d2e..3b16927 100644 --- a/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js +++ b/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js @@ -3,24 +3,26 @@ */ import React from 'react' -import {Segment, Image, List, Button, Header, Icon} from 'semantic-ui-react' -import PropTypes from "prop-types" -import {DragSource, DropTarget} from 'react-dnd'; +import { Segment, Image, List, Button, Header, Icon } from 'semantic-ui-react' +import PropTypes from 'prop-types' +import { DragSource, DropTarget } from 'react-dnd' -import ParticipantProfilePopup from "../ParticipantProfilePopup"; -import {ParticipantTypes} from "../../constants/ParticipantTypes" -import SidebarMenu from "../../../../components/SidebarMenu/SidebarMenu"; -import ParticipantTrash from "./ParticipantTrash"; +import ParticipantProfilePopup from '../ParticipantProfilePopup' +import { ParticipantTypes } from '../../constants/ParticipantTypes' +import SidebarMenu from '../../../../components/SidebarMenu/SidebarMenu' +import ParticipantTrash from './ParticipantTrash' + +import { Drawer, MuiThemeProvider } from 'material-ui' const participantSidebarItemSource = { beginDrag(props) { - props.setCurrentlySelected(props.participantId); + props.setCurrentlySelected(props.participantId) return { participantId: props.participantId, oldGroupNumber: -1 - }; + } } -}; +} @DragSource(ParticipantTypes.UNGROUPED_PARTICIPANT, participantSidebarItemSource, (connect, monitor) => ({ connectDragSource: connect.dragSource(), @@ -31,13 +33,13 @@ class DraggableParticipantListItem extends React.Component { name: PropTypes.string.isRequired, image: PropTypes.string.isRequired, participantId: PropTypes.string.isRequired - }; + } - render() { - const {image, name, participantId, connectDragSource, isDragging} = this.props; + render () { + const {image, name, participantId, connectDragSource, isDragging} = this.props return connectDragSource(
+ style={ {visibility: isDragging ? 'hidden' : 'visible', cursor: 'move', padding: '7px'} }> { name } @@ -55,16 +57,16 @@ class Participant extends React.Component { groupNumber: PropTypes.number.isRequired, availability: PropTypes.array.isRequired, skills: PropTypes.array.isRequired, - }; + } - render() { + render () { const draggableParticipantListItem = ( - ); + ) return ( ( participants.filter((participantObj) => ( participantObj.groupNumber < 0 )).length - ); + ) let generateSidebarList = (participants) => ( @@ -168,10 +167,10 @@ class ParticipantListSidebar extends React.Component { )) } - ); + ) let generateEmailButton = () => ( -
+
All Grouped! @@ -179,14 +178,14 @@ class ParticipantListSidebar extends React.Component {
- ); + ) let generateEmptyMessage = () => ( -
+
Get a coffee @@ -194,37 +193,45 @@ class ParticipantListSidebar extends React.Component {
- ); + ) return connectDropTarget(
- -
- - { - (this.props.participants.length <= 0) ? - generateEmptyMessage() : - ((getUngroupedNumber(this.props.participants)) ? - generateSidebarList(this.props.participants) : - generateEmailButton()) - } - - - -
-
+ + + +
+ + { + (this.props.participants.length <= 0) ? generateEmptyMessage() : ((getUngroupedNumber(this.props.participants)) ? generateSidebarList(this.props.participants) : generateEmailButton()) + } + + {/* + + */} + +
+
+
) } } -export default ParticipantListSidebar; +export default ParticipantListSidebar diff --git a/src/routes/Activity/containers/ActivityContainer.js b/src/routes/Activity/containers/ActivityContainer.js index e3f629e..7a5e0d4 100644 --- a/src/routes/Activity/containers/ActivityContainer.js +++ b/src/routes/Activity/containers/ActivityContainer.js @@ -17,6 +17,7 @@ const mapDispatchToProps = (dispatch) => ({ generateGroupAssignment: Actions.generateGroupAssignmentActions.generateGroupAssignment(dispatch), sortParticipantsMatch: Actions.userMatchingActions.sortParticipants(dispatch), filterParticipantsMatch: Actions.userMatchingActions.filterParticipants(dispatch), + filterParticipants: Actions.filterParticipantsActions.filterParticipants(dispatch), createLocks: Actions.groupLockActions.createLocks(dispatch), toggleLock: Actions.groupLockActions.toggleLock(dispatch) }); @@ -28,7 +29,8 @@ const mapStateToProps = (state, ownProps) => { groupCapacity: state.activity.get("groupCapacity"), totalCapacity: state.activity.get("totalCapacity"), matching: state.activity.get("matching"), - unlocked: state.activity.get("unlocked") + unlocked: state.activity.get("unlocked"), + filter: state.activity.get("filter") } }; diff --git a/src/routes/Activity/modules/actions/filterParticipantsActions.js b/src/routes/Activity/modules/actions/filterParticipantsActions.js new file mode 100644 index 0000000..35825ac --- /dev/null +++ b/src/routes/Activity/modules/actions/filterParticipantsActions.js @@ -0,0 +1,11 @@ +/** + * Created by rui on 6/1/17. + */ +export const FILTER_PARTICIPANTS = "FILTER_PARTICIPANTS"; +let filterParticipants = ( dispatch ) => (payload) => { + dispatch({ type: FILTER_PARTICIPANTS, payload: payload }); +}; + +export { + filterParticipants +} \ No newline at end of file diff --git a/src/routes/Activity/modules/actions/index.js b/src/routes/Activity/modules/actions/index.js index 2899d0a..65a40d1 100644 --- a/src/routes/Activity/modules/actions/index.js +++ b/src/routes/Activity/modules/actions/index.js @@ -6,11 +6,13 @@ import * as updateParticipantGroupNumberActions from "./updateParticipantGroupNu import * as generateGroupAssignmentActions from "./generateGroupAssignmentActions" import * as userMatchingActions from "./userMatchingActions" import * as groupLockActions from "./groupLockActions" +import * as filterParticipantsActions from "./filterParticipantsActions" export { fetchParticipantListActions, updateParticipantGroupNumberActions, generateGroupAssignmentActions, userMatchingActions, - groupLockActions + groupLockActions, + filterParticipantsActions } \ No newline at end of file diff --git a/src/routes/Activity/modules/actions/userMatchingActions.js b/src/routes/Activity/modules/actions/userMatchingActions.js index 69ac7aa..38302e9 100644 --- a/src/routes/Activity/modules/actions/userMatchingActions.js +++ b/src/routes/Activity/modules/actions/userMatchingActions.js @@ -3,7 +3,7 @@ let sortParticipants = (participants) => { return {type: SORT_PARTICIPANTS, payload: participants }; }; -export const FILTER_PARTICIPANTS = "FILTER_PARTICIPANTS" +export const FILTER_PARTICIPANTS = "FILTER_PARTICIPANTS_useless" let filterParticipants = (dispatch) => { return (userId) => { dispatch({ type: FILTER_PARTICIPANTS, payload: userId }); diff --git a/src/routes/Activity/modules/reducer/actionsHandlers/filterParticipantsActionsHandlers.js b/src/routes/Activity/modules/reducer/actionsHandlers/filterParticipantsActionsHandlers.js new file mode 100644 index 0000000..c6b584a --- /dev/null +++ b/src/routes/Activity/modules/reducer/actionsHandlers/filterParticipantsActionsHandlers.js @@ -0,0 +1,11 @@ +/** + * Created by rui on 6/1/17. + */ + +let handleFilterParticipants = (state, payload) => { + return state.set("filter", payload); +}; + +export { + handleFilterParticipants, +} diff --git a/src/routes/Activity/modules/reducer/actionsHandlers/index.js b/src/routes/Activity/modules/reducer/actionsHandlers/index.js index 3adef97..8b51998 100644 --- a/src/routes/Activity/modules/reducer/actionsHandlers/index.js +++ b/src/routes/Activity/modules/reducer/actionsHandlers/index.js @@ -6,11 +6,13 @@ import * as generateGroupAssignmentActionsHandlers from "./generateGroupAssignme import * as updateParticipantGroupNumberActionsHandlers from "./updateParticipantGroupNumberActionsHandlers" import * as userMatchingActionsHandlers from "./userMatchingActionsHandlers" import * as groupLockActionsHandlers from "./groupLockActionsHandlers" +import * as filterParticipantsActionsHandlers from "./filterParticipantsActionsHandlers" export { fetchParticipantListActionsHandlers, generateGroupAssignmentActionsHandlers, updateParticipantGroupNumberActionsHandlers, userMatchingActionsHandlers, - groupLockActionsHandlers + groupLockActionsHandlers, + filterParticipantsActionsHandlers } diff --git a/src/routes/Activity/modules/reducer/reducer.js b/src/routes/Activity/modules/reducer/reducer.js index 29c00a7..62028ce 100644 --- a/src/routes/Activity/modules/reducer/reducer.js +++ b/src/routes/Activity/modules/reducer/reducer.js @@ -10,6 +10,7 @@ const initialState = Map({ groupCapacity: 0, totalCapacity: 0, unlocked: List([]), + filter: [], matching: Map({ current: "", matchingParticipants: new Set(), @@ -28,6 +29,9 @@ export default function activityReducer (state = initialState, action) { case Actions.groupLockActions.TOGGLE_LOCK: return ActionsHandlers.groupLockActionsHandlers.handleToggleLock(state, action.payload); + case Actions.filterParticipantsActions.FILTER_PARTICIPANTS: + return ActionsHandlers.filterParticipantsActionsHandlers.handleFilterParticipants(state, action.payload); + /* reduce userMatching */ case Actions.userMatchingActions.SORT_PARTICIPANTS: return ActionsHandlers.userMatchingActionsHandlers.handleSortParticipants(state, action.payload); diff --git a/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/ActivityCard.js b/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/ActivityCard.js index 0a7745c..3a10fd0 100644 --- a/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/ActivityCard.js +++ b/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/ActivityCard.js @@ -5,6 +5,8 @@ import React from 'react' import PropTypes from 'prop-types' import { Button, Card, Dropdown, Icon, Popup } from 'semantic-ui-react' +import CopyToClipboard from 'react-copy-to-clipboard'; + import EditActivityInfoModal from './EditActivityInfoModal' import DeleteActivityModal from './DeleteActivityModal' import { browserHistory } from 'react-router' @@ -39,7 +41,11 @@ export default class ActivityCard extends React.Component { browserHistory.push('/survey?id=' + this.props.activityId) } + render () { + + const surveyLink = 'http://' + window.location.host + '/survey?id=' + this.props.activityId; + return ( {/* modal components has to stay inside for style reason */} @@ -73,13 +79,16 @@ export default class ActivityCard extends React.Component { trigger={ window.open(surveyLink, '_blank' + )} name='file text outline'/> } position='top right' hoverable wide - >
http://address/survey?id=...
- + >
http://{window.location.host}/survey?id={this.props.activityId}
+ + + diff --git a/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/DeleteActivityModal/DeleteActivityModal.js b/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/DeleteActivityModal/DeleteActivityModal.js index baa391d..b7f814d 100644 --- a/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/DeleteActivityModal/DeleteActivityModal.js +++ b/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/DeleteActivityModal/DeleteActivityModal.js @@ -12,8 +12,6 @@ export default class DeleteActivityModal extends React.Component { } static propTypes = { - name: PropTypes.string.isRequired, - activityId: PropTypes.string.isRequired, onClose: PropTypes.func.isRequired }; diff --git a/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/EditActivityInfoModal/EditActivityInfoModal.js b/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/EditActivityInfoModal/EditActivityInfoModal.js index 4c4da0d..9c28021 100644 --- a/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/EditActivityInfoModal/EditActivityInfoModal.js +++ b/src/routes/Dashboard/components/ActivitiesView/components/ActivityCard/EditActivityInfoModal/EditActivityInfoModal.js @@ -53,7 +53,7 @@ export default class EditActivityInfoModal extends React.Component { render () { return ( - + Edit Activity { + this.props.updateActivityViewSelectingSurvey(false); this.props.updateActivityViewOpenCreateModal(false); } diff --git a/src/routes/Dashboard/components/ActivitiesView/components/CreateActivityCard/CreateActivityModal/CreateActivityModal.js b/src/routes/Dashboard/components/ActivitiesView/components/CreateActivityCard/CreateActivityModal/CreateActivityModal.js index bdd335d..dd60002 100644 --- a/src/routes/Dashboard/components/ActivitiesView/components/CreateActivityCard/CreateActivityModal/CreateActivityModal.js +++ b/src/routes/Dashboard/components/ActivitiesView/components/CreateActivityCard/CreateActivityModal/CreateActivityModal.js @@ -46,7 +46,26 @@ export default class Create extends React.Component { if (questionMissingType) { this.props.updateActivityFailedToCreate(true); - this.props.updateActivityCreateError('EACH QUESTION MUST HAVE A TYPE'); + this.props.updateActivityCreateError('QUESTION "' + + questionMissingType[1].get('title') + +'" MUST HAVE A TYPE'); + return; + } + + let questionMinHigherThanMax = this.props.surveyHolder.get('questions').findEntry((question) => { + return ( + question.get('answersEnableMinimum') && question.get('answersEnableMaximum') + && (question.get('answersMinimum') > question.get('answersMaximum')) + ) + } + ) + + if (questionMinHigherThanMax ) { + this.props.updateActivityFailedToCreate(true); + this.props.updateActivityCreateError('QUESTION "' + + questionMinHigherThanMax[1].get('title') + +'" MUST NOT HAVE A MAXIMUM ANSWER LIMIT THAT IS LOWER THAN THE MINIMUM ANSWER LIMIT' + ); return; } @@ -154,7 +173,7 @@ export default class Create extends React.Component { }) ); return ( - Create Activity @@ -187,6 +206,7 @@ export default class Create extends React.Component { {this.props.creatingSurvey ? 'New Survey' : 'Preview'} +
+ +
: null @@ -254,7 +276,7 @@ export default class Create extends React.Component { - ) + +
{this.props.title}
+
{this.props.tooltip}
+ {((this.props.answersEnableMinimum) && (this.props.answersEnableMaximum)) ? +
+ {'Must select at least ' + this.props.answersMinimum + + ' and at most ' + this.props.answersMaximum} +
+ : +
+ {(this.props.answersEnableMinimum) && + 'Must select at least ' + this.props.answersMinimum} + {(this.props.answersEnableMaximum) && + 'Must select at most ' + this.props.answersMaximum} +
+ } + { + this.props.answersFilter + .map(option => ( + { + (this.props.answers.has(option)) ? + this.props.removeAnswer( + this.props.index, option + ) + : + this.props.addAnswer( + this.props.index, option + ) + }}> + {option[0]} + + } + position='top center' + content={option} + /> ) - } -
- -
+ ) + } + ); } - - - } - -export default CircleSelectionQuestionView; +export default TimeAvailabilityQuestionView; diff --git a/src/routes/Survey/components/QuestionView/Questions/CircleSelectionQuestionView_.js b/src/routes/Survey/components/QuestionView/Questions/CircleSelectionQuestionView_.js new file mode 100644 index 0000000..227c46d --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/CircleSelectionQuestionView_.js @@ -0,0 +1,52 @@ +/** + * Created by Matt on 16/05/17. + */ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Label, Header, Button} from 'semantic-ui-react'; +import {Map, List, Set, OrderedSet} from 'immutable'; + +class CircleSelectionQuestionView extends React.Component { + render() { + return ( +
+ +
{this.props.title}
+
{this.props.tooltip}
+
+ { + this.props.answersFilter + .map(answer => ( + + ) + ) + } +
+
+
+ ); + } + + + +} + + +export default CircleSelectionQuestionView; diff --git a/src/routes/Survey/components/QuestionView/Questions/Constants/PROGRAMMING_LANGUAGES.js b/src/routes/Survey/components/QuestionView/Questions/Constants/PROGRAMMING_LANGUAGES.js new file mode 100644 index 0000000..9086bce --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/Constants/PROGRAMMING_LANGUAGES.js @@ -0,0 +1,693 @@ +const PROGRAMMING_LANGUAGES = [ + + {key: 'GAMS', value: 'GAMS', text: 'GAMS'}, + + {key: 'C#', value: 'C#', text: 'C#'}, + + {key: 'Ioke', value: 'Ioke', text: 'Ioke'}, + + {key: 'Inform 7', value: 'Inform 7', text: 'Inform 7'}, + + {key: 'Vala', value: 'Vala', text: 'Vala'}, + + {key: 'Opa', value: 'Opa', text: 'Opa'}, + + {key: 'ATS', value: 'ATS', text: 'ATS'}, + + {key: 'Kotlin', value: 'Kotlin', text: 'Kotlin'}, + + {key: 'AutoHotkey', value: 'AutoHotkey', text: 'AutoHotkey'}, + + {key: 'Idris', value: 'Idris', text: 'Idris'}, + + {key: 'Volt', value: 'Volt', text: 'Volt'}, + + {key: 'RenderScript', value: 'RenderScript', text: 'RenderScript'}, + + {key: 'ActionScript', value: 'ActionScript', text: 'ActionScript'}, + + {key: 'Hack', value: 'Hack', text: 'Hack'}, + + {key: 'Cap\'n Proto', value: 'Cap\'n Proto', text: 'Cap\'n Proto'}, + + {key: 'DTrace', value: 'DTrace', text: 'DTrace'}, + + {key: 'Apex', value: 'Apex', text: 'Apex'}, + + {key: 'Boo', value: 'Boo', text: 'Boo'}, + + {key: 'Game Maker Language', value: 'Game Maker Language', text: 'Game Maker Language'}, + + {key: 'Standard ML', value: 'Standard ML', text: 'Standard ML'}, + + {key: 'Java', value: 'Java', text: 'Java'}, + + {key: 'Literate Haskell', value: 'Literate Haskell', text: 'Literate Haskell'}, + + {key: 'UnrealScript', value: 'UnrealScript', text: 'UnrealScript'}, + + {key: 'C', value: 'C', text: 'C'}, + + {key: 'C++', value: 'C++', text: 'C++'}, + + {key: 'Harbour', value: 'Harbour', text: 'Harbour'}, + + {key: 'XSLT', value: 'XSLT', text: 'XSLT'}, + + {key: 'CSS', value: 'CSS', text: 'CSS'}, + + {key: 'PureScript', value: 'PureScript', text: 'PureScript'}, + + {key: 'Filterscript', value: 'Filterscript', text: 'Filterscript'}, + + {key: 'ooc', value: 'ooc', text: 'ooc'}, + + {key: 'CLIPS', value: 'CLIPS', text: 'CLIPS'}, + + {key: 'Agda', value: 'Agda', text: 'Agda'}, + + {key: 'SourcePawn', value: 'SourcePawn', text: 'SourcePawn'}, + + {key: 'JFlex', value: 'JFlex', text: 'JFlex'}, + + {key: 'Inno Setup', value: 'Inno Setup', text: 'Inno Setup'}, + + {key: 'Rust', value: 'Rust', text: 'Rust'}, + + {key: 'D', value: 'D', text: 'D'}, + + {key: 'Groff', value: 'Groff', text: 'Groff'}, + + {key: 'Dylan', value: 'Dylan', text: 'Dylan'}, + + {key: 'Smali', value: 'Smali', text: 'Smali'}, + + {key: 'Tcsh', value: 'Tcsh', text: 'Tcsh'}, + + {key: 'Max', value: 'Max', text: 'Max'}, + + {key: 'Mathematica', value: 'Mathematica', text: 'Mathematica'}, + + {key: 'Eagle', value: 'Eagle', text: 'Eagle'}, + + {key: 'Clojure', value: 'Clojure', text: 'Clojure'}, + + {key: 'RUNOFF', value: 'RUNOFF', text: 'RUNOFF'}, + + {key: 'NetLinx', value: 'NetLinx', text: 'NetLinx'}, + + {key: 'Genshi', value: 'Genshi', text: 'Genshi'}, + + {key: 'Augeas', value: 'Augeas', text: 'Augeas'}, + + {key: 'E', value: 'E', text: 'E'}, + + {key: 'Brightscript', value: 'Brightscript', text: 'Brightscript'}, + + {key: 'AppleScript', value: 'AppleScript', text: 'AppleScript'}, + + {key: 'Gentoo Ebuild', value: 'Gentoo Ebuild', text: 'Gentoo Ebuild'}, + + {key: 'TypeScript', value: 'TypeScript', text: 'TypeScript'}, + + {key: 'Coq', value: 'Coq', text: 'Coq'}, + + {key: 'Scheme', value: 'Scheme', text: 'Scheme'}, + + {key: 'Java Server Pages', value: 'Java Server Pages', text: 'Java Server Pages'}, + + {key: 'Oxygene', value: 'Oxygene', text: 'Oxygene'}, + + {key: 'GDB', value: 'GDB', text: 'GDB'}, + + {key: 'LSL', value: 'LSL', text: 'LSL'}, + + {key: 'KRL', value: 'KRL', text: 'KRL'}, + + {key: 'SAS', value: 'SAS', text: 'SAS'}, + + {key: 'Parrot Internal Representation', value: 'Parrot Internal Representation', text: 'Parrot Internal Representation'}, + + {key: 'BitBake', value: 'BitBake', text: 'BitBake'}, + + {key: 'Elm', value: 'Elm', text: 'Elm'}, + + {key: 'Scala', value: 'Scala', text: 'Scala'}, + + {key: 'Io', value: 'Io', text: 'Io'}, + + {key: 'Vue', value: 'Vue', text: 'Vue'}, + + {key: 'MTML', value: 'MTML', text: 'MTML'}, + + {key: 'Haxe', value: 'Haxe', text: 'Haxe'}, + + {key: 'Racket', value: 'Racket', text: 'Racket'}, + + {key: 'FreeMarker', value: 'FreeMarker', text: 'FreeMarker'}, + + {key: 'Assembly', value: 'Assembly', text: 'Assembly'}, + + {key: 'ShellSession', value: 'ShellSession', text: 'ShellSession'}, + + {key: 'Lean', value: 'Lean', text: 'Lean'}, + + {key: 'Cucumber', value: 'Cucumber', text: 'Cucumber'}, + + {key: 'SRecode Template', value: 'SRecode Template', text: 'SRecode Template'}, + + {key: 'M4', value: 'M4', text: 'M4'}, + + {key: 'Nu', value: 'Nu', text: 'Nu'}, + + {key: 'nesC', value: 'nesC', text: 'nesC'}, + + {key: 'ECLiPSe', value: 'ECLiPSe', text: 'ECLiPSe'}, + + {key: 'Metal', value: 'Metal', text: 'Metal'}, + + {key: 'Perl6', value: 'Perl6', text: 'Perl6'}, + + {key: 'TeX', value: 'TeX', text: 'TeX'}, + + {key: 'Logos', value: 'Logos', text: 'Logos'}, + + {key: 'GDScript', value: 'GDScript', text: 'GDScript'}, + + {key: 'Arduino', value: 'Arduino', text: 'Arduino'}, + + {key: 'ColdFusion', value: 'ColdFusion', text: 'ColdFusion'}, + + {key: 'ColdFusion CFC', value: 'ColdFusion CFC', text: 'ColdFusion CFC'}, + + {key: 'PAWN', value: 'PAWN', text: 'PAWN'}, + + {key: 'NetLogo', value: 'NetLogo', text: 'NetLogo'}, + + {key: 'Go', value: 'Go', text: 'Go'}, + + {key: 'Handlebars', value: 'Handlebars', text: 'Handlebars'}, + + {key: 'KiCad', value: 'KiCad', text: 'KiCad'}, + + {key: 'Click', value: 'Click', text: 'Click'}, + + {key: 'Yacc', value: 'Yacc', text: 'Yacc'}, + + {key: 'SQF', value: 'SQF', text: 'SQF'}, + + {key: 'TXL', value: 'TXL', text: 'TXL'}, + + {key: 'Cycript', value: 'Cycript', text: 'Cycript'}, + + {key: 'AMPL', value: 'AMPL', text: 'AMPL'}, + + {key: 'Literate CoffeeScript', value: 'Literate CoffeeScript', text: 'Literate CoffeeScript'}, + + {key: 'DM', value: 'DM', text: 'DM'}, + + {key: 'TLA', value: 'TLA', text: 'TLA'}, + + {key: 'Cython', value: 'Cython', text: 'Cython'}, + + {key: 'FLUX', value: 'FLUX', text: 'FLUX'}, + + {key: 'Ox', value: 'Ox', text: 'Ox'}, + + {key: 'Clean', value: 'Clean', text: 'Clean'}, + + {key: 'Fancy', value: 'Fancy', text: 'Fancy'}, + + {key: 'BlitzBasic', value: 'BlitzBasic', text: 'BlitzBasic'}, + + {key: 'Cool', value: 'Cool', text: 'Cool'}, + + {key: 'xBase', value: 'xBase', text: 'xBase'}, + + {key: 'Pony', value: 'Pony', text: 'Pony'}, + + {key: 'SQLPL', value: 'SQLPL', text: 'SQLPL'}, + + {key: 'Filebench WML', value: 'Filebench WML', text: 'Filebench WML'}, + + {key: 'J', value: 'J', text: 'J'}, + + {key: 'Makefile', value: 'Makefile', text: 'Makefile'}, + + {key: 'Gosu', value: 'Gosu', text: 'Gosu'}, + + {key: 'GCC Machine Description', value: 'GCC Machine Description', text: 'GCC Machine Description'}, + + {key: 'Eiffel', value: 'Eiffel', text: 'Eiffel'}, + + {key: 'PowerShell', value: 'PowerShell', text: 'PowerShell'}, + + {key: 'Golo', value: 'Golo', text: 'Golo'}, + + {key: 'PostScript', value: 'PostScript', text: 'PostScript'}, + + {key: 'Isabelle', value: 'Isabelle', text: 'Isabelle'}, + + {key: 'mupad', value: 'mupad', text: 'mupad'}, + + {key: 'Oz', value: 'Oz', text: 'Oz'}, + + {key: 'LFE', value: 'LFE', text: 'LFE'}, + + {key: 'XC', value: 'XC', text: 'XC'}, + + {key: 'Alloy', value: 'Alloy', text: 'Alloy'}, + + {key: 'HTML', value: 'HTML', text: 'HTML'}, + + {key: 'Bison', value: 'Bison', text: 'Bison'}, + + {key: 'Pascal', value: 'Pascal', text: 'Pascal'}, + + {key: 'EQ', value: 'EQ', text: 'EQ'}, + + {key: 'Glyph', value: 'Glyph', text: 'Glyph'}, + + {key: 'Omgrofl', value: 'Omgrofl', text: 'Omgrofl'}, + + {key: 'Opal', value: 'Opal', text: 'Opal'}, + + {key: 'Grammatical Framework', value: 'Grammatical Framework', text: 'Grammatical Framework'}, + + {key: 'XPages', value: 'XPages', text: 'XPages'}, + + {key: 'Rebol', value: 'Rebol', text: 'Rebol'}, + + {key: 'Csound', value: 'Csound', text: 'Csound'}, + + {key: 'LoomScript', value: 'LoomScript', text: 'LoomScript'}, + + {key: 'Zephir', value: 'Zephir', text: 'Zephir'}, + + {key: 'Mask', value: 'Mask', text: 'Mask'}, + + {key: 'MoonScript', value: 'MoonScript', text: 'MoonScript'}, + + {key: 'OCaml', value: 'OCaml', text: 'OCaml'}, + + {key: 'Self', value: 'Self', text: 'Self'}, + + {key: 'Sage', value: 'Sage', text: 'Sage'}, + + {key: 'M', value: 'M', text: 'M'}, + + {key: 'Matlab', value: 'Matlab', text: 'Matlab'}, + + {key: 'Stata', value: 'Stata', text: 'Stata'}, + + {key: 'Brainfuck', value: 'Brainfuck', text: 'Brainfuck'}, + + {key: 'ANTLR', value: 'ANTLR', text: 'ANTLR'}, + + {key: 'JavaScript', value: 'JavaScript', text: 'JavaScript'}, + + {key: 'Modula-2', value: 'Modula-2', text: 'Modula-2'}, + + {key: 'MiniD', value: 'MiniD', text: 'MiniD'}, + + {key: 'API Blueprint', value: 'API Blueprint', text: 'API Blueprint'}, + + {key: 'RAML', value: 'RAML', text: 'RAML'}, + + {key: 'Groovy', value: 'Groovy', text: 'Groovy'}, + + {key: 'EJS', value: 'EJS', text: 'EJS'}, + + {key: 'C2hs Haskell', value: 'C2hs Haskell', text: 'C2hs Haskell'}, + + {key: 'Sass', value: 'Sass', text: 'Sass'}, + + {key: 'IGOR Pro', value: 'IGOR Pro', text: 'IGOR Pro'}, + + {key: 'Jupyter Notebook', value: 'Jupyter Notebook', text: 'Jupyter Notebook'}, + + {key: 'NetLinx+ERB', value: 'NetLinx+ERB', text: 'NetLinx+ERB'}, + + {key: 'Stan', value: 'Stan', text: 'Stan'}, + + {key: 'Clarion', value: 'Clarion', text: 'Clarion'}, + + {key: 'Visual Basic', value: 'Visual Basic', text: 'Visual Basic'}, + + {key: 'ECL', value: 'ECL', text: 'ECL'}, + + {key: 'XProc', value: 'XProc', text: 'XProc'}, + + {key: 'NumPy', value: 'NumPy', text: 'NumPy'}, + + {key: 'JSX', value: 'JSX', text: 'JSX'}, + + {key: 'Csound Document', value: 'Csound Document', text: 'Csound Document'}, + + {key: 'SuperCollider', value: 'SuperCollider', text: 'SuperCollider'}, + + {key: 'Cuda', value: 'Cuda', text: 'Cuda'}, + + {key: 'Objective-C', value: 'Objective-C', text: 'Objective-C'}, + + {key: 'wisp', value: 'wisp', text: 'wisp'}, + + {key: 'Component Pascal', value: 'Component Pascal', text: 'Component Pascal'}, + + {key: 'Factor', value: 'Factor', text: 'Factor'}, + + {key: 'POV-Ray SDL', value: 'POV-Ray SDL', text: 'POV-Ray SDL'}, + + {key: 'Common Lisp', value: 'Common Lisp', text: 'Common Lisp'}, + + {key: 'NSIS', value: 'NSIS', text: 'NSIS'}, + + {key: 'Objective-C++', value: 'Objective-C++', text: 'Objective-C++'}, + + {key: 'Gnuplot', value: 'Gnuplot', text: 'Gnuplot'}, + + {key: '1C Enterprise', value: '1C Enterprise', text: '1C Enterprise'}, + + {key: 'Perl', value: 'Perl', text: 'Perl'}, + + {key: 'SystemVerilog', value: 'SystemVerilog', text: 'SystemVerilog'}, + + {key: 'MAXScript', value: 'MAXScript', text: 'MAXScript'}, + + {key: 'Gentoo Eclass', value: 'Gentoo Eclass', text: 'Gentoo Eclass'}, + + {key: 'Cirru', value: 'Cirru', text: 'Cirru'}, + + {key: 'M4Sugar', value: 'M4Sugar', text: 'M4Sugar'}, + + {key: 'ABAP', value: 'ABAP', text: 'ABAP'}, + + {key: 'JSONiq', value: 'JSONiq', text: 'JSONiq'}, + + {key: 'Latte', value: 'Latte', text: 'Latte'}, + + {key: 'SCSS', value: 'SCSS', text: 'SCSS'}, + + {key: 'Parrot Assembly', value: 'Parrot Assembly', text: 'Parrot Assembly'}, + + {key: 'REALbasic', value: 'REALbasic', text: 'REALbasic'}, + + {key: 'QML', value: 'QML', text: 'QML'}, + + {key: 'Logtalk', value: 'Logtalk', text: 'Logtalk'}, + + {key: 'Terra', value: 'Terra', text: 'Terra'}, + + {key: 'Shell', value: 'Shell', text: 'Shell'}, + + {key: 'HyPhy', value: 'HyPhy', text: 'HyPhy'}, + + {key: 'XQuery', value: 'XQuery', text: 'XQuery'}, + + {key: 'Smarty', value: 'Smarty', text: 'Smarty'}, + + {key: 'Turing', value: 'Turing', text: 'Turing'}, + + {key: 'Red', value: 'Red', text: 'Red'}, + + {key: 'CMake', value: 'CMake', text: 'CMake'}, + + {key: 'Hy', value: 'Hy', text: 'Hy'}, + + {key: 'IDL', value: 'IDL', text: 'IDL'}, + + {key: 'HCL', value: 'HCL', text: 'HCL'}, + + {key: 'OpenRC runscript', value: 'OpenRC runscript', text: 'OpenRC runscript'}, + + {key: 'Emacs Lisp', value: 'Emacs Lisp', text: 'Emacs Lisp'}, + + {key: 'R', value: 'R', text: 'R'}, + + {key: 'LabVIEW', value: 'LabVIEW', text: 'LabVIEW'}, + + {key: 'Apollo Guidance Computer', value: 'Apollo Guidance Computer', text: 'Apollo Guidance Computer'}, + + {key: 'Arc', value: 'Arc', text: 'Arc'}, + + {key: 'PLSQL', value: 'PLSQL', text: 'PLSQL'}, + + {key: 'Alpine Abuild', value: 'Alpine Abuild', text: 'Alpine Abuild'}, + + {key: 'EmberScript', value: 'EmberScript', text: 'EmberScript'}, + + {key: 'AspectJ', value: 'AspectJ', text: 'AspectJ'}, + + {key: 'Myghty', value: 'Myghty', text: 'Myghty'}, + + {key: 'PogoScript', value: 'PogoScript', text: 'PogoScript'}, + + {key: 'VimL', value: 'VimL', text: 'VimL'}, + + {key: 'SaltStack', value: 'SaltStack', text: 'SaltStack'}, + + {key: 'Pure Data', value: 'Pure Data', text: 'Pure Data'}, + + {key: 'OpenEdge ABL', value: 'OpenEdge ABL', text: 'OpenEdge ABL'}, + + {key: 'OpenCL', value: 'OpenCL', text: 'OpenCL'}, + + {key: 'REXX', value: 'REXX', text: 'REXX'}, + + {key: 'Pike', value: 'Pike', text: 'Pike'}, + + {key: 'COBOL', value: 'COBOL', text: 'COBOL'}, + + {key: 'Swift', value: 'Swift', text: 'Swift'}, + + {key: 'Smalltalk', value: 'Smalltalk', text: 'Smalltalk'}, + + {key: 'Mercury', value: 'Mercury', text: 'Mercury'}, + + {key: 'Processing', value: 'Processing', text: 'Processing'}, + + {key: 'Propeller Spin', value: 'Propeller Spin', text: 'Propeller Spin'}, + + {key: 'Monkey', value: 'Monkey', text: 'Monkey'}, + + {key: 'Dogescript', value: 'Dogescript', text: 'Dogescript'}, + + {key: 'Haskell', value: 'Haskell', text: 'Haskell'}, + + {key: 'Puppet', value: 'Puppet', text: 'Puppet'}, + + {key: 'CartoCSS', value: 'CartoCSS', text: 'CartoCSS'}, + + {key: 'RobotFramework', value: 'RobotFramework', text: 'RobotFramework'}, + + {key: 'Ragel in Ruby Host', value: 'Ragel in Ruby Host', text: 'Ragel in Ruby Host'}, + + {key: 'Scilab', value: 'Scilab', text: 'Scilab'}, + + {key: 'FORTRAN', value: 'FORTRAN', text: 'FORTRAN'}, + + {key: 'Ceylon', value: 'Ceylon', text: 'Ceylon'}, + + {key: 'Literate Agda', value: 'Literate Agda', text: 'Literate Agda'}, + + {key: 'DIGITAL Command Language', value: 'DIGITAL Command Language', text: 'DIGITAL Command Language'}, + + {key: 'Ren\'Py', value: 'Ren\'Py', text: 'Ren\'Py'}, + + {key: 'Nimrod', value: 'Nimrod', text: 'Nimrod'}, + + {key: 'Awk', value: 'Awk', text: 'Awk'}, + + {key: 'Bluespec', value: 'Bluespec', text: 'Bluespec'}, + + {key: 'Papyrus', value: 'Papyrus', text: 'Papyrus'}, + + {key: 'LOLCODE', value: 'LOLCODE', text: 'LOLCODE'}, + + {key: 'Rouge', value: 'Rouge', text: 'Rouge'}, + + {key: 'Objective-J', value: 'Objective-J', text: 'Objective-J'}, + + {key: 'Uno', value: 'Uno', text: 'Uno'}, + + {key: 'Parrot', value: 'Parrot', text: 'Parrot'}, + + {key: 'PigLatin', value: 'PigLatin', text: 'PigLatin'}, + + {key: 'GAP', value: 'GAP', text: 'GAP'}, + + {key: 'Jasmin', value: 'Jasmin', text: 'Jasmin'}, + + {key: 'PowerBuilder', value: 'PowerBuilder', text: 'PowerBuilder'}, + + {key: 'Crystal', value: 'Crystal', text: 'Crystal'}, + + {key: 'Batchfile', value: 'Batchfile', text: 'Batchfile'}, + + {key: 'PureBasic', value: 'PureBasic', text: 'PureBasic'}, + + {key: 'LLVM', value: 'LLVM', text: 'LLVM'}, + + {key: 'X10', value: 'X10', text: 'X10'}, + + {key: 'LiveScript', value: 'LiveScript', text: 'LiveScript'}, + + {key: 'NCL', value: 'NCL', text: 'NCL'}, + + {key: 'Prolog', value: 'Prolog', text: 'Prolog'}, + + {key: 'Isabelle ROOT', value: 'Isabelle ROOT', text: 'Isabelle ROOT'}, + + {key: 'UrWeb', value: 'UrWeb', text: 'UrWeb'}, + + {key: 'Frege', value: 'Frege', text: 'Frege'}, + + {key: 'CoffeeScript', value: 'CoffeeScript', text: 'CoffeeScript'}, + + {key: 'Module Management System', value: 'Module Management System', text: 'Module Management System'}, + + {key: 'Haml', value: 'Haml', text: 'Haml'}, + + {key: 'ChucK', value: 'ChucK', text: 'ChucK'}, + + {key: 'PHP', value: 'PHP', text: 'PHP'}, + + {key: 'Charity', value: 'Charity', text: 'Charity'}, + + {key: 'Mako', value: 'Mako', text: 'Mako'}, + + {key: 'fish', value: 'fish', text: 'fish'}, + + {key: 'Grace', value: 'Grace', text: 'Grace'}, + + {key: 'Lua', value: 'Lua', text: 'Lua'}, + + {key: 'Unified Parallel C', value: 'Unified Parallel C', text: 'Unified Parallel C'}, + + {key: 'Julia', value: 'Julia', text: 'Julia'}, + + {key: 'Less', value: 'Less', text: 'Less'}, + + {key: 'Thrift', value: 'Thrift', text: 'Thrift'}, + + {key: 'Nit', value: 'Nit', text: 'Nit'}, + + {key: 'GAS', value: 'GAS', text: 'GAS'}, + + {key: 'Groovy Server Pages', value: 'Groovy Server Pages', text: 'Groovy Server Pages'}, + + {key: 'Squirrel', value: 'Squirrel', text: 'Squirrel'}, + + {key: 'Befunge', value: 'Befunge', text: 'Befunge'}, + + {key: 'Lasso', value: 'Lasso', text: 'Lasso'}, + + {key: 'SMT', value: 'SMT', text: 'SMT'}, + + {key: 'Zimpl', value: 'Zimpl', text: 'Zimpl'}, + + {key: 'Ruby', value: 'Ruby', text: 'Ruby'}, + + {key: 'NewLisp', value: 'NewLisp', text: 'NewLisp'}, + + {key: 'Moocode', value: 'Moocode', text: 'Moocode'}, + + {key: 'VHDL', value: 'VHDL', text: 'VHDL'}, + + {key: 'AutoIt', value: 'AutoIt', text: 'AutoIt'}, + + {key: 'Nginx', value: 'Nginx', text: 'Nginx'}, + + {key: 'Erlang', value: 'Erlang', text: 'Erlang'}, + + {key: 'XS', value: 'XS', text: 'XS'}, + + {key: 'Chapel', value: 'Chapel', text: 'Chapel'}, + + {key: 'PLpgSQL', value: 'PLpgSQL', text: 'PLpgSQL'}, + + {key: 'Python', value: 'Python', text: 'Python'}, + + {key: 'Nemerle', value: 'Nemerle', text: 'Nemerle'}, + + {key: 'Xojo', value: 'Xojo', text: 'Xojo'}, + + {key: 'Pan', value: 'Pan', text: 'Pan'}, + + {key: 'F#', value: 'F#', text: 'F#'}, + + {key: 'Mirah', value: 'Mirah', text: 'Mirah'}, + + {key: 'Forth', value: 'Forth', text: 'Forth'}, + + {key: 'Web Ontology Language', value: 'Web Ontology Language', text: 'Web Ontology Language'}, + + {key: 'Slash', value: 'Slash', text: 'Slash'}, + + {key: 'Slim', value: 'Slim', text: 'Slim'}, + + {key: 'Nix', value: 'Nix', text: 'Nix'}, + + {key: 'APL', value: 'APL', text: 'APL'}, + + {key: 'HLSL', value: 'HLSL', text: 'HLSL'}, + + {key: 'Limbo', value: 'Limbo', text: 'Limbo'}, + + {key: 'WebIDL', value: 'WebIDL', text: 'WebIDL'}, + + {key: 'Tcl', value: 'Tcl', text: 'Tcl'}, + + {key: 'OpenSCAD', value: 'OpenSCAD', text: 'OpenSCAD'}, + + {key: 'Verilog', value: 'Verilog', text: 'Verilog'}, + + {key: 'Ada', value: 'Ada', text: 'Ada'}, + + {key: 'eC', value: 'eC', text: 'eC'}, + + {key: 'LookML', value: 'LookML', text: 'LookML'}, + + {key: 'Shen', value: 'Shen', text: 'Shen'}, + + {key: 'Redcode', value: 'Redcode', text: 'Redcode'}, + + {key: 'GLSL', value: 'GLSL', text: 'GLSL'}, + + {key: 'ASP', value: 'ASP', text: 'ASP'}, + + {key: 'Modelica', value: 'Modelica', text: 'Modelica'}, + + {key: 'AGS Script', value: 'AGS Script', text: 'AGS Script'}, + + {key: 'MUF', value: 'MUF', text: 'MUF'}, + + {key: 'Csound Score', value: 'Csound Score', text: 'Csound Score'}, + + {key: 'Xtend', value: 'Xtend', text: 'Xtend'}, + + {key: 'ASN.1', value: 'ASN.1', text: 'ASN.1'}, + + {key: 'Fantom', value: 'Fantom', text: 'Fantom'}, + + {key: 'QMake', value: 'QMake', text: 'QMake'}, + + {key: 'Bro', value: 'Bro', text: 'Bro'}, + + {key: 'Lex', value: 'Lex', text: 'Lex'}, + + {key: 'PicoLisp', value: 'PicoLisp', text: 'PicoLisp'}, + + {key: 'LilyPond', value: 'LilyPond', text: 'LilyPond'}, + + {key: 'BlitzMax', value: 'BlitzMax', text: 'BlitzMax'}, + + {key: 'VCL', value: 'VCL', text: 'VCL'}, + + {key: 'Dart', value: 'Dart', text: 'Dart'}, + + {key: 'Elixir', value: 'Elixir', text: 'Elixir'}, + +]; + +export default PROGRAMMING_LANGUAGES; diff --git a/src/routes/Survey/components/QuestionView/Questions/Constants/index.js b/src/routes/Survey/components/QuestionView/Questions/Constants/index.js new file mode 100644 index 0000000..8073b10 --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/Constants/index.js @@ -0,0 +1,3 @@ +import PROGRAMMING_LANGUAGES from './PROGRAMMING_LANGUAGES' + +export default PROGRAMMING_LANGUAGES; diff --git a/src/routes/Survey/components/QuestionView/Questions/EmailQuestionView.js b/src/routes/Survey/components/QuestionView/Questions/EmailQuestionView.js new file mode 100644 index 0000000..ff6071e --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/EmailQuestionView.js @@ -0,0 +1,34 @@ +/** + * Created by Matt on 16/05/17. + */ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Label, Header, Button, Input} from 'semantic-ui-react'; +import {Map, List, Set, OrderedSet} from 'immutable'; + +class SingleInputTextFieldQuestionView extends React.Component { + render() { + return ( +
+ +
{this.props.title}
+
{this.props.tooltip}
+
+ { + this.props.setEmail(event.target.value) + }} + /> +
+
+
+ ); + } + + + +} + + +export default SingleInputTextFieldQuestionView; diff --git a/src/routes/Survey/components/QuestionView/Questions/MultiInputTextFieldQuestionView.js b/src/routes/Survey/components/QuestionView/Questions/MultiInputTextFieldQuestionView.js index 28b59d2..0f95b3a 100644 --- a/src/routes/Survey/components/QuestionView/Questions/MultiInputTextFieldQuestionView.js +++ b/src/routes/Survey/components/QuestionView/Questions/MultiInputTextFieldQuestionView.js @@ -3,25 +3,65 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import {Label, Header, Button, Input} from 'semantic-ui-react'; +import {Label, Header, Button, Input, Dropdown} from 'semantic-ui-react'; import {Map, List, Set, OrderedSet} from 'immutable'; class MultiInputTextFieldQuestionView extends React.Component { render() { + let answersFilterOptions = []; + + this.props.answersFilter.forEach((filter) => { + answersFilterOptions.push({ + key:filter, + value:filter, + text:filter, + }) + }); + + this.props.answers.forEach((answer) => { + answersFilterOptions.push({ + key:answer, + value:answer, + text:answer, + }) + }); + return (
{this.props.title}
{this.props.tooltip}
+ {((this.props.answersEnableMinimum) && (this.props.answersEnableMaximum)) ? +
+ {'Must select at least ' + this.props.answersMinimum + + ' and at most ' + this.props.answersMaximum} +
+ : +
+ {(this.props.answersEnableMinimum) && + 'Must select at least ' + this.props.answersMinimum} + {(this.props.answersEnableMaximum) && + 'Must select at most ' + this.props.answersMaximum} +
+ }
- { - this.props.clearSurveyQuestionAnswers(this.props.type, this.props.title); - event.target.value.split(',').map(entry => { - entry.trim().length !== 0 - && - this.props.addSurveyQuestionAnswer(this.props.type, this.props.title, entry.trim()) - } ) - }}/> + { + this.props.setAnswer(this.props.index, Set(data.value)); + }} + onAddItem={(e, data) => { + this.props.addAnswer(this.props.index, data.value) + }} + />
diff --git a/src/routes/Survey/components/QuestionView/Questions/MultiInputTextFieldQuestionView_.js b/src/routes/Survey/components/QuestionView/Questions/MultiInputTextFieldQuestionView_.js new file mode 100644 index 0000000..28b59d2 --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/MultiInputTextFieldQuestionView_.js @@ -0,0 +1,36 @@ +/** + * Created by Matt on 16/05/17. + */ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Label, Header, Button, Input} from 'semantic-ui-react'; +import {Map, List, Set, OrderedSet} from 'immutable'; + +class MultiInputTextFieldQuestionView extends React.Component { + render() { + return ( +
+ +
{this.props.title}
+
{this.props.tooltip}
+
+ { + this.props.clearSurveyQuestionAnswers(this.props.type, this.props.title); + event.target.value.split(',').map(entry => { + entry.trim().length !== 0 + && + this.props.addSurveyQuestionAnswer(this.props.type, this.props.title, entry.trim()) + } ) + }}/> +
+
+
+ ); + } + + + +} + + +export default MultiInputTextFieldQuestionView; diff --git a/src/routes/Survey/components/QuestionView/Questions/NameQuestionView.js b/src/routes/Survey/components/QuestionView/Questions/NameQuestionView.js new file mode 100644 index 0000000..d033e6c --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/NameQuestionView.js @@ -0,0 +1,34 @@ +/** + * Created by Matt on 16/05/17. + */ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Label, Header, Button, Input} from 'semantic-ui-react'; +import {Map, List, Set, OrderedSet} from 'immutable'; + +class SingleInputTextFieldQuestionView extends React.Component { + render() { + return ( +
+ +
{this.props.title}
+
{this.props.tooltip}
+
+ { + this.props.setName(event.target.value) + }} + /> +
+
+
+ ); + } + + + +} + + +export default SingleInputTextFieldQuestionView; diff --git a/src/routes/Survey/components/QuestionView/Questions/ProgrammingLanguagesQuestionView.js b/src/routes/Survey/components/QuestionView/Questions/ProgrammingLanguagesQuestionView.js new file mode 100644 index 0000000..7695f12 --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/ProgrammingLanguagesQuestionView.js @@ -0,0 +1,54 @@ +/** + * Created by Matt on 16/05/17. + */ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Label, Header, Button, Input, Dropdown} from 'semantic-ui-react'; +import {Map, List, Set, OrderedSet} from 'immutable'; +import PROGRAMMING_LANGUAGES from './Constants' + +class ProgrammingLanguagesQuestionView extends React.Component { + render() { + return ( +
+ +
{this.props.title}
+
{this.props.tooltip}
+ {((this.props.answersEnableMinimum) && (this.props.answersEnableMaximum)) ? +
+ {'Must select at least ' + this.props.answersMinimum + + ' and at most ' + this.props.answersMaximum} +
+ : +
+ {(this.props.answersEnableMinimum) && + 'Must select at least ' + this.props.answersMinimum} + {(this.props.answersEnableMaximum) && + 'Must select at most ' + this.props.answersMaximum} +
+ } +
+ { + this.props.setAnswer(this.props.index, Set(data.value)); + }} + /> +
+
+
+ ); + } + + + +} + + +export default ProgrammingLanguagesQuestionView; diff --git a/src/routes/Survey/components/QuestionView/Questions/SingleInputTextFieldQuestionView_.js b/src/routes/Survey/components/QuestionView/Questions/SingleInputTextFieldQuestionView_.js new file mode 100644 index 0000000..77ab40e --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/SingleInputTextFieldQuestionView_.js @@ -0,0 +1,32 @@ +/** + * Created by Matt on 16/05/17. + */ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Label, Header, Button, Input} from 'semantic-ui-react'; +import {Map, List, Set, OrderedSet} from 'immutable'; + +class SingleInputTextFieldQuestionView extends React.Component { + render() { + return ( +
+ +
{this.props.title}
+
{this.props.tooltip}
+
+ { + this.props.clearSurveyQuestionAnswers(this.props.type, this.props.title); + this.props.addSurveyQuestionAnswer(this.props.type, this.props.title, event.target.value.trim()); + }}/> +
+
+
+ ); + } + + + +} + + +export default SingleInputTextFieldQuestionView; diff --git a/src/routes/Survey/components/QuestionView/Questions/TimeAvailabilityQuestionView.js b/src/routes/Survey/components/QuestionView/Questions/TimeAvailabilityQuestionView.js new file mode 100644 index 0000000..8b941e0 --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/TimeAvailabilityQuestionView.js @@ -0,0 +1,66 @@ +/** + * Created by Matt on 16/05/17. + */ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Label, Header, Button, Popup, Segment} from 'semantic-ui-react'; +import {Map, List, Set, OrderedSet} from 'immutable'; + +const weekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + +class TimeAvailabilityQuestionView extends React.Component { + render() { + return ( + +
{this.props.title}
+
{this.props.tooltip}
+ {((this.props.answersEnableMinimum) && (this.props.answersEnableMaximum)) ? +
+ {'Must select at least ' + this.props.answersMinimum + + ' and at most ' + this.props.answersMaximum} +
+ : +
+ {(this.props.answersEnableMinimum) && + 'Must select at least ' + this.props.answersMinimum} + {(this.props.answersEnableMaximum) && + 'Must select at most ' + this.props.answersMaximum} +
+ } + { + weekDays + .map(day => ( + { + (this.props.answers.has(day)) ? + this.props.removeAnswer( + this.props.index, day + ) + : + this.props.addAnswer( + this.props.index, day + ) + }}> + {day[0]} + + } + position='top center' + content={day} + /> + ) + ) + } +
+ ); + } +} + +export default TimeAvailabilityQuestionView; diff --git a/src/routes/Survey/components/QuestionView/Questions/index.js b/src/routes/Survey/components/QuestionView/Questions/index.js index a30684d..4591017 100644 --- a/src/routes/Survey/components/QuestionView/Questions/index.js +++ b/src/routes/Survey/components/QuestionView/Questions/index.js @@ -1,16 +1,19 @@ /** * Created by Matt on 05/16/17. */ -import CircleSelectionQuestionView from "./CircleSelectionQuestionView" -import MultiInputTextFieldQuestionView from "./MultiInputTextFieldQuestionView" -import SingleInputTextFieldQuestionView from "./SingleInputTextFieldQuestionView" -import testQuestionView from "./testQuestionView" +import NameQuestionView from "./NameQuestionView" +import EmailQuestionView from "./EmailQuestionView" +import TimeAvailabilityQuestionView from "./TimeAvailabilityQuestionView" +import ProgrammingLanguagesQuestionView from "./ProgrammingLanguagesQuestionView" +import MultiInputTextFieldQuestionView from "./MultiInputTextFieldQuestionView" +import CircleSelectionQuestionView from "./CircleSelectionQuestionView" export { - CircleSelectionQuestionView, - MultiInputTextFieldQuestionView, - SingleInputTextFieldQuestionView, - - testQuestionView, + NameQuestionView, + EmailQuestionView, + TimeAvailabilityQuestionView, + ProgrammingLanguagesQuestionView, + MultiInputTextFieldQuestionView, + CircleSelectionQuestionView, } diff --git a/src/routes/Survey/components/QuestionView/Questions/testQuestionView_.js b/src/routes/Survey/components/QuestionView/Questions/testQuestionView_.js new file mode 100644 index 0000000..e434041 --- /dev/null +++ b/src/routes/Survey/components/QuestionView/Questions/testQuestionView_.js @@ -0,0 +1,141 @@ +/** + * Created by Matt on 16/05/17. + */ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Label, Header, Button, Input, Checkbox, Dropdown} from 'semantic-ui-react'; +import {Map, List, Set, OrderedSet} from 'immutable'; + +import jwt from 'jsonwebtoken'; +import axios from 'axios' +import setAuthorizationToken from '../../../../../components/utils/setAuthorizationToken'; +import { setCurrentUser } from "../../../../../routes/Login/modules/actions/authActions" + +const SERVER_URL = "http://"+window.location.host; + +let input_1_test = ""; +let input_2_test = ""; +let input_3_test = ""; +let input_4_test = 0; +let input_5_test = 0; + +class testQuestionView extends React.Component { + render() { + return ( +
+
+ {input_1_test = data.value; console.log(input_1_test);}}/> + +
+ +
+ {input_2_test = event.target.value;}} /> +
+ +
+ {input_3_test = event.target.value;}} /> +
+ +
+ + +
+ +
+ {this.props.setSurveyQuestionAnswersMaximum(input_1_test, input_2_test, event.target.value);}} /> + { + (this.props.answersEnableMaximum) ? + this.props.disableSurveyQuestionAnswersMaximum(input_1_test, input_2_test) + : + this.props.enableSurveyQuestionAnswersMaximum(input_1_test, input_2_test) + }} + checked={this.props.answersEnableMaximum} /> +
+ +
+ {this.props.setSurveyQuestionAnswersMinimum(input_1_test, input_2_test, event.target.value);}} /> + { + (this.props.answersEnableMinimum) ? + this.props.disableSurveyQuestionAnswersMinimum(input_1_test, input_2_test) + : + this.props.enableSurveyQuestionAnswersMinimum(input_1_test, input_2_test) + }} + checked={this.props.answersEnableMinimum} /> +
+
+ { + this.props.clearSurveyQuestionAnswersFilters(this.props.type, this.props.title); + event.target.value.split(',').map(entry => { + entry.trim().length !== 0 + && + this.props.addSurveyQuestionAnswersFilter(this.props.type, this.props.title, entry.trim()) + } ) + }} /> + { + (this.props.answersEnableFilter) ? + this.props.disableSurveyQuestionAnswersFilter(input_1_test, input_2_test) + : + this.props.enableSurveyQuestionAnswersFilter(input_1_test, input_2_test) + }} + checked={this.props.answersEnableFilter} /> + { + (this.props.answersFilterEnableBlacklistMode) ? + this.props.disableSurveyQuestionAnswersFilterBlacklistMode(input_1_test, input_2_test) + : + this.props.enableSurveyQuestionAnswersFilterBlacklistMode(input_1_test, input_2_test) + }} + checked={this.props.answersEnableFilterBlacklistMode} /> +
+
+ +
+
+ +
+ +
+ ); + } +} + + +export default testQuestionView; diff --git a/src/routes/Survey/components/SurveyView.js b/src/routes/Survey/components/SurveyView.js index 9bec3c3..e70ad69 100644 --- a/src/routes/Survey/components/SurveyView.js +++ b/src/routes/Survey/components/SurveyView.js @@ -1,15 +1,140 @@ import React from 'react' -import {Grid, Card, Label, Button} from 'semantic-ui-react' +import {Grid, Card, Label, Button, Segment, Header, Icon, Divider, Message} from 'semantic-ui-react' import QuestionView from './QuestionView' +import {NameQuestionView, EmailQuestionView} from './QuestionView/Questions' import {Map, List, Set, OrderedSet} from 'immutable'; class Survey extends React.Component { + + componentWillMount () { + this.props.fetchSurvey(this.props.activityId); + } + + //from https://stackoverflow.com/questions/46155/validate-email-address-in-javascript + validateEmail = (email) => { + var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(email); + } + + submitSurveyHandler = (e) => { + + this.props.setIsSubmitting(true); + if (this.props.name.trim().length <= 0){ + this.props.setSubmitError('You Must Enter Your Name'); + this.props.setFailedToSubmit(true); + this.props.setIsSubmitting(false); + return; + }; + + if (!this.validateEmail(this.props.email)){ + this.props.setSubmitError('You Must Enter a Valid Email!'); + this.props.setFailedToSubmit(true); + this.props.setIsSubmitting(false); + return; + }; + + let invalidMinimumAnswer= this.props.questions.findEntry((question) => { + return (question.get('answersEnableMinimum')) + && (question.get('answers').size < question.get('answersMinimum')); + }); + + if (invalidMinimumAnswer){ + this.props.setSubmitError('Question [' + + invalidMinimumAnswer[1].get('title') + +'] Requires a Minimum of ' + + invalidMinimumAnswer[1].get('answersMinimum') + + ' Answers!' + ); + this.props.setIsSubmitting(false); + this.props.setFailedToSubmit(true); + return; + }; + + let invalidMaximumAnswer= this.props.questions.findEntry((question) => { + return (question.get('answersEnableMaximum')) + && (question.get('answers').size > question.get('answersMaximum')); + }); + + if (invalidMaximumAnswer){ + this.props.setSubmitError('Question [' + + invalidMaximumAnswer[1].get('title') + +'] May have a Maximum of ' + + invalidMaximumAnswer[1].get('answersMaximum') + + ' Answers!' + ); + this.props.setIsSubmitting(false); + this.props.setFailedToSubmit(true); + return; + }; + + this.props.setIsSubmitting(false); + this.props.setSubmitError(''); + this.props.setFailedToSubmit(false); + this.props.submitSurvey({activityId: this.props.activityId, name:this.props.name, + email:this.props.email, questions:this.props.questions}); + } + render() { - return ( -
- {this.props.questions.map(question => - + + + ) + : + ( + + { + (!this.props.isLoading) && + +
+ {this.props.title} +
+
+ } + { + (!this.props.isLoading) && + + + + } + { + (!this.props.isLoading) && + + + + } + {this.props.questions.map((question, index) => + )} -
+ + + { + + (!this.props.isLoading) && + diff --git a/src/routes/Login/containers/loginContainer.js b/src/routes/Login/containers/loginContainer.js index c424358..d594810 100644 --- a/src/routes/Login/containers/loginContainer.js +++ b/src/routes/Login/containers/loginContainer.js @@ -20,8 +20,8 @@ const mapDispatchToProps = (dispatch) => ({ const mapStateToProps = (state, ownProps) => { return { - isAuthenticated: state.authentication.jwtToken !== null, - redirect: ownProps.location.query.redirect || '/dashboard' + isAuthenticated: state.authentication.get("jwtToken"), + redirect: ownProps.location.query.redirect || '/dashboard', } } diff --git a/src/routes/Login/index.js b/src/routes/Login/index.js index bde0b61..0b272e8 100644 --- a/src/routes/Login/index.js +++ b/src/routes/Login/index.js @@ -2,7 +2,6 @@ import { injectReducer } from '../../store/reducers' import { Map, List } from 'immutable' import * as Actions from './modules/actions' -const Login = require('./containers/loginContainer').default export default (store) => ({ path: 'login', @@ -14,6 +13,7 @@ export default (store) => ({ /* Webpack - use require callback to define dependencies for bundling */ const reducer = require('./modules/reducer').default + const Login = require('./containers/loginContainer').default /* The reducer is merged with global reducer */ injectReducer(store, {key: 'login', reducer}) diff --git a/src/routes/Login/modules/actions/loginActions.js b/src/routes/Login/modules/actions/loginActions.js index cc5f133..9abbcf1 100644 --- a/src/routes/Login/modules/actions/loginActions.js +++ b/src/routes/Login/modules/actions/loginActions.js @@ -16,8 +16,6 @@ let login = (dispatch) => { return (email, password) => { let payload = {email: email, password: password} - console.log(payload); - /* first dispatch an action so we know that user is logging in*/ dispatch({type: LOGIN, payload: null}) @@ -30,8 +28,6 @@ let login = (dispatch) => { /* store token in the local storage*/ localStorage.setItem('jwtToken', token) - dispatch(routerActions.replace("/dashboard")) - /* this will set the the authorization token in all axios requests. */ axios.defaults.headers.common['Authorization'] = token; @@ -41,7 +37,7 @@ let login = (dispatch) => { dispatch(authenticationActions.authenticationSuccess(token)) }) .catch((error) => { - console.log("got here"); + console.log(error); dispatch(loginFailure(error, payload)) }) } diff --git a/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js b/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js index 388aa00..f05b56e 100644 --- a/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js +++ b/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js @@ -1,12 +1,11 @@ import isEmpty from 'lodash/isEmpty' let handleLogin = (state, payload) => { - return state.set('authenticating', true) + return {something: "cool"} } let handleLoginSuccess = (state, payload) => { - return state.set('authenticating', false) - .set('jwtToken', payload.token) + return {bad: "shit"} } export { diff --git a/src/routes/Login/modules/reducer/reducer.js b/src/routes/Login/modules/reducer/reducer.js index 9cdd592..ded6ccd 100644 --- a/src/routes/Login/modules/reducer/reducer.js +++ b/src/routes/Login/modules/reducer/reducer.js @@ -1,18 +1,19 @@ import { Map, List } from 'immutable' import * as Actions from '../actions' +import * as ActionHandlers from './actionHandlers' const initialState = Map({ - isLoginSuccess: false, + loggedIn: false, }) export default function reducer (state = initialState, action) { switch (action.type) { case(Actions.loginActions.LOGIN): - return state + return ActionHandlers.loginActionsHandlers.handleLogin(state, action.playload) case(Actions.loginActions.LOGIN_SUCCESS): - return state.set("isLoginSuccess", true); + return ActionHandlers.loginActionsHandlers.handleLoginSuccess(state, action.playload) case(Actions.loginActions.LOGIN_FAILURE): return state diff --git a/yarn.lock b/yarn.lock index 88bda3f..aa2e36e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,6 @@ # yarn lockfile v1 -Base64@~0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/Base64/-/Base64-0.2.1.tgz#ba3a4230708e186705065e66babdd4c35cf60028" - abbrev@1, abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" @@ -73,9 +69,9 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" -ansi-html@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.6.tgz#bda8e33dd2ee1c20f54c08eb405713cbfc0ed80e" +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" ansi-regex@^2.0.0: version "2.0.0" @@ -85,6 +81,10 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" +ansi@0.2.x: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansi/-/ansi-0.2.1.tgz#3ab568ec18cd0ab7753c83117d57dad684a1c017" + anymatch@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" @@ -282,7 +282,7 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.0" -babel-core@^6.17.0, babel-core@^6.18.0: +babel-core@^6.17.0: version "6.18.2" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.18.2.tgz#d8bb14dd6986fa4f3566a26ceda3964fa0e04e5b" dependencies: @@ -988,19 +988,7 @@ babel-preset-stage-3@^6.17.0: babel-plugin-transform-exponentiation-operator "^6.3.13" babel-plugin-transform-object-rest-spread "^6.16.0" -babel-register@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68" - dependencies: - babel-core "^6.18.0" - babel-runtime "^6.11.6" - core-js "^2.4.0" - home-or-tmp "^2.0.0" - lodash "^4.2.0" - mkdirp "^0.5.1" - source-map-support "^0.4.2" - -babel-register@^6.24.1, babel-register@^6.5.1: +babel-register@^6.18.0, babel-register@^6.24.1, babel-register@^6.5.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f" dependencies: @@ -1012,20 +1000,20 @@ babel-register@^6.24.1, babel-register@^6.5.1: mkdirp "^0.5.1" source-map-support "^0.4.2" -babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.9.5" - -babel-runtime@^6.2.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0: +babel-runtime@^6.0.0, babel-runtime@^6.2.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" dependencies: core-js "^2.4.0" regenerator-runtime "^0.10.0" +babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.3.0, babel-template@^6.8.0: version "6.16.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" @@ -1074,20 +1062,20 @@ babel-traverse@^6.24.1: invariant "^2.2.0" lodash "^4.2.0" -babel-types@^6.13.0, babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.8.0, babel-types@^6.9.0: - version "6.19.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.19.0.tgz#8db2972dbed01f1192a8b602ba1e1e4c516240b9" +babel-types@^6.13.0, babel-types@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" dependencies: - babel-runtime "^6.9.1" + babel-runtime "^6.22.0" esutils "^2.0.2" lodash "^4.2.0" to-fast-properties "^1.0.1" -babel-types@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" +babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.8.0, babel-types@^6.9.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.19.0.tgz#8db2972dbed01f1192a8b602ba1e1e4c516240b9" dependencies: - babel-runtime "^6.22.0" + babel-runtime "^6.9.1" esutils "^2.0.2" lodash "^4.2.0" to-fast-properties "^1.0.1" @@ -1187,22 +1175,7 @@ bluebird@^3.0.5, bluebird@^3.3.0, bluebird@^3.4.6: version "3.4.6" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.6.tgz#01da8d821d87813d158967e743d5fe6c62cf8c0f" -body-parser@^1.12.4: - version "1.15.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.15.2.tgz#d7578cf4f1d11d5f6ea804cef35dc7a7ff6dae67" - dependencies: - bytes "2.4.0" - content-type "~1.0.2" - debug "~2.2.0" - depd "~1.1.0" - http-errors "~1.5.0" - iconv-lite "0.4.13" - on-finished "~2.3.0" - qs "6.2.0" - raw-body "~2.1.7" - type-is "~1.6.13" - -body-parser@^1.17.1: +body-parser@^1.12.4, body-parser@^1.17.1: version "1.17.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" dependencies: @@ -1256,7 +1229,13 @@ browser-stdout@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" -browserify-zlib@~0.1.4: +browserify-aes@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-0.4.0.tgz#067149b668df31c4b58533e02d01e806d8608e2c" + dependencies: + inherits "^2.0.1" + +browserify-zlib@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" dependencies: @@ -1292,6 +1271,10 @@ builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + bytes@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" @@ -1566,7 +1549,7 @@ commander@2.8.x: dependencies: graceful-readlink ">= 1.0.0" -commander@2.9.0, commander@2.9.x, commander@^2.8.1, commander@^2.9.0: +commander@2.9.0, commander@2.9.x, commander@2.x.x, commander@^2.8.1, commander@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: @@ -1668,9 +1651,9 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" -constants-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-0.0.1.tgz#92577db527ba6c4cf0a4568d84bc031f441e21f2" +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" content-disposition@0.5.1: version "0.5.1" @@ -1733,10 +1716,11 @@ cryptiles@2.x.x: dependencies: boom "2.x.x" -crypto-browserify@~3.2.6: - version "3.2.8" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.2.8.tgz#b9b11dbe6d9651dd882a01e6cc467df718ecf189" +crypto-browserify@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.3.0.tgz#b9fc75bb4a0ed61dcf1cd5dae96eb30c9c3e506c" dependencies: + browserify-aes "0.4.0" pbkdf2-compat "2.0.1" ripemd160 "0.2.0" sha.js "2.2.6" @@ -2721,6 +2705,10 @@ forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" +form-data-to-object@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/form-data-to-object/-/form-data-to-object-0.2.0.tgz#f7a8e68ddd910a1100a65e25ac6a484143ff8168" + form-data@~1.0.0-rc4: version "1.0.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" @@ -2743,6 +2731,19 @@ formatio@1.1.1: dependencies: samsam "~1.1" +formsy-react@^0.19.2: + version "0.19.2" + resolved "https://registry.yarnpkg.com/formsy-react/-/formsy-react-0.19.2.tgz#7fa818ff93c8c07195486c4d2e42b6da0c0ee4a3" + dependencies: + form-data-to-object "^0.2.0" + +formsy-semantic-ui-react@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/formsy-semantic-ui-react/-/formsy-semantic-ui-react-0.2.4.tgz#2ccbc02f8aef34f9d6cce4f93742ba5f8b5a85b8" + dependencies: + lodash.debounce "^4.0.8" + prop-types "^15.5.8" + forwarded@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" @@ -3070,7 +3071,7 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" -hoist-non-react-statics@^1.0.0, hoist-non-react-statics@^1.0.3, hoist-non-react-statics@^1.2.0: +hoist-non-react-statics@1.2.0, hoist-non-react-statics@^1.0.0, hoist-non-react-statics@^1.0.3, hoist-non-react-statics@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" @@ -3147,13 +3148,6 @@ htmlparser2@~3.3.0: domutils "1.1" readable-stream "1.0" -http-browserify@^1.3.2: - version "1.7.0" - resolved "https://registry.yarnpkg.com/http-browserify/-/http-browserify-1.7.0.tgz#33795ade72df88acfbfd36773cefeda764735b20" - dependencies: - Base64 "~0.2.0" - inherits "~2.0.1" - http-errors@~1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" @@ -3186,19 +3180,25 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.0.tgz#b3ffdfe734b2a3d4a9efd58e8654c91fce86eafd" +http-status-code@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-status-code/-/http-status-code-2.1.0.tgz#3e0dc85ea4369cf4cbdb1bc4447d2b4114bd4d3a" + dependencies: + strip-json-comments "^1.0.2" + +http-status-codes@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.1.6.tgz#7a75d2b94d35a93183f39a0c8a6eb8963c20e50d" + +https-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" hyphenate-style-name@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" -iconv-lite@0.4.13, iconv-lite@~0.4.13: - version "0.4.13" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" - -iconv-lite@0.4.15: +iconv-lite@0.4.15, iconv-lite@~0.4.13: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" @@ -3218,6 +3218,10 @@ ignore@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" +immutable@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2" + imports-loader@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.7.0.tgz#468c04de8075941cfab28146c755c24cc1f36ccd" @@ -3941,6 +3945,10 @@ lodash.create@3.1.1: lodash._basecreate "^3.0.0" lodash._isiterateecall "^3.0.0" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + lodash.defaults@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c" @@ -3980,6 +3988,10 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" +lodash.isempty@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" + lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -4059,13 +4071,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.0.tgz#6b26248c42f6d4fa4b0d8542f78edfcde35642a8" - dependencies: - js-tokens "^2.0.0" - -loose-envify@^1.3.1: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -4402,32 +4408,32 @@ node-gyp@^3.3.1: tar "^2.0.0" which "1" -node-libs-browser@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.6.0.tgz#244806d44d319e048bc8607b5cc4eaf9a29d2e3c" +node-libs-browser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.7.0.tgz#3e272c0819e308935e26674408d7af0e1491b83b" dependencies: assert "^1.1.1" - browserify-zlib "~0.1.4" + browserify-zlib "^0.1.4" buffer "^4.9.0" console-browserify "^1.1.0" - constants-browserify "0.0.1" - crypto-browserify "~3.2.6" + constants-browserify "^1.0.0" + crypto-browserify "3.3.0" domain-browser "^1.1.1" events "^1.0.0" - http-browserify "^1.3.2" - https-browserify "0.0.0" - os-browserify "~0.1.2" + https-browserify "0.0.1" + os-browserify "^0.2.0" path-browserify "0.0.0" process "^0.11.0" punycode "^1.2.4" - querystring-es3 "~0.2.0" - readable-stream "^1.1.13" - stream-browserify "^1.0.0" - string_decoder "~0.10.25" - timers-browserify "^1.0.1" + querystring-es3 "^0.2.0" + readable-stream "^2.0.5" + stream-browserify "^2.0.1" + stream-http "^2.3.1" + string_decoder "^0.10.25" + timers-browserify "^2.0.2" tty-browserify "0.0.0" - url "~0.10.1" - util "~0.10.3" + url "^0.11.0" + util "^0.10.3" vm-browserify "0.0.4" node-pre-gyp@^0.6.29: @@ -4669,9 +4675,9 @@ options@>=0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" -os-browserify@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" +os-browserify@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f" os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" @@ -5164,7 +5170,7 @@ process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" -process@^0.11.0, process@~0.11.0: +process@^0.11.0: version "0.11.9" resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" @@ -5184,13 +5190,7 @@ prop-types@15.5.8: dependencies: fbjs "^0.8.9" -prop-types@^15.5.2, prop-types@^15.5.4: - version "15.5.4" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.4.tgz#2ed3692716a5060f8cc020946d8238e7419d92c0" - dependencies: - fbjs "^0.8.9" - -prop-types@^15.5.6, prop-types@^15.5.8, prop-types@~15.5.7: +prop-types@^15.5.2, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@~15.5.7: version "15.5.10" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" dependencies: @@ -5257,7 +5257,7 @@ query-string@^4.1.0, query-string@^4.2.2: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -querystring-es3@~0.2.0: +querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -5290,14 +5290,6 @@ range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" -raw-body@~2.1.7: - version "2.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" - dependencies: - bytes "2.4.0" - iconv-lite "0.4.13" - unpipe "1.0.0" - raw-body@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" @@ -5426,6 +5418,10 @@ react-redux@^5.0.1: lodash-es "^4.2.0" loose-envify "^1.1.0" +react-router-redux@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-4.0.8.tgz#227403596b5151e182377dab835b5d45f0f8054e" + react-router@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.0.0.tgz#3f313e4dbaf57048c48dd0a8c3cac24d93667dff" @@ -5506,7 +5502,7 @@ readable-stream@1.0, readable-stream@~1.0.2: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@2.2.7: +readable-stream@2.2.7, readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.2.6: version "2.2.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.7.tgz#07057acbe2467b22042d36f98c5ad507054e95b1" dependencies: @@ -5518,27 +5514,6 @@ readable-stream@2.2.7: string_decoder "~1.0.0" util-deprecate "~1.0.1" -readable-stream@^1.0.27-1, readable-stream@^1.1.13: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" - dependencies: - buffer-shims "^1.0.0" - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - readable-stream@~2.0.0, readable-stream@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" @@ -5622,6 +5597,14 @@ reduce-function-call@^1.0.1: dependencies: balanced-match "^0.4.2" +redux-auth-wrapper@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/redux-auth-wrapper/-/redux-auth-wrapper-1.1.0.tgz#ccd4a753fe2134eb93c44f4e5781054577f6244a" + dependencies: + hoist-non-react-statics "1.2.0" + lodash.isempty "4.4.0" + prop-types "15.5.8" + redux-thunk@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.1.0.tgz#c724bfee75dbe352da2e3ba9bc14302badd89a98" @@ -5894,6 +5877,14 @@ sax@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" +scandir@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/scandir/-/scandir-0.1.2.tgz#aeda630ab9a3328c544c34e2efb0f862e5ff5526" + dependencies: + ansi "0.2.x" + commander "2.x.x" + mime "1.2.x" + semantic-ui-css@^2.2.10: version "2.2.10" resolved "https://registry.yarnpkg.com/semantic-ui-css/-/semantic-ui-css-2.2.10.tgz#f8f4470dbeffca0f0f3ff4fb71a35c71e88ad89c" @@ -5963,7 +5954,7 @@ set-immediate-shim@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" -setimmediate@^1.0.5: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -6108,6 +6099,10 @@ source-list-map@^0.1.4, source-list-map@~0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.6.tgz#e1e6f94f0b40c4d28dcf8f5b8766e0e45636877f" +source-list-map@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" + source-map-support@^0.4.2: version "0.4.6" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.6.tgz#32552aa64b458392a85eab3b0b5ee61527167aeb" @@ -6189,12 +6184,12 @@ stdout-stream@^1.4.0: dependencies: readable-stream "^2.0.1" -stream-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-1.0.0.tgz#bf9b4abfb42b274d751479e44e0ff2656b6f1193" +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" dependencies: inherits "~2.0.1" - readable-stream "^1.0.27-1" + readable-stream "^2.0.2" stream-combiner@~0.0.4: version "0.0.4" @@ -6202,6 +6197,16 @@ stream-combiner@~0.0.4: dependencies: duplexer "~0.1.1" +stream-http@^2.3.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.1.tgz#546a51741ad5a6b07e9e31b0b10441a917df528a" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.2.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + stream-shift@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" @@ -6231,7 +6236,7 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" -string_decoder@~0.10.25, string_decoder@~0.10.x: +string_decoder@^0.10.25, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -6274,7 +6279,7 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: +strip-json-comments@^1.0.2, strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" @@ -6284,6 +6289,10 @@ style-loader@^0.13.1: dependencies: loader-utils "^0.2.7" +style@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/style/-/style-0.0.3.tgz#a2d7989a9e010101f2bc4d287cff3b45cfbb5837" + subscribe-ui-event@^1.0.0: version "1.0.14" resolved "https://registry.yarnpkg.com/subscribe-ui-event/-/subscribe-ui-event-1.0.14.tgz#c506104bc35c7abb762eb347b595442a2567267f" @@ -6386,11 +6395,11 @@ timed-out@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a" -timers-browserify@^1.0.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" +timers-browserify@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86" dependencies: - process "~0.11.0" + setimmediate "^1.0.4" tmp@0.0.28: version "0.0.28" @@ -6402,6 +6411,10 @@ to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + to-fast-properties@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" @@ -6563,9 +6576,9 @@ url-loader@^0.5.6: loader-utils "0.2.x" mime "1.2.x" -url@~0.10.1: - version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" dependencies: punycode "1.3.2" querystring "0.2.0" @@ -6598,7 +6611,7 @@ util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -util@0.10.3, "util@>=0.10.3 <1", util@~0.10.3: +util@0.10.3, "util@>=0.10.3 <1", util@^0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" dependencies: @@ -6641,6 +6654,10 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" +validator@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-7.0.0.tgz#c74deb8063512fac35547938e6f0b1504a282fd2" + vary@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" @@ -6679,11 +6696,11 @@ watchpack@^0.2.1: chokidar "^1.0.0" graceful-fs "^4.1.2" -webpack-core@~0.6.0: - version "0.6.8" - resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.8.tgz#edf9135de00a6a3c26dd0f14b208af0aa4af8d0a" +webpack-core@~0.6.9: + version "0.6.9" + resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2" dependencies: - source-list-map "~0.1.0" + source-list-map "~0.1.7" source-map "~0.4.1" webpack-dev-middleware@^1.0.11, webpack-dev-middleware@^1.6.1: @@ -6695,11 +6712,11 @@ webpack-dev-middleware@^1.0.11, webpack-dev-middleware@^1.6.1: path-is-absolute "^1.0.0" range-parser "^1.0.3" -webpack-hot-middleware@^2.12.2: - version "2.13.2" - resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.13.2.tgz#6500b15e6d4f1a9590f8df708183f4d2ac2c3e9e" +webpack-hot-middleware@^2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.18.0.tgz#a16bb535b83a6ac94a78ac5ebce4f3059e8274d3" dependencies: - ansi-html "0.0.6" + ansi-html "0.0.7" html-entities "^1.2.0" querystring "^0.2.0" strip-ansi "^3.0.0" @@ -6711,9 +6728,9 @@ webpack-sources@^0.1.0: source-list-map "~0.1.0" source-map "~0.5.3" -webpack@^1.12.14: - version "1.13.3" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.13.3.tgz#e79c46fe5a37c5ca70084ba0894c595cdcb42815" +webpack@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.15.0.tgz#4ff31f53db03339e55164a9d468ee0324968fe98" dependencies: acorn "^3.0.0" async "^1.3.0" @@ -6723,13 +6740,13 @@ webpack@^1.12.14: loader-utils "^0.2.11" memory-fs "~0.3.0" mkdirp "~0.5.0" - node-libs-browser "^0.6.0" + node-libs-browser "^0.7.0" optimist "~0.6.0" supports-color "^3.1.0" tapable "~0.1.8" uglify-js "~2.7.3" watchpack "^0.2.1" - webpack-core "~0.6.0" + webpack-core "~0.6.9" whatwg-fetch@>=0.10.0: version "2.0.1" From 0a7c3e8439846d76b0887680263f164b7b5d82ed Mon Sep 17 00:00:00 2001 From: lightertu Date: Sun, 4 Jun 2017 13:06:19 -0700 Subject: [PATCH 11/23] login route done --- .../Activity/containers/ActivityContainer.js | 3 ++- src/routes/Activity/index.js | 4 +--- src/routes/Login/components/LoginView.js | 15 +++++++++----- src/routes/Login/containers/loginContainer.js | 5 +++++ .../Login/modules/actions/loginActions.js | 9 ++++++++- .../actionHandlers/loginActionsHandlers.js | 20 ++++++++++++++++--- src/routes/Login/modules/reducer/reducer.js | 8 ++++++-- 7 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/routes/Activity/containers/ActivityContainer.js b/src/routes/Activity/containers/ActivityContainer.js index e3f629e..6462af9 100644 --- a/src/routes/Activity/containers/ActivityContainer.js +++ b/src/routes/Activity/containers/ActivityContainer.js @@ -9,6 +9,7 @@ import {connect} from 'react-redux' component - in this case */ import ActivityView from '../components/ActivityView' import * as Actions from "../modules/actions" +import UserIsAuthenticated from '../../UserIsAuthenticated' const mapDispatchToProps = (dispatch) => ({ @@ -32,4 +33,4 @@ const mapStateToProps = (state, ownProps) => { } }; -export default connect(mapStateToProps, mapDispatchToProps)(ActivityView); +export default UserIsAuthenticated(connect(mapStateToProps, mapDispatchToProps)(ActivityView)); diff --git a/src/routes/Activity/index.js b/src/routes/Activity/index.js index 8aa0118..fd36475 100644 --- a/src/routes/Activity/index.js +++ b/src/routes/Activity/index.js @@ -3,7 +3,6 @@ */ import {injectReducer} from '../../store/reducers' -import UserIsAuthenticated from "../UserIsAuthenticated" export default (store) => ({ path: 'activity', @@ -16,14 +15,13 @@ export default (store) => ({ /* Webpack - use require callback to define dependencies for bundling */ const activity = require('./containers/ActivityContainer').default; - const securedActivity = UserIsAuthenticated(activity); /* Add the reducer to the store on key 'counter' */ const reducer = require('./modules/reducer/reducer').default; injectReducer(store, {key: 'activity', reducer}); /* Return getComponent */ - cb(null, securedActivity) + cb(null, activity) /* Webpack named bundle */ }, 'activity') diff --git a/src/routes/Login/components/LoginView.js b/src/routes/Login/components/LoginView.js index d4dd9c4..ec8fb6d 100644 --- a/src/routes/Login/components/LoginView.js +++ b/src/routes/Login/components/LoginView.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react' -import { Button, Grid, Header, Image, Label, Message, Segment } from 'semantic-ui-react' +import { Button, Grid, Header, Icon, Image, Label, Message, Segment } from 'semantic-ui-react' import { Form, Input, TextArea, Checkbox, Radio, RadioGroup, Dropdown, Select, } from 'formsy-semantic-ui-react' @@ -11,7 +11,10 @@ class LoginView extends Component { static propTypes = { login: PropTypes.func.isRequired, - replace: PropTypes.func.isRequired + replace: PropTypes.func.isRequired, + hideErrorMessage: PropTypes.func.isRequired, + authenticating: PropTypes.bool.isRequired, + authenticationFailed: PropTypes.bool.isRequired } componentWillMount () { @@ -37,12 +40,14 @@ class LoginView extends Component { } render () { + const {hideErrorMessage, authenticating, authenticationFailed} = this.props return ( - +
Login
+ { authenticationFailed && email or password is incorrect }
@@ -56,8 +61,8 @@ class LoginView extends Component { }} /> - + name="password" /> +
diff --git a/src/routes/Login/containers/loginContainer.js b/src/routes/Login/containers/loginContainer.js index d594810..b25a8f5 100644 --- a/src/routes/Login/containers/loginContainer.js +++ b/src/routes/Login/containers/loginContainer.js @@ -15,6 +15,7 @@ const mapDispatchToProps = (dispatch) => ({ /* not sure what does it do, but it is quite important*/ /* https://github.com/mjrussell/redux-auth-wrapper/blob/master/examples/localStorage/components/Login.js */ replace: (newLocation) => { dispatch(routerActions.replace(newLocation)) }, + hideErrorMessage: () => {dispatch(Actions.loginActions.hideErrorMessage())}, logout: Actions.logoutActions.logout(dispatch), }) @@ -22,6 +23,10 @@ const mapStateToProps = (state, ownProps) => { return { isAuthenticated: state.authentication.get("jwtToken"), redirect: ownProps.location.query.redirect || '/dashboard', + + /* for UI */ + authenticating: state.login.get("authenticating"), + authenticationFailed: state.login.get("authenticationFailed"), } } diff --git a/src/routes/Login/modules/actions/loginActions.js b/src/routes/Login/modules/actions/loginActions.js index 9abbcf1..ce5672e 100644 --- a/src/routes/Login/modules/actions/loginActions.js +++ b/src/routes/Login/modules/actions/loginActions.js @@ -54,8 +54,15 @@ let loginSuccess = (payload) => { return {type: LOGIN_SUCCESS, payload: payload} } +export const HIDE_ERROR_MESSAGE = 'HIDE_ERROR_MESSAGE' +let hideErrorMessage = (payload) => { + return {type: HIDE_ERROR_MESSAGE, payload: payload} +} + + export { login, loginSuccess, - loginFailure + loginFailure, + hideErrorMessage } diff --git a/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js b/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js index f05b56e..42fb641 100644 --- a/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js +++ b/src/routes/Login/modules/reducer/actionHandlers/loginActionsHandlers.js @@ -1,14 +1,28 @@ import isEmpty from 'lodash/isEmpty' let handleLogin = (state, payload) => { - return {something: "cool"} + return state.set("authenticating", true) + .set("authenticationFailed", false) +} + +let handleLoginFailure = (state, payload) => { + return state.set("authenticating", false) + .set("authenticationFailed", true) } let handleLoginSuccess = (state, payload) => { - return {bad: "shit"} + return state.set("authenticating", false) + .set("authenticationFailed", false) +} + +let handleHideErrorMessage = (state, payload) => { + console.log("here"); + return state.set("authenticationFailed", false) } export { handleLogin, - handleLoginSuccess + handleLoginSuccess, + handleLoginFailure, + handleHideErrorMessage } \ No newline at end of file diff --git a/src/routes/Login/modules/reducer/reducer.js b/src/routes/Login/modules/reducer/reducer.js index ded6ccd..f9c5e29 100644 --- a/src/routes/Login/modules/reducer/reducer.js +++ b/src/routes/Login/modules/reducer/reducer.js @@ -4,7 +4,8 @@ import * as ActionHandlers from './actionHandlers' const initialState = Map({ - loggedIn: false, + authenticating: false, + authenticationFailed: false }) export default function reducer (state = initialState, action) { @@ -16,10 +17,13 @@ export default function reducer (state = initialState, action) { return ActionHandlers.loginActionsHandlers.handleLoginSuccess(state, action.playload) case(Actions.loginActions.LOGIN_FAILURE): - return state + return ActionHandlers.loginActionsHandlers.handleLoginFailure(state, action.playload) case(Actions.logoutActions.LOGOUT): return state + + case(Actions.loginActions.HIDE_ERROR_MESSAGE): + return ActionHandlers.loginActionsHandlers.handleHideErrorMessage(state, action.payload) default: return state } From ef12b42064bd320e65599ac30684d39f1770451c Mon Sep 17 00:00:00 2001 From: lightertu Date: Sun, 4 Jun 2017 14:38:00 -0700 Subject: [PATCH 12/23] sign up done --- src/routes/Login/components/LoginView.js | 2 +- .../Login/modules/actions/loginActions.js | 2 - src/routes/Signup/components/SignupView.js | 102 ++++++++++++++++++ .../Signup/containers/signupContainer.js | 32 ++++++ src/routes/Signup/index.js | 24 +++++ src/routes/Signup/modules/actions/index.js | 7 ++ .../Signup/modules/actions/signupActions.js | 60 +++++++++++ .../modules/reducer/actionHandlers/index.js | 6 ++ .../actionHandlers/signupActionsHandlers.js | 32 ++++++ src/routes/Signup/modules/reducer/index.js | 3 + src/routes/Signup/modules/reducer/reducer.js | 26 +++++ src/routes/Signup/modules/utils/index.js | 19 ++++ src/routes/index.js | 2 + 13 files changed, 314 insertions(+), 3 deletions(-) create mode 100644 src/routes/Signup/components/SignupView.js create mode 100644 src/routes/Signup/containers/signupContainer.js create mode 100644 src/routes/Signup/index.js create mode 100644 src/routes/Signup/modules/actions/index.js create mode 100644 src/routes/Signup/modules/actions/signupActions.js create mode 100644 src/routes/Signup/modules/reducer/actionHandlers/index.js create mode 100644 src/routes/Signup/modules/reducer/actionHandlers/signupActionsHandlers.js create mode 100644 src/routes/Signup/modules/reducer/index.js create mode 100644 src/routes/Signup/modules/reducer/reducer.js create mode 100644 src/routes/Signup/modules/utils/index.js diff --git a/src/routes/Login/components/LoginView.js b/src/routes/Login/components/LoginView.js index ec8fb6d..176bef5 100644 --- a/src/routes/Login/components/LoginView.js +++ b/src/routes/Login/components/LoginView.js @@ -42,7 +42,7 @@ class LoginView extends Component { render () { const {hideErrorMessage, authenticating, authenticationFailed} = this.props return ( - +
Login diff --git a/src/routes/Login/modules/actions/loginActions.js b/src/routes/Login/modules/actions/loginActions.js index ce5672e..a8212da 100644 --- a/src/routes/Login/modules/actions/loginActions.js +++ b/src/routes/Login/modules/actions/loginActions.js @@ -4,8 +4,6 @@ import axios from 'axios' import { authenticationActions } from '../../../../store/authentication/actions' -import { browserHistory } from 'react-router' -import {routerActions } from 'react-router-redux' const SERVER_URL = 'http://localhost:3000' export const LOGIN = 'LOGIN' diff --git a/src/routes/Signup/components/SignupView.js b/src/routes/Signup/components/SignupView.js new file mode 100644 index 0000000..2156ffb --- /dev/null +++ b/src/routes/Signup/components/SignupView.js @@ -0,0 +1,102 @@ +import React, { Component, PropTypes } from 'react' +import { Button, Grid, Header, Icon, Image, Label, Message, Segment } from 'semantic-ui-react' +import { Form, Input, TextArea, Checkbox, Radio, RadioGroup, Dropdown, Select, } from 'formsy-semantic-ui-react' + +class SignupView extends Component { + constructor (props) { + super(props) + } + + static propTypes = { + signup: PropTypes.func.isRequired, + replace: PropTypes.func.isRequired, + hideErrorMessage: PropTypes.func.isRequired, + signingUp: PropTypes.bool.isRequired, + signupSuccess: PropTypes.bool.isRequired, + signupFailure: PropTypes.bool.isRequired + } + + componentWillMount () { + const {isAuthenticated, replace, redirect} = this.props + if (isAuthenticated) { + replace(redirect) + } + } + + handleOnValidSubmit = (formData) => { + const {email, password} = formData + const {signup} = this.props + signup(email, password) + } + + redirectToLogin = () => { + this.props.push('/login') + } + + render () { + const {hideErrorMessage, signingUp, signupFailure, signupSuccess} = this.props + return ( + + +
+ Signup +
+ { signupFailure && Duplicate Email } + { signupSuccess && + + Signup Success +

Redirect to Login in 3 Seconds ...

+
+ } + + +
+ } + validationErrors={{ + isEmail: 'This has to be your email', + isDefaultRequiredValue: 'required', + }} + /> + } + validationErrors={{ + minLength: 'at least 6 characters', + equalsField: 'Passwords do not match', + isDefaultRequiredValue: 'required', + }} + /> + + } + validationErrors={{ + equalsField: 'Passwords do not match', + isDefaultRequiredValue: 'required', + }} + + /> + + + +
+ + Already have an account? Log + in + +
+
+ ) + } + +} + +export default SignupView \ No newline at end of file diff --git a/src/routes/Signup/containers/signupContainer.js b/src/routes/Signup/containers/signupContainer.js new file mode 100644 index 0000000..9d80c22 --- /dev/null +++ b/src/routes/Signup/containers/signupContainer.js @@ -0,0 +1,32 @@ +import { connect } from 'react-redux' +import { routerActions } from 'react-router-redux' + + +/* This is a container component. Notice it does not contain any JSX, + nor does it import React. This component is **only** responsible for + wiring in the actions and state necessary to render a presentational + component - in this case, the counter: */ + +import SignupView from '../components/SignupView' +import * as Actions from '../modules/actions' + +const mapDispatchToProps = (dispatch) => ({ + signup: Actions.signupActions.signup(dispatch), + replace: (newLocation) => { dispatch(routerActions.replace(newLocation)) }, + push: (newLocation) => { dispatch(routerActions.push(newLocation)) }, + hideErrorMessage: () => {dispatch(Actions.signupActions.hideErrorMessage())}, +}) + +const mapStateToProps = (state, ownProps) => { + return { + isAuthenticated: state.authentication.get("jwtToken"), + redirect: ownProps.location.query.redirect || '/dashboard', + + /* for UI */ + signingUp: state.signup.get("signingUp"), + signupSuccess: state.signup.get("signupSuccess"), + signupFailure: state.signup.get("signupFailure"), + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(SignupView) diff --git a/src/routes/Signup/index.js b/src/routes/Signup/index.js new file mode 100644 index 0000000..17028c6 --- /dev/null +++ b/src/routes/Signup/index.js @@ -0,0 +1,24 @@ +import { injectReducer } from '../../store/reducers' + + +export default (store) => ({ + path: 'signup', + /* Async getComponent is only invoked when route matches */ + getComponent (nextState, cb) { + /* Webpack - use 'require.ensure' to create a split point + and embed an async module loader (jsonp) when bundling */ + require.ensure([], (require) => { + /* Webpack - use require callback to define + dependencies for bundling */ + const reducer = require('./modules/reducer').default + const Signup = require('./containers/signupContainer').default + /* The reducer is merged with global reducer */ + injectReducer(store, {key: 'signup', reducer}) + + /* Return getComponent */ + cb(null, Signup) + + /* Webpack named bundle */ + }, 'signup') + } +}); diff --git a/src/routes/Signup/modules/actions/index.js b/src/routes/Signup/modules/actions/index.js new file mode 100644 index 0000000..3ff6ff5 --- /dev/null +++ b/src/routes/Signup/modules/actions/index.js @@ -0,0 +1,7 @@ +import * as signupActions from "./signupActions" + +export { + signupActions, +} + + diff --git a/src/routes/Signup/modules/actions/signupActions.js b/src/routes/Signup/modules/actions/signupActions.js new file mode 100644 index 0000000..c4f674b --- /dev/null +++ b/src/routes/Signup/modules/actions/signupActions.js @@ -0,0 +1,60 @@ +/** + * Created by rui on 6/2/17. + */ + +import axios from 'axios' +import {routerActions } from 'react-router-redux' + +const SERVER_URL = 'http://localhost:3000' +export const SIGNUP = 'SIGNUP' + + + +let signup = (dispatch) => { + return (email, password) => { + let payload = {email: email, password: password} + + /* first dispatch an action so we know that user is logging in*/ + dispatch({type: SIGNUP, payload: null}) + + let url = SERVER_URL + '/api/auth/signup' + axios.post(url, payload) + .then((response) => { + /* this will set the the authorization token in all axios requests. */ + dispatch(signupSuccess(response)) + + /* redirect to login in 3 seconds */ + setTimeout(()=>{ + dispatch(routerActions.replace("/login")) + }, 3000) + }) + .catch((error) => { + console.log(error); + dispatch(signupFailure(error, payload)) + }) + } +} + +/* user failure */ +export const SIGNUP_FAILURE = 'SIGNUP_FAILURE' +let signupFailure = (error) => { + return {type: SIGNUP_FAILURE, error: error} +} + +export const SIGNUP_SUCCESS = 'SIGNUP_SUCCESS' +let signupSuccess = (payload) => { + return {type: SIGNUP_SUCCESS, payload: payload} +} + +export const HIDE_ERROR_MESSAGE = 'HIDE_ERROR_MESSAGE' +let hideErrorMessage = (payload) => { + return {type: HIDE_ERROR_MESSAGE, payload: payload} +} + + +export { + signup, + signupSuccess, + signupFailure, + hideErrorMessage +} diff --git a/src/routes/Signup/modules/reducer/actionHandlers/index.js b/src/routes/Signup/modules/reducer/actionHandlers/index.js new file mode 100644 index 0000000..67bad7e --- /dev/null +++ b/src/routes/Signup/modules/reducer/actionHandlers/index.js @@ -0,0 +1,6 @@ +import * as signupActionsHandlers from "./signupActionsHandlers" + + +export { + signupActionsHandlers, +} \ No newline at end of file diff --git a/src/routes/Signup/modules/reducer/actionHandlers/signupActionsHandlers.js b/src/routes/Signup/modules/reducer/actionHandlers/signupActionsHandlers.js new file mode 100644 index 0000000..1139dd7 --- /dev/null +++ b/src/routes/Signup/modules/reducer/actionHandlers/signupActionsHandlers.js @@ -0,0 +1,32 @@ +import isEmpty from 'lodash/isEmpty' + +let handleSignup = (state, payload) => { + return state.set("signingUp", false) + .set("signupFailure", false) + .set("signupSuccess", false) +} + +let handleSignupFailure = (state, payload) => { + return state.set("signingUp", false) + .set("signupFailure", true) + .set("signupSuccess", false) +} + +let handleSignupSuccess = (state, payload) => { + return state.set("signingUp", false) + .set("signupFailure", false) + .set("signupSuccess", true) +} + +let handleHideErrorMessages = (state, payload) => { + return state.set("signingUp", false) + .set("signupFailure", false) + .set("signupSuccess", false) +} + +export { + handleSignup, + handleSignupSuccess, + handleSignupFailure, + handleHideErrorMessages +} \ No newline at end of file diff --git a/src/routes/Signup/modules/reducer/index.js b/src/routes/Signup/modules/reducer/index.js new file mode 100644 index 0000000..d472a0d --- /dev/null +++ b/src/routes/Signup/modules/reducer/index.js @@ -0,0 +1,3 @@ +import reducer from "./reducer" + +export default reducer \ No newline at end of file diff --git a/src/routes/Signup/modules/reducer/reducer.js b/src/routes/Signup/modules/reducer/reducer.js new file mode 100644 index 0000000..cbed5e6 --- /dev/null +++ b/src/routes/Signup/modules/reducer/reducer.js @@ -0,0 +1,26 @@ +import { Map, List } from 'immutable' +import * as Actions from '../actions' +import * as ActionHandlers from './actionHandlers' + + +const initialState = Map({ + signingUp: false, + signupSuccess: false, + signupFailure: false +}) + +export default function reducer (state = initialState, action) { + switch (action.type) { + case(Actions.signupActions.SIGNUP): + return ActionHandlers.signupActionsHandlers.handleSignup(state, null) + case(Actions.signupActions.SIGNUP_SUCCESS): + return ActionHandlers.signupActionsHandlers.handleSignupSuccess(state, null) + case(Actions.signupActions.SIGNUP_FAILURE): + return ActionHandlers.signupActionsHandlers.handleSignupFailure(state, null) + + case(Actions.signupActions.HIDE_ERROR_MESSAGE): + return ActionHandlers.signupActionsHandlers.handleHideErrorMessages(state, null) + default: + return state + } +} diff --git a/src/routes/Signup/modules/utils/index.js b/src/routes/Signup/modules/utils/index.js new file mode 100644 index 0000000..f8bdf9f --- /dev/null +++ b/src/routes/Signup/modules/utils/index.js @@ -0,0 +1,19 @@ +/** + * Created by rui on 6/2/17. + */ + +import React from 'react'; + +export function checkHttpStatus(response) { + if (response.status >= 200 && response.status < 300) { + return response + } else { + let error = new Error(response.statusText) + error.response = response + throw error + } +} + +export function parseJSON(response) { + return response.json() +} \ No newline at end of file diff --git a/src/routes/index.js b/src/routes/index.js index 5e9ccae..b409da9 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -4,6 +4,7 @@ import ActivityRoute from './Activity' import Dashboard from './Dashboard' import Survey from './Survey' import LoginRoute from './Login' +import SignupRoute from './Signup' import PageNotFound from './PageNotFound' /*home route*/ @@ -19,6 +20,7 @@ export const createRoutes = (store) => { childRoutes: [ ActivityRoute(store), LoginRoute(store), + SignupRoute(store), Dashboard(store), Survey(store), PageNotFound(store), From 3a80c9a869dba15bd91cbf965e2d9eb331ed1c3d Mon Sep 17 00:00:00 2001 From: lightertu Date: Sun, 4 Jun 2017 14:42:17 -0700 Subject: [PATCH 13/23] login and signup 1.0 done --- src/routes/Login/components/LoginView.js | 7 ++++++- src/routes/Login/containers/loginContainer.js | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/routes/Login/components/LoginView.js b/src/routes/Login/components/LoginView.js index 176bef5..cedcb4e 100644 --- a/src/routes/Login/components/LoginView.js +++ b/src/routes/Login/components/LoginView.js @@ -12,6 +12,7 @@ class LoginView extends Component { static propTypes = { login: PropTypes.func.isRequired, replace: PropTypes.func.isRequired, + push: PropTypes.func.isRequired, hideErrorMessage: PropTypes.func.isRequired, authenticating: PropTypes.bool.isRequired, authenticationFailed: PropTypes.bool.isRequired @@ -39,6 +40,10 @@ class LoginView extends Component { login(email, password) } + redirectToSignup = () => { + this.props.push('/signup') + } + render () { const {hideErrorMessage, authenticating, authenticationFailed} = this.props return ( @@ -66,7 +71,7 @@ class LoginView extends Component { - New to us? Sign Up + New to us? Sign up diff --git a/src/routes/Login/containers/loginContainer.js b/src/routes/Login/containers/loginContainer.js index b25a8f5..4d78522 100644 --- a/src/routes/Login/containers/loginContainer.js +++ b/src/routes/Login/containers/loginContainer.js @@ -15,6 +15,7 @@ const mapDispatchToProps = (dispatch) => ({ /* not sure what does it do, but it is quite important*/ /* https://github.com/mjrussell/redux-auth-wrapper/blob/master/examples/localStorage/components/Login.js */ replace: (newLocation) => { dispatch(routerActions.replace(newLocation)) }, + push: (newLocation) => { dispatch(routerActions.push(newLocation)) }, hideErrorMessage: () => {dispatch(Actions.loginActions.hideErrorMessage())}, logout: Actions.logoutActions.logout(dispatch), }) From c32c59185b5cfffc0ea61415cc999d0fff9d9280 Mon Sep 17 00:00:00 2001 From: lightertu Date: Sun, 4 Jun 2017 15:16:40 -0700 Subject: [PATCH 14/23] home route --- .../AuthenticationModal.js | 97 ------------------- src/components/AuthenticationModal/index.js | 3 - src/components/Header/Header.js | 5 +- src/routes/Home/components/HomeView.js | 58 ++++++++--- src/routes/Home/containers/homeContainer.js | 26 +++++ src/routes/Home/index.js | 2 +- src/routes/Welcome/components/WelcomeView.js | 35 ------- .../Welcome/containers/WelcomeContainer.js | 18 ---- src/routes/Welcome/index.js | 6 -- src/routes/index.js | 4 +- 10 files changed, 74 insertions(+), 180 deletions(-) delete mode 100644 src/components/AuthenticationModal/AuthenticationModal.js delete mode 100644 src/components/AuthenticationModal/index.js create mode 100644 src/routes/Home/containers/homeContainer.js delete mode 100644 src/routes/Welcome/components/WelcomeView.js delete mode 100644 src/routes/Welcome/containers/WelcomeContainer.js delete mode 100644 src/routes/Welcome/index.js diff --git a/src/components/AuthenticationModal/AuthenticationModal.js b/src/components/AuthenticationModal/AuthenticationModal.js deleted file mode 100644 index 6d409d2..0000000 --- a/src/components/AuthenticationModal/AuthenticationModal.js +++ /dev/null @@ -1,97 +0,0 @@ -import React, { Component } from 'react' -import {Card, Menu, Form, Modal, Button, Header, Image, Popup} from 'semantic-ui-react' - -class AuthenticationModal extends React.Component { - - constructor(props) { - super(props); - this.state = {email: '', password: '', login: true, activeItem: 'Login', open: true}; - this.handleSubmit = this.handleSubmit.bind(this); - this.handleItemClick= this.handleItemClick.bind(this); - } - - handleItemClick = (e, { name }) => this.setState({ activeItem: name }) - - handleSubmit(e) { - //todo: action stuff - } - - show = (dimmer) => () => this.setState({ dimmer, open: true }) - close = () => this.setState({ open: false }) - - render() { - const { open, dimmer } = this.state - - const cardStyle = { - } - - const { activeItem } = this.state - return ( - - - - - - - - {(activeItem === 'Login') ? ( - -
- - - - - - - - -
- - - - -
-
-
- ) : ( - -
- - - - - - - - - - - - -
- - - - -
- -
-
- )} -
-
-
- ) - } -} - -export default AuthenticationModal - diff --git a/src/components/AuthenticationModal/index.js b/src/components/AuthenticationModal/index.js deleted file mode 100644 index d1f5891..0000000 --- a/src/components/AuthenticationModal/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import AuthenticationModal from './AuthenticationModal' - -export default AuthenticationModal diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js index 74bdbd7..369fff3 100644 --- a/src/components/Header/Header.js +++ b/src/components/Header/Header.js @@ -13,10 +13,7 @@ class Header extends React.Component { render() { const {activeItem} = this.state; const options = [ - { key: 'dashboard', text: 'Dashboard', src: `/dashboard`}, - { key: 'activities', text: 'Activites ', src: `/dashboard?view=activities`}, - { key: 'survey', text: 'Surveys' , src: `/dashboard?view=surveys`}, - { key: 'help', text: 'Help' }, + { key: 'dashboard', text: 'Dashboard', src: `/dashboard?view=activity`}, { key: 'settings', text: 'Settings', src: `/dashboard?view=accountSettings`}, { key: 'sign-out', text: 'Sign Out' }, ]; diff --git a/src/routes/Home/components/HomeView.js b/src/routes/Home/components/HomeView.js index aa3f961..3265abf 100644 --- a/src/routes/Home/components/HomeView.js +++ b/src/routes/Home/components/HomeView.js @@ -1,14 +1,44 @@ -import React from 'react' -import DuckImage from '../assets/Duck.jpg' - -export const HomeView = () => ( -
-

Welcome!

- This is a duck, because Redux! -
-) - -export default HomeView +import React, { Component, PropTypes } from 'react' +import { Button, Header } from 'semantic-ui-react' + +export default class HomeView extends Component { + constructor(props) { + super(props); + } + + static propTypes = { + replace: PropTypes.func.isRequired, + push: PropTypes.func.isRequired, + + redirect: PropTypes.string.isRequired, + isAuthenticated: PropTypes.bool.isRequired, + } + + componentWillMount () { + const {isAuthenticated, replace, redirect} = this.props + if (isAuthenticated) { + console.log("redirect"); + replace(redirect) + } + } + render() { + console.log(this.props) + + return ( +
+
+ Welcome to Groupify +
+ +
+ The most efficient web application for creating teams based on timewise availability. +
+ + +
+ ) + } +} + diff --git a/src/routes/Home/containers/homeContainer.js b/src/routes/Home/containers/homeContainer.js new file mode 100644 index 0000000..64a0033 --- /dev/null +++ b/src/routes/Home/containers/homeContainer.js @@ -0,0 +1,26 @@ +import { connect } from 'react-redux' +import { routerActions } from 'react-router-redux' + + +/* This is a container component. Notice it does not contain any JSX, + nor does it import React. This component is **only** responsible for + wiring in the actions and state necessary to render a presentational + component - in this case, the counter: */ + +import HomeView from '../components/HomeView' + +const mapDispatchToProps = (dispatch) => ({ + /* not sure what does it do, but it is quite important*/ + /* https://github.com/mjrussell/redux-auth-wrapper/blob/master/examples/localStorage/components/Login.js */ + replace: (newLocation) => { dispatch(routerActions.replace(newLocation)) }, + push: (newLocation) => { dispatch(routerActions.push(newLocation)) }, +}) + +const mapStateToProps = (state, ownProps) => { + return { + isAuthenticated: state.authentication.get("jwtToken"), + redirect: ownProps.location.query.redirect || '/dashboard', + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(HomeView) diff --git a/src/routes/Home/index.js b/src/routes/Home/index.js index 5b3578f..36931dc 100644 --- a/src/routes/Home/index.js +++ b/src/routes/Home/index.js @@ -1,4 +1,4 @@ -import HomeView from './components/HomeView' +import HomeView from './containers/homeContainer' // Sync route definition export default { diff --git a/src/routes/Welcome/components/WelcomeView.js b/src/routes/Welcome/components/WelcomeView.js deleted file mode 100644 index 032ebc3..0000000 --- a/src/routes/Welcome/components/WelcomeView.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { Component } from 'react' -import { Button, Header } from 'semantic-ui-react' -import AuthenticationModal from '../../../components/AuthenticationModal' - -export default class WelcomeView extends Component { - constructor(props) { - super(props); - } - - render() { - console.log(this.props) - - return ( -
-
- Welcome to Groupify -
- -
- The most efficient web application for creating teams - based on timewise availability. -
- - - - - - -
- ) - } -} diff --git a/src/routes/Welcome/containers/WelcomeContainer.js b/src/routes/Welcome/containers/WelcomeContainer.js deleted file mode 100644 index 57e0924..0000000 --- a/src/routes/Welcome/containers/WelcomeContainer.js +++ /dev/null @@ -1,18 +0,0 @@ -import {connect} from 'react-redux' - -/* This is a container component. Notice it does not contain any JSX, - nor does it import React. This component is **only** responsible for - wiring in the actions and state necessary to render a presentational - component - in this case, the counter: */ - -import Welcome from '../components/WelcomeView' - - -const mapDispatchToProps = (dispatch) => ({ -}); - -const mapStateToProps = (state, ownProps) => ( { - }) - - -export default connect(mapStateToProps, mapDispatchToProps)(Welcome) diff --git a/src/routes/Welcome/index.js b/src/routes/Welcome/index.js deleted file mode 100644 index 8087323..0000000 --- a/src/routes/Welcome/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import WelcomeView from './components/WelcomeView' - -// Sync route definition -export default { - component: WelcomeView -} diff --git a/src/routes/index.js b/src/routes/index.js index b409da9..f4e604c 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -8,7 +8,7 @@ import SignupRoute from './Signup' import PageNotFound from './PageNotFound' /*home route*/ -import WelcomeRoute from './Welcome' +import HomeRoute from './Home' /* Note: Instead of using JSX, we recommend using react-router PlainRoute objects to build route definitions. */ @@ -16,7 +16,7 @@ export const createRoutes = (store) => { return { path: '/', component: CoreLayout, - indexRoute: WelcomeRoute, + indexRoute: HomeRoute, childRoutes: [ ActivityRoute(store), LoginRoute(store), From 988ae190fc09c61c8cedee00926f2a214bc43769 Mon Sep 17 00:00:00 2001 From: lightertu Date: Sun, 4 Jun 2017 16:58:39 -0700 Subject: [PATCH 15/23] login sign up signout complete --- src/components/Header/Header.js | 133 ++++++++++-------- .../Header/containers/headerContainer.js | 29 ++++ src/components/Header/index.js | 2 +- src/routes/Home/components/HomeView.js | 2 - src/routes/Login/components/LoginView.js | 2 +- .../actions/authenticationActions.js | 23 +++ 6 files changed, 129 insertions(+), 62 deletions(-) create mode 100644 src/components/Header/containers/headerContainer.js diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js index 369fff3..3674581 100644 --- a/src/components/Header/Header.js +++ b/src/components/Header/Header.js @@ -1,76 +1,93 @@ import React from 'react' -import { withRouter, Link } from 'react-router'; -import {Button, Dropdown, Icon, Menu} from 'semantic-ui-react' +import { Link } from 'react-router' +import { Button, Dropdown, Icon, Menu } from 'semantic-ui-react' -class Header extends React.Component { - constructor() { - super(); - this.state = {activeItem: 'home'}; +class _SettingMenu extends React.Component { + constructor () { + super() } - handleItemClick = (e, {name}) => this.setState({activeItem: name}) - - render() { - const {activeItem} = this.state; + render () { const options = [ - { key: 'dashboard', text: 'Dashboard', src: `/dashboard?view=activity`}, - { key: 'settings', text: 'Settings', src: `/dashboard?view=accountSettings`}, - { key: 'sign-out', text: 'Sign Out' }, - ]; + {key: 'dashboard', icon: 'dashboard', text: 'Dashboard', src: `/dashboard?view=activity`}, + {key: 'settings', icon: 'setting', text: 'Settings', src: `/dashboard?view=accountSettings`}, + ] let menuItems = options.map((op) => - - {op.text} - - ); + + {op.text} + ) + const {unauthenticate} = this.props return ( - - - - - + + + + + } + > + + - + Signed in as Michael Young - } - > - - - - Signed in as Michael Young - - - {menuItems} - - - - - + + {menuItems} + + Sign out + + + + + ) } } -/* - export const Header = () => ( -
-

React Redux cool Kit

- - Home - - {' · '} - - Counter - -
- ) - */ +class _AuthenticationMenu extends React.Component { + constructor () { + super() + } + + redirectToLogin = () => { this.props.push('/login') } + redirectToSignup = () => { this.props.push('/signup') } + + render () { + return ( + + + + + + + + + ) + } +} +class Header extends React.Component { + constructor () { + super() + } + + render () { + const {isAuthenticated, unauthenticate, push, replace} = this.props + let createMenuContent = () => + isAuthenticated ? <_SettingMenu push={push} unauthenticate={unauthenticate}/> : + <_AuthenticationMenu push={push}/> + + return ( + + + { createMenuContent() } + + ) + } +} export default Header diff --git a/src/components/Header/containers/headerContainer.js b/src/components/Header/containers/headerContainer.js new file mode 100644 index 0000000..cd291df --- /dev/null +++ b/src/components/Header/containers/headerContainer.js @@ -0,0 +1,29 @@ +/** + * Created by rui on 6/4/17. + */ +import { connect } from 'react-redux' +import { routerActions } from 'react-router-redux' +import * as Actions from '../../../store/authentication/actions' + +/* This is a container component. Notice it does not contain any JSX, + nor does it import React. This component is **only** responsible for + wiring in the actions and state necessary to render a presentational + component - in this case, the counter: */ + +import Header from '../Header' + +const mapDispatchToProps = (dispatch) => ({ + /* not sure what does it do, but it is quite important*/ + /* https://github.com/mjrussell/redux-auth-wrapper/blob/master/examples/localStorage/components/Login.js */ + replace: (newLocation) => { dispatch(routerActions.replace(newLocation)) }, + push: (newLocation) => { dispatch(routerActions.push(newLocation)) }, + unauthenticate: Actions.authenticationActions.unauthenticate(dispatch), +}) + +const mapStateToProps = (state, ownProps) => { + return { + isAuthenticated: state.authentication.get("jwtToken"), + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Header) diff --git a/src/components/Header/index.js b/src/components/Header/index.js index 7cd29d7..8f2d2fd 100644 --- a/src/components/Header/index.js +++ b/src/components/Header/index.js @@ -1,3 +1,3 @@ -import Header from './Header' +import Header from './containers/headerContainer' export default Header diff --git a/src/routes/Home/components/HomeView.js b/src/routes/Home/components/HomeView.js index 3265abf..08a83c6 100644 --- a/src/routes/Home/components/HomeView.js +++ b/src/routes/Home/components/HomeView.js @@ -22,8 +22,6 @@ export default class HomeView extends Component { } } render() { - console.log(this.props) - return (
diff --git a/src/routes/Login/components/LoginView.js b/src/routes/Login/components/LoginView.js index cedcb4e..1d6d242 100644 --- a/src/routes/Login/components/LoginView.js +++ b/src/routes/Login/components/LoginView.js @@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react' import { Button, Grid, Header, Icon, Image, Label, Message, Segment } from 'semantic-ui-react' -import { Form, Input, TextArea, Checkbox, Radio, RadioGroup, Dropdown, Select, } from 'formsy-semantic-ui-react' +import { Form } from 'formsy-semantic-ui-react' class LoginView extends Component { constructor (props) { diff --git a/src/store/authentication/actions/authenticationActions.js b/src/store/authentication/actions/authenticationActions.js index 808f049..a26559b 100644 --- a/src/store/authentication/actions/authenticationActions.js +++ b/src/store/authentication/actions/authenticationActions.js @@ -2,6 +2,28 @@ * Created by rui on 6/2/17. */ +import {routerActions} from 'react-router-redux' +import axios from 'axios' + + +let unauthenticate = (dispatch) => { + return () => { + console.log("unauthenticated"); + + /* this action will be handled in the global authentication reducer, therefore we can + * remove the token from the store */ + dispatch(unauthenticationSuccess()) + + localStorage.removeItem('jwtToken') + + /* remove the axios token from the client side */ + delete axios.defaults.headers.common['Authorization']; + + /* back to the landing page */ + dispatch(routerActions.replace("/")); + } +} + export const UNAUTHENTICATIONSUCCESS = 'UNAUTHENTICATIONSUCCESS' let unauthenticationSuccess = () => { return {type: UNAUTHENTICATIONSUCCESS, payload: null} @@ -15,6 +37,7 @@ let authenticationSuccess = (payload) => { } export { + unauthenticate, authenticationSuccess, unauthenticationSuccess } From 97f265ba9c93a8bb46e7d637f8bb2912f36350f6 Mon Sep 17 00:00:00 2001 From: Matt Almenshad Date: Mon, 5 Jun 2017 06:50:50 -0700 Subject: [PATCH 16/23] more fixing acitvity --- .../participants/controllers/getAllParticipantsController.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/routes/activities/participants/controllers/getAllParticipantsController.js b/server/routes/activities/participants/controllers/getAllParticipantsController.js index b1b0f7c..056c498 100644 --- a/server/routes/activities/participants/controllers/getAllParticipantsController.js +++ b/server/routes/activities/participants/controllers/getAllParticipantsController.js @@ -43,6 +43,9 @@ module.exports = function (req, res, next) { return res.json({ participants: activity.participants, + lockedGroups: activity.lockedGroups, + totalCapacity: activity.totalCapacity, + groupCapacity: activity.groupCapacity, }) }) .catch(createErrorHandler(res, HttpStatus.INTERNAL_SERVER_ERROR)); From 94c8d28cc0bd93334e432b46ac504cf857d8f304 Mon Sep 17 00:00:00 2001 From: Matt Almenshad Date: Mon, 5 Jun 2017 06:51:07 -0700 Subject: [PATCH 17/23] more fixing acitvity --- src/components/utils/QuestionType.js | 128 ++++++++++++++--- .../Activity/components/ActivityView.js | 132 ++++-------------- .../components/GroupCard/GroupCard.js | 119 ++-------------- .../ParticipantListSidebar.js | 89 +++++------- .../ParticipantProfilePopup.js | 56 +++----- .../renderFunctions.js | 69 +++++++++ .../Activity/containers/ActivityContainer.js | 13 +- .../actions/fetchParticpantListActions.js | 25 +--- .../fetchParticipantListActionsHandlers.js | 53 ++++++- .../groupLockActionsHandlers.js | 5 +- ...teParticipantGroupNumberActionsHandlers.js | 25 ++-- .../Activity/modules/reducer/reducer.js | 15 +- .../modules/actions/submitSurveyActions.js | 2 +- src/store/createStore.js | 7 +- 14 files changed, 355 insertions(+), 383 deletions(-) create mode 100644 src/routes/Activity/components/ParticipantProfilePopup/renderFunctions.js diff --git a/src/components/utils/QuestionType.js b/src/components/utils/QuestionType.js index 3a9f484..da8944d 100644 --- a/src/components/utils/QuestionType.js +++ b/src/components/utils/QuestionType.js @@ -7,17 +7,101 @@ import {Map, List} from 'immutable'; let QuestionTypes = Map({ + TimeAvailability: Map({ + type:'TimeAvailability', + display:'Time Availability', + description:'This type allows participants to select days of the week', + options:Map({ + 'tooltip':true, + 'tooltipHint':'Descripe the question to your participants', + 'tooltipLabel':'Description', + + 'answersEnableMaximum':true, + 'answersEnableMaximumHint':'This toggle enables the maximum answers limit', + 'answersEnableMaximumTrueLabel':'Enabled', + 'answersEnableMaximumFalseLabel':'Disabled', + + 'answersMaximum':true, + 'answersMaximumHint':'Maximum amount of answers allowed.', + 'answersMaximumLabel':'Maximum Answers Limit', + + 'answersEnableMinimum':true, + 'answersEnableMinimumHint':'This toggle enables the minimum answers limit', + 'answersEnableMinimumTrueLabel':'Enabled', + 'answersEnableMinimumFalseLabel':'Disabled', + + 'answersMinimum':true, + 'answersMinimumHint':'Minimum amount of answers allowed. (Must be less than 8)', + 'answersMinimumLabel':'Minimum Answers Limit', + + 'answersEnableFilter':false, + 'answersEnableFilterHint':'When filter is enabeled, only options in this list can be selected', + 'answersEnableFilterTrueLabel':'Enabled', + 'answersEnableFilterFalseLabel':'Disabled', + + 'answersFilter':false, + 'answersFilterHint':'When filter is enabeled, participant will only be able to select answers from this field', + 'answersFilterLabel':'Limit Options', + + 'answersFilterEnableBlacklistMode':false, + 'answersFilterEnableBlacklistModeHint':'Blacklist: block filter entries. Whitelist: allow filter entries.', + 'answersFilterEnableBlacklistModeTrueLabel':'Blacklist', + 'answersFilterEnableBlacklistModeFalseLabel':'Whitelist', + }) + }), + ProgrammingLanguages: Map({ + type:'ProgrammingLanguages', + display:'Programming Languages', + description:'This type allows participants select programming languages', + options:Map({ + 'tooltip':true, + 'tooltipHint':'Descripe the question to your participants', + 'tooltipLabel':'Description', + + 'answersEnableMaximum':true, + 'answersEnableMaximumHint':'This toggle enables the maximum answers limit', + 'answersEnableMaximumTrueLabel':'Enabled', + 'answersEnableMaximumFalseLabel':'Disabled', + + 'answersMaximum':true, + 'answersMaximumHint':'Maximum amount of answers allowed.', + 'answersMaximumLabel':'Maximum Answers Limit', + + 'answersEnableMinimum':true, + 'answersEnableMinimumHint':'This toggle enables the minimum answers limit', + 'answersEnableMinimumTrueLabel':'Enabled', + 'answersEnableMinimumFalseLabel':'Disabled', + + 'answersMinimum':true, + 'answersMinimumHint':'Minimum amount of answers allowed.', + 'answersMinimumLabel':'Minimum Answers Limit', + + 'answersEnableFilter':false, + 'answersEnableFilterHint':'Toggles between Limited and Unlimited answers. In Limited mode, studennts can only choose from this list of options. in Unlimited mode, Students may add their own answers', + 'answersEnableFilterTrueLabel':'Limited', + 'answersEnableFilterFalseLabel':'Unlimited', + + 'answersFilter':false, + 'answersFilterHint':'When filter is enabeled, participant will only be able to select answers from this field', + 'answersFilterLabel':'Options', + + 'answersFilterEnableBlacklistMode':false, + 'answersFilterEnableBlacklistModeHint':'Blacklist: block filter entries. Whitelist: allow filter entries.', + 'answersFilterEnableBlacklistModeTrueLabel':'Blacklist', + 'answersFilterEnableBlacklistModeFalseLabel':'Whitelist', + }) + }), CircleSelection: Map({ type:'CircleSelection', - display:'Circle Selection', - description:'This type allows participants to selected multiple answers from a list of options', + display:'Radio Button Selection', + description:'This type allows participants to toggle choises from a set of radio buttons representing options', options:Map({ 'tooltip':true, 'tooltipHint':'Descripe the question to your participants', 'tooltipLabel':'Description', 'answersEnableMaximum':true, - 'answersEnableMaximumHint':'', + 'answersEnableMaximumHint':'This toggle enables the maximum answers limit', 'answersEnableMaximumTrueLabel':'Enabled', 'answersEnableMaximumFalseLabel':'Disabled', @@ -26,7 +110,7 @@ let QuestionTypes = Map({ 'answersMaximumLabel':'Maximum Answers Limit', 'answersEnableMinimum':true, - 'answersEnableMinimumHint':'', + 'answersEnableMinimumHint':'This toggle enables the minimum answers limit', 'answersEnableMinimumTrueLabel':'Enabled', 'answersEnableMinimumFalseLabel':'Disabled', @@ -59,7 +143,7 @@ let QuestionTypes = Map({ 'tooltipLabel':'Description', 'answersEnableMaximum':true, - 'answersEnableMaximumHint':'', + 'answersEnableMaximumHint':'This toggle enables the maximum answers limit', 'answersEnableMaximumTrueLabel':'Enabled', 'answersEnableMaximumFalseLabel':'Disabled', @@ -68,7 +152,7 @@ let QuestionTypes = Map({ 'answersMaximumLabel':'Maximum Answers Limit', 'answersEnableMinimum':true, - 'answersEnableMinimumHint':'', + 'answersEnableMinimumHint':'This toggle enables the minimum answers limit', 'answersEnableMinimumTrueLabel':'Enabled', 'answersEnableMinimumFalseLabel':'Disabled', @@ -77,15 +161,15 @@ let QuestionTypes = Map({ 'answersMinimumLabel':'Minimum Answers Limit', 'answersEnableFilter':true, - 'answersEnableFilterHint':'Limit the answers allowed to answers seperated by comma in this field.', + 'answersEnableFilterHint':'When filter is enabeled, only options in this list can be selected', 'answersEnableFilterTrueLabel':'Enabled', 'answersEnableFilterFalseLabel':'Disabled', 'answersFilter':true, - 'answersFilterHint':'When filter is enabeled, only optiosn in this list can be selected', - 'answersFilterLabel':'Filter', + 'answersFilterHint':'When filter is enabeled, participant will only be able to select answers from this field', + 'answersFilterLabel':'Limit Options', - 'answersFilterEnableBlacklistMode':true, + 'answersFilterEnableBlacklistMode':false, 'answersFilterEnableBlacklistModeHint':'Blacklist: block filter entries. Whitelist: allow filter entries.', 'answersFilterEnableBlacklistModeTrueLabel':'Blacklist', 'answersFilterEnableBlacklistModeFalseLabel':'Whitelist', @@ -93,41 +177,41 @@ let QuestionTypes = Map({ }), 'SingleInputTextField': Map({ type:'SingleInputTextField', - display:'Single Answer Text-Field', - description:'This type allows participants to enter a single textual answer', + display:'Text Field', + description:'This type allows participants to enter information into an Open-Ended Text Field', options:Map({ 'tooltip':true, 'tooltipHint':'Descripe the question to your participants', 'tooltipLabel':'Description', - 'answersEnableMaximum':true, + 'answersEnableMaximum':false, 'answersEnableMaximumHint':'', 'answersEnableMaximumTrueLabel':'Enabled', 'answersEnableMaximumFalseLabel':'Disabled', - 'answersMaximum':true, + 'answersMaximum':false, 'answersMaximumHint':'Maximum amount of characters allowed.', 'answersMaximumLabel':'Maximum Character Limit', - 'answersEnableMinimum':true, + 'answersEnableMinimum':false, 'answersEnableMinimumHint':'', 'answersEnableMinimumTrueLabel':'Enabled', 'answersEnableMinimumFalseLabel':'Disabled', - 'answersMinimum':true, + 'answersMinimum':false, 'answersMinimumHint':'Minimum amount of characters allowed.', - 'answersMinimumLabel':'Minimum Characters Limit', + 'answersMinimumLabel':'Minimum Character Limit', - 'answersEnableFilter':true, - 'answersEnableFilterHint':'Limit the answers allowed to answers seperated by comma in this field.', + 'answersEnableFilter':false, + 'answersEnableFilterHint':'Limit the answers allowed to only these options.', 'answersEnableFilterTrueLabel':'Enabled', 'answersEnableFilterFalseLabel':'Disabled', - 'answersFilter':true, - 'answersFilterHint':'When filter is enabeled, only optiosn in this list can be selected', + 'answersFilter':false, + 'answersFilterHint':'When filter is enabeled, only options in this list can be selected', 'answersFilterLabel':'Filter', - 'answersFilterEnableBlacklistMode':true, + 'answersFilterEnableBlacklistMode':false, 'answersFilterEnableBlacklistModeHint':'Blacklist: block filter entries. Whitelist: allow filter entries.', 'answersFilterEnableBlacklistModeTrueLabel':'Blacklist', 'answersFilterEnableBlacklistModeFalseLabel':'Whitelist', diff --git a/src/routes/Activity/components/ActivityView.js b/src/routes/Activity/components/ActivityView.js index d82c58e..926dd89 100644 --- a/src/routes/Activity/components/ActivityView.js +++ b/src/routes/Activity/components/ActivityView.js @@ -3,11 +3,13 @@ * Additions made by Joseph 5/28/17 */ import React from 'react' -import {Grid, Segment} from 'semantic-ui-react' +import {Grid, Segment, Button} from 'semantic-ui-react' import {DragDropContext} from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; import ParticipantListSidebar from "./ParticipantListSidebar" +import {Map, List, Set} from 'immutable'; + import GroupCard from "./GroupCard/GroupCard" import FilterMenu from "./FilterMenu" @@ -36,83 +38,17 @@ export class ActivityCardViewWrapper extends React.Component { export class ActivityView extends React.Component { constructor(props) { super(props); - - this.state = ({filters: []}); - this.toggleLock = this.toggleLock.bind(this); - } componentWillMount() { this.props.fetchParticipantList(this.props.activityId); } - toggleLock(group) { - this.props.toggleLock(group); - } - - setFilterValues = (input, event) => { - console.log('---------------------------'); - console.log('SET FILTER VALUES'); - console.log(input); - console.log(event.target); - console.log('---------------------------'); - let field = this.state[input]; - if(event.target.getAttribute('class') === "delete icon") { - let item = event.target.parentNode.getAttribute('value'); - let index = field.indexOf(item) - if(index >= 0) { - field.splice(index, 1); // remove item from filter - } - } else { - if(event.target.getAttribute('name') !== "-search") { - if(event.target.getAttribute('name') === null) { - field.push(event.target.parentNode.getAttribute('name')); // add item to filter - } else { - field.push(event.target.getAttribute('name')); // add item to filter - } - } - } - this.setState({field:field}); - } - - setCurrentlySelected(id) { this.props.filterParticipantsMatch(id); } - - render() { + render (){ const itemsPerRow = 10; const cardsPerRow = 1; let numOfGroups = this.props.totalCapacity / this.props.groupCapacity; - const refilterParticipants = (participants) => { - const hasSkills = (filterSkills, skills) => { - skills = skills.map( (skill) => (skill.name)); - - let result = true; - for (let i = 0; i < filterSkills.length; i++) { - result &= skills.includes(filterSkills[i]); - } - return result; - } - - const hasFilterValues = (filter, participant) => { - if (filter.length === 0) { - return true; - } - - const skills = participant.skills, - availiblity = participant.availability; - - return hasSkills(filter, skills); - } - - return participants.filter( - (participant) => { - return hasFilterValues(this.props.filter, participant); - } - ) - } - - /* the master participants list is filtered here it is just a hacky implementation*/ - let participants = refilterParticipants(this.props.participants); - - let separateIntoGroups = (participants) => { + + let separateParticipantsIntoGroups = () => { let groups = []; for (let i = 0; i < numOfGroups; i++) { groups.push({ @@ -120,20 +56,19 @@ export class ActivityView extends React.Component { participants: [] }) } - - for (let i = 0; i < participants.length; i++) { - let participantGroupNumber = participants[i].groupNumber; + this.props.participants.forEach((participant) => { + console.log(participant); + let participantGroupNumber = participant.get('groupNumber'); if (participantGroupNumber >= 0 && participantGroupNumber < numOfGroups) { - groups[participantGroupNumber].participants.push(participants[i]); + groups[participantGroupNumber].participants.push(participant); } - } + }); return groups; }; - let dragging = (this.props.matching.get("current").length > 0); - let getGroupCards = (groups) => { + console.log(this.props.activityId) return ( groups.map( (group, i) => ( @@ -144,45 +79,30 @@ export class ActivityView extends React.Component { itemsPerRow={ itemsPerRow } updateParticipantGroupNumber={ this.props.updateParticipantGroupNumber } activityId={ this.props.activityId } - setCurrentlySelected={ this.setCurrentlySelected.bind(this) } - toggleLock={ this.toggleLock.bind(this) } - matching={ this.props.matching.get("matchingCriteria") } - draggedUser={ this.props.matching.get("current") } + setCurrentlySelected={(v) => console.log(v) } + toggleLock={(v) => console.log(v) } group={ i } - unlocked={ this.props.unlocked.get(i) } - filters={ this.state.filters } - dragging={dragging} + unlocked={ this.props.lockedGroups.get(i)} /> ) ) ) }; - return (
- - - { - (this.props.participants.length > 0) && - - } - - - { getGroupCards(separateIntoGroups(participants)) } - + + console.log(v) }> + + { getGroupCards(separateParticipantsIntoGroups()) } + -
+
) } } diff --git a/src/routes/Activity/components/GroupCard/GroupCard.js b/src/routes/Activity/components/GroupCard/GroupCard.js index ab20dd2..7fd0bbe 100644 --- a/src/routes/Activity/components/GroupCard/GroupCard.js +++ b/src/routes/Activity/components/GroupCard/GroupCard.js @@ -42,12 +42,10 @@ class DraggableCard extends React.Component { offset={ 0 } name={ participant.name } image={ participant.image } + surveyResponses={ this.props.surveyResponses } groupNumber={participant.groupNumber } - skills={ participant.skills } - availability={ participant.availability } participantId={ participant.participantId }/>
- if (this.props.unlocked) { return ( participantCard ) } @@ -78,28 +76,25 @@ const participantTarget = { ) class GroupCard extends React.Component { static propTypes = { + /* activityId: PropTypes.string.isRequired, participants: PropTypes.array.isRequired, capacity: PropTypes.number.isRequired, groupNumber: PropTypes.number.isRequired, itemsPerRow: PropTypes.number.isRequired, updateParticipantGroupNumber: PropTypes.func.isRequired + */ } constructor (props) { super(props) - /* - this.state = { - matchingStatusOpen: true, availability: [], skills: [] - } - */ } render () { const {connectDropTarget, isOver} = this.props let generateEmptySpots = () => { - let emptyNum = this.props.capacity - this.props.participants.length + let emptyNum = this.props.capacity - this.props.participants.size let result = [] for (let i = 0; i < emptyNum; i++) { result.push( @@ -146,89 +141,14 @@ class GroupCard extends React.Component { return skillCountMap } - let skills = generateSkillCountMap(this.props.participants) - let days = overAllAvailability(this.props.participants) - let numsTodays = { - 1: 'monday', - 2: 'tuseday', - 3: 'wednesday', - 4: 'thursday', - 5: 'friday', - 6: 'saturday', - 0: 'sunday' - } - let daysToNums = { - 'monday': 1, - 'tuseday': 2, - 'wednesday': 3, - 'thursday': 4, - 'friday': 5, - 'saturday': 6, - 'sunday': 0 - } - let count = 0 - let matchingColor = '' - let i - let itemCount = this.props.matching.size - let view = true - let result = 0 - if (itemCount > 0) { - for (i = 0; i < days.length; i++) { - if (this.props.matching.has(numsTodays[i]) && days[i]) { - count++ - } - - } - - let keys = Object.keys(skills) - for (i = 0; i < keys.length; i++) { - if (this.props.matching.has(keys[i])) { - count++ - } - } - - result = Math.round((count / itemCount) * 100) / 100 - - if (result > .70 || this.props.participants.length === 0) { - matchingColor = 'green' - } else if (result > .45) { - matchingColor = 'yellow' - } else { - matchingColor = 'red' - } - } - - for (i = 0; i < this.props.filters.length; i++) { - if (this.props.filters[i] in daysToNums) { - if (!days[daysToNums[this.props.filters[i]]]) { - view = false - break - } - } else { - if (Object.keys(skills).indexOf(this.props.filters[i]) === -1) { - view = false - break - } - } - } - - let background = '' - if (this.props.participants.some((el) => el.participantId === this.props.draggedUser)) { - background = 'black' - } - - if (this.props.unlocked) { - matchingColor = 'grey' - } - let display = (
- Group { this.props.groupNumber }   - {/*matching:  {Math.round(result*100)}% */} - - { - this.props.participants.map((participant) => - - ) - } { generateEmptySpots() } - - - { (this.props.participants.length > 0 ) && - } - - { (this.props.participants.length > 0 ) && - } + { + //Question Segment + }
) diff --git a/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js b/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js index 3b16927..47995e4 100644 --- a/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js +++ b/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js @@ -38,7 +38,8 @@ class DraggableParticipantListItem extends React.Component { render () { const {image, name, participantId, connectDragSource, isDragging} = this.props return connectDragSource( -
@@ -51,12 +52,14 @@ class DraggableParticipantListItem extends React.Component { class Participant extends React.Component { static propTypes = { + /* participantId: PropTypes.string.isRequired, name: PropTypes.string.isRequired, image: PropTypes.string.isRequired, groupNumber: PropTypes.number.isRequired, availability: PropTypes.array.isRequired, skills: PropTypes.array.isRequired, + */ } render () { @@ -64,17 +67,17 @@ class Participant extends React.Component { + setCurrentlySelected={(v) => {console.log(v)}}/> ) return ( ( - participants.filter((participantObj) => ( - participantObj.groupNumber < 0 - )).length + let getUngroupedNumber = () => ( + this.props.participants.filter((participantObj) => ( + participantObj.get('groupNumber') < 0 + )).size ) + let generateSidebarList = (participants) => ( { - participants.filter((participantObj) => ( - participantObj.groupNumber == -1 - )) - - .map((participantObj) => ( - - )) + participants.filter((participantObj) => { + return (participantObj.get('groupNumber') === -1); + }) + .map((participantObj) => { + return + }) } ) @@ -194,7 +180,6 @@ class ParticipantListSidebar extends React.Component {
) - return connectDropTarget(
@@ -203,28 +188,22 @@ class ParticipantListSidebar extends React.Component { open={ true } zDepth={ 1 } width={290} - containerStyle={ {backgroundColor: (!this.props.isOver) ? '#F6F7F9' : '#EFF0F2'} } + containerStyle={{backgroundColor: (!this.props.isOver) ? '#F6F7F9' : '#EFF0F2'}} style={ {zIndex: '1000 !important', width: "290px"} } >
{ - (this.props.participants.length <= 0) ? generateEmptyMessage() : ((getUngroupedNumber(this.props.participants)) ? generateSidebarList(this.props.participants) : generateEmailButton()) + (this.props.participants.size <= 0) ? + generateEmptyMessage() + : + ((getUngroupedNumber(this.props.participants)) ? + generateSidebarList(this.props.participants) + : + generateEmailButton()) } - {/* - - */}
diff --git a/src/routes/Activity/components/ParticipantProfilePopup/ParticipantProfilePopup.js b/src/routes/Activity/components/ParticipantProfilePopup/ParticipantProfilePopup.js index 488312c..df46dec 100644 --- a/src/routes/Activity/components/ParticipantProfilePopup/ParticipantProfilePopup.js +++ b/src/routes/Activity/components/ParticipantProfilePopup/ParticipantProfilePopup.js @@ -4,41 +4,31 @@ import React from 'react' import {Card, Popup, Image, Label, Button, Icon} from 'semantic-ui-react' import PropTypes from "prop-types" - +import * as renderFunctions from './renderFunctions' import getColorByLanguage from "../../modules/LanguageColorMap"; class PopupContent extends React.Component { static propTypes = { + /* name: PropTypes.string.isRequired, image: PropTypes.string.isRequired, groupNumber: PropTypes.number.isRequired, availability: PropTypes.array.isRequired, skills: PropTypes.array.isRequired + */ }; - render() { - let generateAvailabilities = (availability) => { - let weekdayInitial = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; - if (availability.length !== 7) { - alert("availability array: is greater than 7") - } - - let labels = []; - for (let i = 0; i < weekdayInitial.length; i++) { - (availability[i]) ? - labels.push(): - labels.push(); - } - return labels; - }; - - let generateSkillLabels = (skills) => { - let i = 0; - return skills.map((skill) => - + render() { + let answerSegments = []; + this.props.surveyResponses.forEach((response, index) => { + (renderFunctions[response.get('question')]) && + answerSegments.push( + + + {renderFunctions[response.get('question')](response.get('answer'))} + + ); - }; + }) return ( @@ -55,16 +45,7 @@ class PopupContent extends React.Component { } - - - { generateAvailabilities(this.props.availability)} - - - - - { generateSkillLabels(this.props.skills) } - - + {answerSegments} ); } @@ -73,6 +54,7 @@ class PopupContent extends React.Component { class ParticipantProfilePopup extends React.Component { static propTypes = { + /* name: PropTypes.string.isRequired, participantId: PropTypes.string.isRequired, image: PropTypes.string.isRequired, @@ -83,11 +65,12 @@ class ParticipantProfilePopup extends React.Component { trigger: PropTypes.node.isRequired, position:PropTypes.string.isRequired, offset: PropTypes.number.isRequired + */ }; render() { return ( - diff --git a/src/routes/Activity/components/ParticipantProfilePopup/renderFunctions.js b/src/routes/Activity/components/ParticipantProfilePopup/renderFunctions.js new file mode 100644 index 0000000..6223af5 --- /dev/null +++ b/src/routes/Activity/components/ParticipantProfilePopup/renderFunctions.js @@ -0,0 +1,69 @@ +/* + * Created by Matt on 05/25/17 + * This file defines a List of Maps containing the question types and what features they might use + */ + +import React from 'react' +import {Map, List, Set} from 'immutable'; +import {Card, Popup, Image, Label, Button, Icon} from 'semantic-ui-react' +import getColorByLanguage from "../../modules/LanguageColorMap"; + +function TimeAvailability (answers) { + let weekdays= ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + + let labels = []; + weekdays.forEach((day, index) => { + (answers.has(day)) ? + labels.push() + : + labels.push() + }) + return labels; +} + +function ProgrammingLanguages (answers) { + return answers.map((answer, index) => + + ); +} + +function CircleSelection (answers) { + let labels = []; + weekdays.forEach((day, index) => { + labels.push() + }) + return labels; + +} + +function MultiInputTextField (answers) { + return answers.map((answer, index) => + + ); +} + +function SingleInputTextField (answers) { + return answers.map((answer, index) => + + ); +} + +export { + TimeAvailability, + ProgrammingLanguages, + CircleSelection, + MultiInputTextField, + SingleInputTextField, +} diff --git a/src/routes/Activity/containers/ActivityContainer.js b/src/routes/Activity/containers/ActivityContainer.js index 7a5e0d4..8feef67 100644 --- a/src/routes/Activity/containers/ActivityContainer.js +++ b/src/routes/Activity/containers/ActivityContainer.js @@ -25,12 +25,17 @@ const mapDispatchToProps = (dispatch) => ({ const mapStateToProps = (state, ownProps) => { return { activityId: ownProps.location.query.id, - participants: state.activity.get("participants"), + groupCapacity: state.activity.get("groupCapacity"), totalCapacity: state.activity.get("totalCapacity"), - matching: state.activity.get("matching"), - unlocked: state.activity.get("unlocked"), - filter: state.activity.get("filter") + + participants: state.activity.get("participants"), + + lockedGroups: state.activity.get("lockedGroups"), + + allAnswers: state.activity.get("allAnswers"), + filter: state.activity.get("filter"), + } }; diff --git a/src/routes/Activity/modules/actions/fetchParticpantListActions.js b/src/routes/Activity/modules/actions/fetchParticpantListActions.js index b956dc2..984b6f4 100644 --- a/src/routes/Activity/modules/actions/fetchParticpantListActions.js +++ b/src/routes/Activity/modules/actions/fetchParticpantListActions.js @@ -5,40 +5,21 @@ import axios from "axios"; import generateUsers from "../UserGenerator" import { sortParticipants } from "./userMatchingActions" import { createLocks } from "./groupLockActions" -const SERVER_URL = "http://localhost:3000"; -const numOfPeople = 50, - groupCapacity = 3, - totalCapacity = 60; +const SERVER_URL = "http://" + window.location.host; /* fetching, get requests */ export const FETCH_PARTICIPANT_LIST = "FETCH_PARTICIPANT_LIST"; let fetchParticipantList = (dispatch) => { return (activityId) => { dispatch({ type: FETCH_PARTICIPANT_LIST }); - let participants = generateUsers(groupCapacity, numOfPeople) - dispatch(fetchParticipantListSuccess( - { - participants: participants, - groupCapacity: groupCapacity, - totalCapacity: totalCapacity - } - )); - - dispatch(sortParticipants(participants)); - - dispatch(createLocks((totalCapacity / groupCapacity))); - - /* let url = SERVER_URL + "/api/activities/" + activityId + "/participants/"; axios.get(url) .then((response) => { - //console.log(JSON.stringify(response, null, 2)); - dispatch(fetchParticipantListSuccess(response.data)); + dispatch(fetchParticipantListSuccess(response.data)); }) .catch((error) => { - dispatch(fetchParticipantListFailure(error)); + dispatch(fetchParticipantListFailure(error)); }); - */ } }; diff --git a/src/routes/Activity/modules/reducer/actionsHandlers/fetchParticipantListActionsHandlers.js b/src/routes/Activity/modules/reducer/actionsHandlers/fetchParticipantListActionsHandlers.js index b210b32..9eba950 100644 --- a/src/routes/Activity/modules/reducer/actionsHandlers/fetchParticipantListActionsHandlers.js +++ b/src/routes/Activity/modules/reducer/actionsHandlers/fetchParticipantListActionsHandlers.js @@ -1,17 +1,58 @@ /** * Created by rui on 5/9/17. + * Developed by Matt on 6/2/17 */ -// TODO: needs to be implemented - +import {Map, Set, List, OrderedSet} from 'immutable'; let handleFetchParticipantList = (state, payload) => { return state; }; let handleFetchParticipantListSuccess = (state, payload) => { - let update = state.set("participants", payload.participants); - update = update.set("groupCapacity", payload.groupCapacity); - update = update.set("totalCapacity", payload.totalCapacity) - return update + let participantList = List([]); + + payload.participants.forEach((participant) => { + participantList = participantList.push(Map(participant)); + }); + + let newState = state.set("participants", participantList); + + + newState = newState.update('participants', (participants) => { + let newParticipants = List([]); + participants.forEach((participant) => { + let newSurveyResponses = List([]); + participant.get('surveyResponses').forEach((response) => { + let newResponse = Map({ + question: response.question , + answer: Set(response.answer) + }); + newSurveyResponses = newSurveyResponses.push(newResponse); + }); + newParticipants = newParticipants.push(Map({ + surveyResponses: newSurveyResponses, + participantId:participant.get('_id'), + groupNumber: participant.get('groupNumber'), + name:participant.get('name'), + image:participant.get('image') + })); + }); + return newParticipants; + }); + + newState = newState.update("allAnswers", (allAnswers) => { + let newAllAnswers = Set([]); + newState.get('participants').forEach((participant) => { + participant.get('surveyResponses').forEach((response) => { + newAllAnswers = newAllAnswers.union(response.get('answer')); + }); + }); + return newAllAnswers; + }); + + newState = newState.set("groupCapacity", payload.groupCapacity); + newState = newState.set("totalCapacity", payload.totalCapacity); + newState = newState.set("lockedGroups", Set(payload.lockedGroups)); + return newState }; let handleFetchParticipantListFailure = (state, payload) => { diff --git a/src/routes/Activity/modules/reducer/actionsHandlers/groupLockActionsHandlers.js b/src/routes/Activity/modules/reducer/actionsHandlers/groupLockActionsHandlers.js index 2f8e389..90f6cc7 100644 --- a/src/routes/Activity/modules/reducer/actionsHandlers/groupLockActionsHandlers.js +++ b/src/routes/Activity/modules/reducer/actionsHandlers/groupLockActionsHandlers.js @@ -10,11 +10,12 @@ let handleCreateLocks = (state, payload) => { } let handleToggleLock = (state, payload) => { + console.log('Toggle'); let update = state.setIn(["unlocked", payload], !state.getIn(["unlocked", payload])); - return update; + return state; } export { handleCreateLocks, handleToggleLock -} \ No newline at end of file +} diff --git a/src/routes/Activity/modules/reducer/actionsHandlers/updateParticipantGroupNumberActionsHandlers.js b/src/routes/Activity/modules/reducer/actionsHandlers/updateParticipantGroupNumberActionsHandlers.js index 378af15..ccc4a14 100644 --- a/src/routes/Activity/modules/reducer/actionsHandlers/updateParticipantGroupNumberActionsHandlers.js +++ b/src/routes/Activity/modules/reducer/actionsHandlers/updateParticipantGroupNumberActionsHandlers.js @@ -14,21 +14,16 @@ let arrayObjectIndexOf = (myArray, searchTerm, property) => { }; let handleUpdateParticipantGroupsNumber = (state, payload) => { - let newState = (JSON.parse(JSON.stringify(state))), - - participantId = payload.participantId, - oldGroupNumber = payload.oldGroupNumber, - newGroupNumber = payload.newGroupNumber, - participants = newState.participants, - participantIndex = arrayObjectIndexOf(participants, participantId, "participantId"); - - // console.log(JSON.stringify(participantIndex, null, 2)); - participants[participantIndex].groupNumber = newGroupNumber; - let temp = Object.assign({}, participants[participantIndex]); - participants.splice(participantIndex, 1); - participants.push(temp); - let update = state.set("participants", participants); - return update; + console.log(payload) + console.log(state) + let index = state.get('participants') + .findIndex((participant) => (participant.get('participantId') === payload.participantId)) + let newState = ((index == -1) ? + state.setIn(['participants', index], payload.newGroupNumber) + : + state) + + return newState; }; let handleUpdateParticipantGroupsNumberSuccess = (state, payload) => { diff --git a/src/routes/Activity/modules/reducer/reducer.js b/src/routes/Activity/modules/reducer/reducer.js index 62028ce..6158f5c 100644 --- a/src/routes/Activity/modules/reducer/reducer.js +++ b/src/routes/Activity/modules/reducer/reducer.js @@ -1,16 +1,23 @@ /** * Created by rui on 4/18/17. */ -import { Map, List } from "immutable" +import { Map, List, Set } from "immutable" import * as Actions from "../actions" import * as ActionsHandlers from "./actionsHandlers" const initialState = Map({ - participants: [], + currentlyDragging: '', + groupCapacity: 0, totalCapacity: 0, - unlocked: List([]), - filter: [], + + participants: List([]), + + lockedGroups: Set([]), + + allAnswers: Set([]), + filter: Set([]), + matching: Map({ current: "", matchingParticipants: new Set(), diff --git a/src/routes/Survey/modules/actions/submitSurveyActions.js b/src/routes/Survey/modules/actions/submitSurveyActions.js index b5d37f0..3362b87 100644 --- a/src/routes/Survey/modules/actions/submitSurveyActions.js +++ b/src/routes/Survey/modules/actions/submitSurveyActions.js @@ -13,7 +13,7 @@ let submitSurvey = (dispatch) => { payload.questions.forEach((question) => { surveyResponses.push( { - question:question.get('title'), + question:question.get('type'), answer:question.get('answers') } ); diff --git a/src/store/createStore.js b/src/store/createStore.js index 90baee8..1a2b50f 100644 --- a/src/store/createStore.js +++ b/src/store/createStore.js @@ -3,6 +3,7 @@ import thunk from 'redux-thunk' import {browserHistory} from 'react-router' import makeRootReducer from './reducers' import {updateLocation} from './location' +import Immutable from 'immutable'; import generateUsers from "../routes/Activity/modules/UserGenerator" @@ -20,7 +21,11 @@ export default (initialState = {}) => { let composeEnhancers = compose; if (__DEV__) { - const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; + const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ + serialize: { + immutable: Immutable + } + }); if (typeof composeWithDevToolsExtension === 'function') { composeEnhancers = composeWithDevToolsExtension } From 1334def7956286f602d7ae44efd938cb9b3fd40a Mon Sep 17 00:00:00 2001 From: Matt Almenshad Date: Mon, 5 Jun 2017 06:51:29 -0700 Subject: [PATCH 18/23] more fixing acitvity --- server/models/Participant.js | 4 ++-- .../createParticipantController.js | 24 ++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/server/models/Participant.js b/server/models/Participant.js index 674b01b..ad1edb7 100644 --- a/server/models/Participant.js +++ b/server/models/Participant.js @@ -32,8 +32,8 @@ const ParticipantSchema = new Schema({ }, image: { - data: Buffer, - contentType: String + type: String, + default: "", }, diff --git a/server/routes/activities/participants/controllers/createParticipantController.js b/server/routes/activities/participants/controllers/createParticipantController.js index ad20bb0..e9cdbf7 100644 --- a/server/routes/activities/participants/controllers/createParticipantController.js +++ b/server/routes/activities/participants/controllers/createParticipantController.js @@ -11,6 +11,28 @@ const HttpStatus = require("http-status-codes"); const properties = ['name', 'image', 'email', 'surveyResponses']; +const images = [ + "https://react.semantic-ui.com/assets/images/avatar/large/jenny.jpg", + "https://react.semantic-ui.com/assets/images/avatar/large/justen.jpg", + "https://react.semantic-ui.com/assets/images/avatar/large/stevie.jpg", + "https://react.semantic-ui.com/assets/images/avatar/large/veronika.jpg", + "https://semantic-ui.com/images/avatar/large/steve.jpg", + "https://semantic-ui.com/images/avatar2/large/kristy.png", + "https://semantic-ui.com/images/avatar2/large/matthew.png", + "https://semantic-ui.com/images/avatar2/large/molly.png", + "https://semantic-ui.com/images/avatar2/large/elyse.png", + "https://semantic-ui.com/images/avatar/large/daniel.jpg", + "https://semantic-ui.com/images/avatar/large/helen.jpg", + +]; + +let randomBetween = (minVal, maxVal) => { + return Math.floor(Math.random() * (maxVal-minVal+1)) + minVal; +}; + +function pickImage () { + return images[randomBetween(0, images.length-1)]; +}; function validateInput(req) { let payload = req.body; @@ -64,7 +86,7 @@ module.exports = function (req, res, next) { _activity: activityId, email: payload.email, name: payload.name, - image: payload.image, + image: pickImage(), surveyResponses: payload.surveyResponses, }); newParticipant.save() From e5a77cb23c4a8f190b65632cccbad4e9667d8aa1 Mon Sep 17 00:00:00 2001 From: Matt Almenshad Date: Mon, 5 Jun 2017 11:51:30 -0700 Subject: [PATCH 19/23] Prepping to merge with backend again --- server/models/Participant.js | 12 +-- .../Activity/components/ActivityView.js | 3 +- .../components/GroupCard/GroupCard.js | 32 +++++--- .../ParticipantListSidebar.js | 3 + .../updateParticipantGroupNumberActions.js | 10 +-- ...teParticipantGroupNumberActionsHandlers.js | 6 +- src/store/createStore.js | 11 +-- src/store/createStore.js.orig | 74 +++++++++++++++++++ 8 files changed, 117 insertions(+), 34 deletions(-) create mode 100644 src/store/createStore.js.orig diff --git a/server/models/Participant.js b/server/models/Participant.js index ad1edb7..e74dc10 100644 --- a/server/models/Participant.js +++ b/server/models/Participant.js @@ -19,11 +19,11 @@ const ParticipantSchema = new Schema({ required: true, }, - // _creator: { - // type: Schema.ObjectId, - // ref: 'User', - // required: true, - // }, + _creator: { + type: Schema.ObjectId, + ref: 'User', + required: true, + }, _activity :{ type: Schema.ObjectId, @@ -77,7 +77,9 @@ ParticipantSchema.pre('save', function(next){ ParticipantSchema.methods.getPublicFields = function () { return { + _id: this._id, name: this.name, + email: this.email, image: this.image, groupNumber: this.groupNumber, surveyResponses: this.surveyResponses, diff --git a/src/routes/Activity/components/ActivityView.js b/src/routes/Activity/components/ActivityView.js index 926dd89..59467dd 100644 --- a/src/routes/Activity/components/ActivityView.js +++ b/src/routes/Activity/components/ActivityView.js @@ -57,7 +57,6 @@ export class ActivityView extends React.Component { }) } this.props.participants.forEach((participant) => { - console.log(participant); let participantGroupNumber = participant.get('groupNumber'); if (participantGroupNumber >= 0 && participantGroupNumber < numOfGroups) { groups[participantGroupNumber].participants.push(participant); @@ -68,7 +67,6 @@ export class ActivityView extends React.Component { }; let getGroupCards = (groups) => { - console.log(this.props.activityId) return ( groups.map( (group, i) => ( @@ -94,6 +92,7 @@ export class ActivityView extends React.Component { {console.log(v)}} updateParticipantGroupNumber={ this.props.updateParticipantGroupNumber } activityId={ this.props.activityId } /> diff --git a/src/routes/Activity/components/GroupCard/GroupCard.js b/src/routes/Activity/components/GroupCard/GroupCard.js index 7fd0bbe..dea4187 100644 --- a/src/routes/Activity/components/GroupCard/GroupCard.js +++ b/src/routes/Activity/components/GroupCard/GroupCard.js @@ -15,10 +15,11 @@ const transparentImage = 'https://upload.wikimedia.org/wikipedia/commons/thumb/0 const participantCardItemSource = { beginDrag(props) { + console.log(props); props.setCurrentlySelected(props.participant.participantId) // set current selected card return { - participantId: props.participant.participantId, - oldGroupNumber: props.participant.groupNumber + participantId: props.participant.get('participantId'), + oldGroupNumber: props.participant.get('groupNumber') } } } @@ -37,14 +38,14 @@ class DraggableCard extends React.Component { let participantCard =
} + trigger={ } position="top right" offset={ 0 } - name={ participant.name } - image={ participant.image } - surveyResponses={ this.props.surveyResponses } - groupNumber={participant.groupNumber } - participantId={ participant.participantId }/> + name={ participant.get('name') } + image={ participant.get('image') } + surveyResponses={ participant.get('surveyResponses') } + groupNumber={participant.get('groupNumber') } + participantId={ participant.get('participantId') }/>
if (this.props.unlocked) { return ( participantCard ) @@ -94,7 +95,7 @@ class GroupCard extends React.Component { const {connectDropTarget, isOver} = this.props let generateEmptySpots = () => { - let emptyNum = this.props.capacity - this.props.participants.size + let emptyNum = this.props.capacity - this.props.participants.length let result = [] for (let i = 0; i < emptyNum; i++) { result.push( @@ -161,12 +162,21 @@ class GroupCard extends React.Component { Group { this.props.groupNumber }   + + { this.props.participants.map((participant) => + console.log(v) } + unlocked= { this.props.unlocked } + /> + )} { generateEmptySpots() } - { diff --git a/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js b/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js index 47995e4..22cb368 100644 --- a/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js +++ b/src/routes/Activity/components/ParticipantListSidebar/ParticipantListSidebar.js @@ -68,6 +68,7 @@ class Participant extends React.Component { name={ this.props.name } image={ this.props.image } surveyResponses={ this.props.surveyResponses } + setCurrentlySelected={(v) => {console.log(v)}} participantId={ this.props.participantId } setCurrentlySelected={(v) => {console.log(v)}}/> ) @@ -77,6 +78,7 @@ class Participant extends React.Component { name={ this.props.name } image={ this.props.image } surveyResponses={ this.props.surveyResponses } + setCurrentlySelected={(v) => {console.log(v)}} groupNumber={ this.props.groupNumber } position="right center" offset={ 20 } @@ -147,6 +149,7 @@ class ParticipantListSidebar extends React.Component { participantId={ participantObj.get('participantId') } surveyResponses={ participantObj.get('surveyResponses') } name={ participantObj.get('name') } + setCurrentlySelected={(v) => {console.log(v)}} image={ participantObj.get('image') } groupNumber={ participantObj.get('groupNumber') } /> diff --git a/src/routes/Activity/modules/actions/updateParticipantGroupNumberActions.js b/src/routes/Activity/modules/actions/updateParticipantGroupNumberActions.js index c01e37a..c32230b 100644 --- a/src/routes/Activity/modules/actions/updateParticipantGroupNumberActions.js +++ b/src/routes/Activity/modules/actions/updateParticipantGroupNumberActions.js @@ -15,17 +15,15 @@ let updateParticipantGroupNumber = (dispatch) => { oldGroupNumber: oldGroupNumber, newGroupNumber: newGroupNumber }; - + console.log('-------------------------------'); + console.log({groupNumber:payload.newGroupNumber}); dispatch({ type: UPDATE_PARTICIPANT_GROUP_NUMBER, payload: payload }); - let url = SERVER_URL + "/api/activities/" + activityId + "/participants/" + participantId; - axios.put(url, { - oldGroupsNumber: oldGroupNumber, - newGroupNumber: newGroupNumber - }) + let url = SERVER_URL + "/api/activities/" + activityId + "/participants/" + participantId + '/groupNumber'; + axios.put(url, {groupNumber:payload.newGroupNumber}) .then((response) => { dispatch(updateParticipantGroupNumberSuccess(response)); }) diff --git a/src/routes/Activity/modules/reducer/actionsHandlers/updateParticipantGroupNumberActionsHandlers.js b/src/routes/Activity/modules/reducer/actionsHandlers/updateParticipantGroupNumberActionsHandlers.js index ccc4a14..52c0419 100644 --- a/src/routes/Activity/modules/reducer/actionsHandlers/updateParticipantGroupNumberActionsHandlers.js +++ b/src/routes/Activity/modules/reducer/actionsHandlers/updateParticipantGroupNumberActionsHandlers.js @@ -18,10 +18,12 @@ let handleUpdateParticipantGroupsNumber = (state, payload) => { console.log(state) let index = state.get('participants') .findIndex((participant) => (participant.get('participantId') === payload.participantId)) + console.log(payload.participantId) + console.log(index) let newState = ((index == -1) ? - state.setIn(['participants', index], payload.newGroupNumber) + state : - state) + state.setIn(['participants', index, 'groupNumber'], payload.newGroupNumber)) return newState; }; diff --git a/src/store/createStore.js b/src/store/createStore.js index 5955edb..4b87862 100644 --- a/src/store/createStore.js +++ b/src/store/createStore.js @@ -1,10 +1,11 @@ -import {applyMiddleware, compose, createStore} from 'redux' +import { applyMiddleware, compose, createStore } from 'redux' import thunk from 'redux-thunk' import baseHistory from './baseHistory' import makeRootReducer from './reducers' import { updateLocation } from './location' import { routerMiddleware } from 'react-router-redux' import { browserHistory } from 'react-router' +import Immutable from 'immutable'; export default (initialState = {}) => { // ====================================================== @@ -34,13 +35,6 @@ export default (initialState = {}) => { } } - // ====================================================== - // Store Instantiation and HMR Setup - if (typeof composeWithDevToolsExtension === 'function') { - composeEnhancers = composeWithDevToolsExtension - } - } - // ====================================================== // Store Instantiation and HMR Setup // ====================================================== @@ -68,3 +62,4 @@ export default (initialState = {}) => { return store } + diff --git a/src/store/createStore.js.orig b/src/store/createStore.js.orig new file mode 100644 index 0000000..30c4fb5 --- /dev/null +++ b/src/store/createStore.js.orig @@ -0,0 +1,74 @@ +import { applyMiddleware, compose, createStore } from 'redux' +import thunk from 'redux-thunk' +import baseHistory from './baseHistory' +import makeRootReducer from './reducers' +<<<<<<< HEAD +import {updateLocation} from './location' +import Immutable from 'immutable'; + +import generateUsers from "../routes/Activity/modules/UserGenerator" +======= +import { updateLocation } from './location' +import { routerMiddleware } from 'react-router-redux' +import { browserHistory } from 'react-router' +>>>>>>> fix-login + +export default (initialState = {}) => { + // ====================================================== + // Middleware Configuration + // ====================================================== + + // ====================================================== + // Store Enhancers + // ====================================================== + + /* create routing middleware */ + const routingMiddleware = routerMiddleware(baseHistory) + + const middleware = [thunk] + const enhancers = [] + + let composeEnhancers = compose + + if (__DEV__) { +<<<<<<< HEAD + const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ + serialize: { + immutable: Immutable + } + }); +======= + const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ +>>>>>>> fix-login + if (typeof composeWithDevToolsExtension === 'function') { + composeEnhancers = composeWithDevToolsExtension + } + } + + // ====================================================== + // Store Instantiation and HMR Setup + // ====================================================== + const store = createStore( + makeRootReducer(), + initialState, + composeEnhancers( + applyMiddleware(routingMiddleware), + applyMiddleware(...middleware), + ...enhancers + ) + ) + + store.asyncReducers = {} + + // To unsubscribe, invoke `store.unsubscribeHistory()` anytime + // store.unsubscribeHistory = browserHistory.listen(updateLocation(store)) + + if (module.hot) { + module.hot.accept('./reducers', () => { + const reducers = require('./reducers').default + store.replaceReducer(reducers(store.asyncReducers)) + }) + } + + return store +} From b6bcab89aabd7e99e3a9d5772cec00976ef7c561 Mon Sep 17 00:00:00 2001 From: Matt Almenshad Date: Mon, 5 Jun 2017 18:48:49 -0700 Subject: [PATCH 20/23] switching to fix-login --- .../createParticipantController.js.orig | 115 ++++++++++++++++++ .../components/GroupCard/GroupCard.js | 2 +- 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 server/routes/activities/participants/controllers/createParticipantController.js.orig diff --git a/server/routes/activities/participants/controllers/createParticipantController.js.orig b/server/routes/activities/participants/controllers/createParticipantController.js.orig new file mode 100644 index 0000000..3d141e1 --- /dev/null +++ b/server/routes/activities/participants/controllers/createParticipantController.js.orig @@ -0,0 +1,115 @@ +/** + * Created by rui on 5/16/17. + */ +const Activity = require("../../../../models/").Activity; +const Participant = require("../../../../models/").Participant; +const ParticipantValidator = require("../../../../models").ParticipantValidator; +const ObjectIdIsValid = require("mongoose").Types.ObjectId.isValid; + +const createErrorHandler = require("../../../utils").createErrorHandler; +const HttpStatus = require("http-status-codes"); + +const properties = ['name', 'image', 'email', 'surveyResponses']; + +const images = [ + "https://react.semantic-ui.com/assets/images/avatar/large/jenny.jpg", + "https://react.semantic-ui.com/assets/images/avatar/large/justen.jpg", + "https://react.semantic-ui.com/assets/images/avatar/large/stevie.jpg", + "https://react.semantic-ui.com/assets/images/avatar/large/veronika.jpg", + "https://semantic-ui.com/images/avatar/large/steve.jpg", + "https://semantic-ui.com/images/avatar2/large/kristy.png", + "https://semantic-ui.com/images/avatar2/large/matthew.png", + "https://semantic-ui.com/images/avatar2/large/molly.png", + "https://semantic-ui.com/images/avatar2/large/elyse.png", + "https://semantic-ui.com/images/avatar/large/daniel.jpg", + "https://semantic-ui.com/images/avatar/large/helen.jpg", + +]; + +let randomBetween = (minVal, maxVal) => { + return Math.floor(Math.random() * (maxVal-minVal+1)) + minVal; +}; + +function pickImage () { + return images[randomBetween(0, images.length-1)]; +}; + +function validateInput(req) { + let payload = req.body; + return validateParameters(req.params) && validateFormat(payload, properties) + && ParticipantValidator(payload.name, payload.email, payload.image, payload.surveyResponses); +} + + +function validateParameters(prm) { + return prm.hasOwnProperty('activityId') && typeof prm.activityId === 'string' + && ObjectIdIsValid(prm.activityId); +} + + +function validateFormat(payload, properties){ + let res = true; + properties.forEach(function (property) { + res = res && payload.hasOwnProperty(property); + }); + return res; +} + + +module.exports = function (req, res, next) { + if (!validateInput(req)) { + const errorMessage = 'please give valid activityID in URL and correct payload'; + createErrorHandler(res, HttpStatus.BAD_REQUEST)(errorMessage); + return; + } + + const payload = req.body; + const activityId = req.params.activityId; +<<<<<<< HEAD + + console.log(payload); + console.log(payload.surveyResponses); +======= +>>>>>>> a165bb757d8a7aad48820d6f96d783d3fc4c9c50 + + // check if the activity is full. If so, then no other one can participate in + Activity.findOne({_id: activityId, isDeleted: false}) + .exec() + .then(function (activity){ + if (activity === null){ + const errorMessage = "Cannot find activity has id: " + activityId + " in which to create new participant"; + return createErrorHandler(res, HttpStatus.NOT_FOUND)(errorMessage); + } + if (activity.totalCapacity <= activity.currentCapacity){ + const errorMessage = "The activity is full, no other one can participate in"; + return createErrorHandler(res, HttpStatus.NOT_FOUND)(errorMessage); + } + // save a new participant + const newParticipant = new Participant({ + _activity: activityId, + _creator: activity._creator, + email: payload.email, + name: payload.name, + image: pickImage(), + surveyResponses: payload.surveyResponses, + }); + newParticipant.save() + .then(function(participant){ + + // update activity + activity.participants.push({_id: participant.id}); + activity.lastModifiedTime = Date.now(); + activity.currentCapacity ++; + + activity.save().then(function(act){ + return res.status(HttpStatus.CREATED).json({ + participant: participant.getPublicFields() + }) + }).catch(createErrorHandler(res, HttpStatus.INTERNAL_SERVER_ERROR)); + }) + .catch(createErrorHandler(res, HttpStatus.INTERNAL_SERVER_ERROR)); + + + }).catch(createErrorHandler(res, HttpStatus.INTERNAL_SERVER_ERROR)); + +}; diff --git a/src/routes/Activity/components/GroupCard/GroupCard.js b/src/routes/Activity/components/GroupCard/GroupCard.js index dea4187..589cb86 100644 --- a/src/routes/Activity/components/GroupCard/GroupCard.js +++ b/src/routes/Activity/components/GroupCard/GroupCard.js @@ -166,7 +166,7 @@ class GroupCard extends React.Component { { this.props.participants.map((participant) => console.log(v) } unlocked= { this.props.unlocked } /> From ef5f9c6ee2cf1596bb74338db8d25cdf2c72c635 Mon Sep 17 00:00:00 2001 From: Matt Almenshad Date: Tue, 6 Jun 2017 06:43:17 -0700 Subject: [PATCH 21/23] More cleaning up --- package.json | 1 + .../unlockGroupInCertainActivityController.js | 3 + src/main.js | 4 + .../Activity/components/ActivityView.js | 15 +- .../components/FilterMenu/FilterMenu.js | 44 ++-- .../components/GroupCard/GroupCard.js | 88 ++++--- .../components/GroupCard/renderFunctions.js | 104 ++++++++ .../ParticipantListSidebar.js | 13 +- .../Activity/containers/ActivityContainer.js | 4 +- .../actions/filterParticipantsActions.js | 10 +- .../actions/generateGroupAssignmentActions.js | 21 +- .../modules/actions/groupLockActions.js | 30 ++- .../updateParticipantGroupNumberActions.js | 2 - .../filterParticipantsActionsHandlers.js | 4 +- .../generateGroupAssignmentActionsHandlers.js | 57 ++++- .../groupLockActionsHandlers.js | 20 +- ...teParticipantGroupNumberActionsHandlers.js | 4 - .../Activity/modules/reducer/reducer.js | 11 +- src/routes/Signup/components/SignupView.js | 234 ++++++++++-------- src/store/createStore.js | 13 +- 20 files changed, 455 insertions(+), 227 deletions(-) create mode 100644 src/routes/Activity/components/GroupCard/renderFunctions.js diff --git a/package.json b/package.json index 929fd41..3d2406a 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "react-copy-to-clipboard": "^5.0.0", "react-dnd": "^2.3.0", "react-dnd-html5-backend": "^2.3.0", + "react-dnd-scrollzone": "^4.0.0", "react-dom": "^15.5.4", "react-redux": "^5.0.1", "react-router": "^3.0.0", diff --git a/server/routes/activities/controllers/unlockGroupInCertainActivityController.js b/server/routes/activities/controllers/unlockGroupInCertainActivityController.js index 2066af2..ef248fe 100644 --- a/server/routes/activities/controllers/unlockGroupInCertainActivityController.js +++ b/server/routes/activities/controllers/unlockGroupInCertainActivityController.js @@ -38,6 +38,9 @@ module.exports = function (req, res, next) { const userId = req.user._id; const activityId = req.params.activityId; const groupNumber = parseInt(req.params.groupNumber, 10); + console.log("GN") + console.log(groupNumber) + console.log("GN") Activity.findOneAndUpdate( { diff --git a/src/main.js b/src/main.js index 4cd7a8d..ed56d58 100644 --- a/src/main.js +++ b/src/main.js @@ -6,6 +6,7 @@ import injectTapEventPlugin from 'react-tap-event-plugin' import AppContainer from './containers/AppContainer' import setAuthorizationToken from './components/utils/setAuthorizationToken' import { applyMiddleware, compose } from 'redux' +import axios from 'axios'; // imports for web auth import jwt from 'jsonwebtoken' @@ -32,6 +33,9 @@ const MOUNT_NODE = document.getElementById('root') let render = () => { const routes = require('./routes/index').default(store) + //always grab the token from local storage to solve inconsistency + axios.defaults.headers.common['Authorization'] = localStorage.getItem("jwtToken"); + ReactDOM.render(
diff --git a/src/routes/Activity/components/ActivityView.js b/src/routes/Activity/components/ActivityView.js index 59467dd..01d3508 100644 --- a/src/routes/Activity/components/ActivityView.js +++ b/src/routes/Activity/components/ActivityView.js @@ -72,15 +72,18 @@ export class ActivityView extends React.Component { (group, i) => ( console.log(v) } toggleLock={(v) => console.log(v) } group={ i } - unlocked={ this.props.lockedGroups.get(i)} + toggleLock={this.props.toggleLock} /> ) @@ -94,9 +97,19 @@ export class ActivityView extends React.Component { participants={ this.props.participants } setCurrentlySelected={(v) => {console.log(v)}} updateParticipantGroupNumber={ this.props.updateParticipantGroupNumber } + filter={this.props.filter} activityId={ this.props.activityId } /> console.log(v) }> + { + (this.props.participants.size > 0) && + + } { getGroupCards(separateParticipantsIntoGroups()) } diff --git a/src/routes/Activity/components/FilterMenu/FilterMenu.js b/src/routes/Activity/components/FilterMenu/FilterMenu.js index a23cf02..3d0874b 100644 --- a/src/routes/Activity/components/FilterMenu/FilterMenu.js +++ b/src/routes/Activity/components/FilterMenu/FilterMenu.js @@ -4,31 +4,27 @@ import React from 'react' import PropTypes from 'prop-types'; import {Button, Dropdown, Input, Menu, Segment} from 'semantic-ui-react' +import {Map, List, Set} from 'immutable'; import {Sticky} from "react-sticky"; class FilterMenu extends React.Component { constructor(props) { super(props); - this.state = { - inputInverted: false, - } } static propTypes = { generateGroupAssignment: PropTypes.func.isRequired, activityId: PropTypes.string.isRequired, - filterValues: PropTypes.object.isRequired, }; generateGroupButtonHandlerMaker = (algorithmKey) => { let random = () => { - this.props.generateGroupAssignment(this.props.activityId, "random"); + this.props.generateGroupAssignment(this.props.activityId, "randomAlgorithm"); }; let greedy = () => { - this.props.generateGroupAssignment(this.props.activityId, "greedy"); + this.props.generateGroupAssignment(this.props.activityId, "greedyAlgorithm"); }; - switch (algorithmKey) { case("random"): return random; @@ -40,12 +36,9 @@ class FilterMenu extends React.Component { }; handleStickyStateChange = () => { - this.setState({inputInverted: !this.state.inputInverted}); }; handleChange = (e, { value }) => { - console.log(value); - this.props.filterParticipants(value); } render() { @@ -75,10 +68,15 @@ class FilterMenu extends React.Component { height: 45 }; - const [...keys] = this.props.filterValues.keys(); - const options = Object.keys(keys[0]).map(function(key, i) { - return {key: i, text: key, value: key, name: key}; - }) + let answersFilterOptions = []; + this.props.allAnswers.forEach((answer) => { + answersFilterOptions.push({ + key:answer, + value:answer, + text:answer, + }) + }); + return (
@@ -93,35 +91,41 @@ class FilterMenu extends React.Component { { { + this.props.setFilter(Set(data.value)); + }} + options={answersFilterOptions} multiple selection - transparent //inverted={ this.state.inputInverted } //onChange={ this.props.setFilterValues.bind(this, "filters") } - onChange={ this.handleChange } + //onChange={ this.handleChange } /> } - - - - Already have an account? Log - in - - - - ) - } - -} - +import React, { Component, PropTypes } from 'react' +import { Button, Grid, Header, Icon, Image, Label, Message, Segment } from 'semantic-ui-react' +import { Form, Input, TextArea, Checkbox, Radio, RadioGroup, Dropdown, Select, } from 'formsy-semantic-ui-react' + +class CountDownTimer extends Component { + constructor (props) { + super(props) + this.state = { + secondsRemaining: 0 + } + } + + static propTypes = { + secondsRemaining: PropTypes.number.isRequired, + } + + componentDidMount () { + this.setState({secondsRemaining: this.props.secondsRemaining}) + this.interval = setInterval(() => { + this.setState({secondsRemaining: this.state.secondsRemaining - 1}) + if (this.state.secondsRemaining <= 0) { + clearInterval(this.interval) + } + } + , 1000) + } + + componentWillUnmount () { + clearInterval(this.interval) + } + + render () { + return {this.state.secondsRemaining} + } +} + +class SignupView extends Component { + constructor (props) { + super(props) + } + + static propTypes = { + signup: PropTypes.func.isRequired, + replace: PropTypes.func.isRequired, + hideErrorMessage: PropTypes.func.isRequired, + signingUp: PropTypes.bool.isRequired, + signupSuccess: PropTypes.bool.isRequired, + signupFailure: PropTypes.bool.isRequired + } + + componentWillMount () { + const {isAuthenticated, replace, redirect} = this.props + if (isAuthenticated) { + replace(redirect) + } + } + + handleOnValidSubmit = (formData) => { + const {email, password} = formData + const {signup} = this.props + signup(email, password) + } + + redirectToLogin = () => { + this.props.push('/login') + } + + render () { + const {hideErrorMessage, signingUp, signupFailure, signupSuccess} = this.props + return ( + + +
+ Signup +
+ { signupFailure && Duplicate Email } + { signupSuccess && + + Signup Success +

Redirect to Login in Seconds ...

+
+ } + + +
+ } + validationErrors={{ + isEmail: 'This has to be your email', + isDefaultRequiredValue: 'required', + }} + /> + } + validationErrors={{ + minLength: 'at least 6 characters', + equalsField: 'Passwords do not match', + isDefaultRequiredValue: 'required', + }} + /> + + } + validationErrors={{ + equalsField: 'Passwords do not match', + isDefaultRequiredValue: 'required', + }} + + /> + + + +
+ + Already have an account? Log + in + +
+
+ ) + } + +} + export default SignupView \ No newline at end of file diff --git a/src/store/createStore.js b/src/store/createStore.js index 4b87862..ebc8285 100644 --- a/src/store/createStore.js +++ b/src/store/createStore.js @@ -25,11 +25,14 @@ export default (initialState = {}) => { let composeEnhancers = compose if (__DEV__) { - const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ - serialize: { - immutable: Immutable - } - }); + const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ + serialize: { + immutable: Immutable + } + }) + : + potcompose; if (typeof composeWithDevToolsExtension === 'function') { composeEnhancers = composeWithDevToolsExtension } From e81cf1fccaebbdc5d3b3e56a27cc3e648a198769 Mon Sep 17 00:00:00 2001 From: Matt Almenshad Date: Tue, 6 Jun 2017 06:46:33 -0700 Subject: [PATCH 22/23] more cleanup --- .../modules/actions/updateParticipantGroupNumberActions.js | 2 +- src/routes/Login/modules/actions/loginActions.js | 2 +- src/routes/Signup/modules/actions/signupActions.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/Activity/modules/actions/updateParticipantGroupNumberActions.js b/src/routes/Activity/modules/actions/updateParticipantGroupNumberActions.js index 0a4325a..ba4f7ba 100644 --- a/src/routes/Activity/modules/actions/updateParticipantGroupNumberActions.js +++ b/src/routes/Activity/modules/actions/updateParticipantGroupNumberActions.js @@ -2,7 +2,7 @@ * Created by rui on 5/9/17. */ import axios from "axios"; -const SERVER_URL = "http://localhost:3000"; +const SERVER_URL = "http://" + window.location.host; /* update put requests */ export const UPDATE_PARTICIPANT_GROUP_NUMBER = "UPDATE_PARTICIPANT_GROUP"; diff --git a/src/routes/Login/modules/actions/loginActions.js b/src/routes/Login/modules/actions/loginActions.js index a8212da..cf23de9 100644 --- a/src/routes/Login/modules/actions/loginActions.js +++ b/src/routes/Login/modules/actions/loginActions.js @@ -5,7 +5,7 @@ import axios from 'axios' import { authenticationActions } from '../../../../store/authentication/actions' -const SERVER_URL = 'http://localhost:3000' +const SERVER_URL = "http://" + window.location.host; export const LOGIN = 'LOGIN' diff --git a/src/routes/Signup/modules/actions/signupActions.js b/src/routes/Signup/modules/actions/signupActions.js index c4f674b..ceeaffe 100644 --- a/src/routes/Signup/modules/actions/signupActions.js +++ b/src/routes/Signup/modules/actions/signupActions.js @@ -5,7 +5,7 @@ import axios from 'axios' import {routerActions } from 'react-router-redux' -const SERVER_URL = 'http://localhost:3000' +const SERVER_URL = "http://" + window.location.host; export const SIGNUP = 'SIGNUP' From 14f0fa43732741644a84f901b4dd0116b47338f0 Mon Sep 17 00:00:00 2001 From: Matt Almenshad Date: Tue, 6 Jun 2017 06:51:17 -0700 Subject: [PATCH 23/23] switching DB to mlab --- server/config/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/config/main.js b/server/config/main.js index c108ffe..06aaff1 100644 --- a/server/config/main.js +++ b/server/config/main.js @@ -6,6 +6,6 @@ const passport = require('passport'); module.exports = { 'secret': 'asdawldjal', - databaseUrl: 'mongodb://localhost:27017/teamdivider', - authenticationMiddleware: passport.authenticate('jwt', { session: false }), + databaseUrl: 'mongodb://teamdivider:CIS4222017@ds137101.mlab.com:37101/teamdivider', + authenticationMiddleware: passport.authenticate('jwt', { session: false }), };