diff --git a/common/app/redux/actions.js b/common/app/redux/actions.js index 435d3e93cd9..05abf5cdeeb 100644 --- a/common/app/redux/actions.js +++ b/common/app/redux/actions.js @@ -9,7 +9,7 @@ export const updateTitle = createAction(types.updateTitle); // used in combination with fetch-user-saga export const fetchUser = createAction(types.fetchUser); -// setUser( +// addUser( // entities: { [userId]: User } // ) => Action export const addUser = createAction( @@ -25,11 +25,21 @@ export const updateUserPoints = createAction( types.updateUserPoints, (username, points) => ({ username, points }) ); -// updateUserPoints(username: String, flag: String) => Action +// updateUserFlag(username: String, flag: String) => Action export const updateUserFlag = createAction( types.updateUserFlag, (username, flag) => ({ username, flag }) ); +// updateUserEmail(username: String, email: String) => Action +export const updateUserEmail = createAction( + types.updateUserFlag, + (username, email) => ({ username, email }) +); +// updateUserLang(username: String, lang: String) => Action +export const updateUserLang = createAction( + types.updateUserLang, + (username, lang) => ({ username, lang }) +); // updateCompletedChallenges(username: String) => Action export const updateCompletedChallenges = createAction( types.updateCompletedChallenges @@ -55,6 +65,16 @@ export const createErrorObservable = error => Observable.just({ type: types.handleError, error }); +// doActionOnError( +// actionCreator: (() => Action|Null) +// ) => (error: Error) => Observable[Action] +export const doActionOnError = actionCreator => error => Observable.of( + { + type: types.handleError, + error + }, + actionCreator() +); // drawers diff --git a/common/app/redux/entities-reducer.js b/common/app/redux/entities-reducer.js index 250ae395cc6..ad271471c69 100644 --- a/common/app/redux/entities-reducer.js +++ b/common/app/redux/entities-reducer.js @@ -8,8 +8,13 @@ const initialState = { user: {} }; +// future refactor(berks): Several of the actions here are just updating props +// on the main user. These can be refactors into one response for all actions export default function entities(state = initialState, action) { - const { type, payload: { username, points, flag } = {} } = action; + const { + type, + payload: { email, username, points, flag, languageTag } = {} + } = action; if (type === updateCompletedChallenges) { const username = action.payload; const completedChallengeMap = state.user[username].challengeMap || {}; @@ -26,6 +31,12 @@ export default function entities(state = initialState, action) { }, {}) }; } + if (action.meta && action.meta.entities) { + return { + ...state, + ...action.meta.entities + }; + } if (type === updateUserPoints) { return { ...state, @@ -38,12 +49,6 @@ export default function entities(state = initialState, action) { } }; } - if (action.meta && action.meta.entities) { - return { - ...state, - ...action.meta.entities - }; - } if (action.type === types.updateUserFlag) { return { ...state, @@ -56,5 +61,29 @@ export default function entities(state = initialState, action) { } }; } + if (action.type === types.updateUserEmail) { + return { + ...state, + user: { + ...state.user, + [username]: { + ...state.user[username], + email + } + } + }; + } + if (action.type === types.updateUserLang) { + return { + ...state, + user: { + ...state.user, + [username]: { + ...state.user[username], + languageTag + } + } + }; + } return state; } diff --git a/common/app/redux/types.js b/common/app/redux/types.js index 3ab9197c8b1..2a6025d1b0a 100644 --- a/common/app/redux/types.js +++ b/common/app/redux/types.js @@ -8,6 +8,8 @@ export default createTypes([ 'updateThisUser', 'updateUserPoints', 'updateUserFlag', + 'updateUserEmail', + 'updateUserLang', 'updateCompletedChallenges', 'showSignIn', diff --git a/common/app/routes/settings/components/Email-Setting.jsx b/common/app/routes/settings/components/Email-Setting.jsx index a9332d56e45..0a6ad360125 100644 --- a/common/app/routes/settings/components/Email-Setting.jsx +++ b/common/app/routes/settings/components/Email-Setting.jsx @@ -1,20 +1,22 @@ import React, { PropTypes } from 'react'; +import { Link } from 'react-router'; import { Button, Row, Col } from 'react-bootstrap'; import FA from 'react-fontawesome'; import classnames from 'classnames'; export function UpdateEmailButton() { return ( - + + + ); } diff --git a/common/app/routes/settings/components/Language-Settings.jsx b/common/app/routes/settings/components/Language-Settings.jsx index f8b11aaec1b..c8e3b7306c5 100644 --- a/common/app/routes/settings/components/Language-Settings.jsx +++ b/common/app/routes/settings/components/Language-Settings.jsx @@ -1,7 +1,27 @@ import React, { PropTypes } from 'react'; +import { createSelector } from 'reselect'; +import { reduxForm } from 'redux-form'; import { FormControl } from 'react-bootstrap'; + +import { updateMyLang } from '../redux/actions'; +import { userSelector } from '../../../redux/selectors'; import langs from '../../../../utils/supported-languages'; +const mapStateToProps = createSelector( + userSelector, + ({ user: { languageTag } }) => ({ + // send null to prevent redux-form from initialize empty + initialValues: languageTag ? { lang: languageTag } : null + }) +); +const actions = { updateMyLang }; +const fields = [ 'lang' ]; +const validator = values => { + if (!langs[values.lang]) { + return { lang: `${values.lang} is unsupported` }; + } + return {}; +}; const options = [(