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 = [(