Feature(settings): Update url/challenge lang onChange

This commit is contained in:
Berkeley Martinez
2016-07-20 15:06:44 -07:00
parent 232e0713d1
commit e5efcbb6c6
6 changed files with 54 additions and 29 deletions

View File

@ -9,7 +9,8 @@ import {
initWindowHeight,
updateNavHeight,
toggleMapDrawer,
toggleMainChat
toggleMainChat,
updateAppLang
} from './redux/actions';
import { submitChallenge } from './routes/challenges/redux/actions';
@ -18,6 +19,16 @@ import Nav from './components/Nav';
import Toasts from './toasts/Toasts.jsx';
import { userSelector } from './redux/selectors';
const bindableActions = {
initWindowHeight,
updateNavHeight,
fetchUser,
submitChallenge,
toggleMapDrawer,
toggleMainChat,
updateAppLang
};
const mapStateToProps = createSelector(
userSelector,
state => state.app.shouldShowSignIn,
@ -43,15 +54,6 @@ const mapStateToProps = createSelector(
})
);
const bindableActions = {
initWindowHeight,
updateNavHeight,
fetchUser,
submitChallenge,
toggleMapDrawer,
toggleMainChat
};
// export plain class for testing
export class FreeCodeCamp extends React.Component {
static displayName = 'FreeCodeCamp';
@ -74,9 +76,16 @@ export class FreeCodeCamp extends React.Component {
toggleMainChat: PropTypes.func,
fetchUser: PropTypes.func,
shouldShowSignIn: PropTypes.bool,
params: PropTypes.object
params: PropTypes.object,
updateAppLang: PropTypes.func.isRequired
};
componentWillReceiveProps(nextProps) {
if (this.props.params.lang !== nextProps.params.lang) {
this.props.updateAppLang(nextProps.params.lang);
}
}
componentDidMount() {
this.props.initWindowHeight();
if (!this.props.isSignedIn) {

View File

@ -40,6 +40,7 @@ export const updateUserLang = createAction(
types.updateUserLang,
(username, lang) => ({ username, lang })
);
export const updateAppLang = createAction(types.updateAppLang);
// updateCompletedChallenges(username: String) => Action
export const updateCompletedChallenges = createAction(
types.updateCompletedChallenges

View File

@ -25,6 +25,10 @@ export default handleActions(
user,
shouldShowSignIn: true
}),
[types.updateAppLang]: (state, { payload = 'en' }) =>({
...state,
lang: payload
}),
[types.showSignIn]: state => ({
...state,
shouldShowSignIn: true

View File

@ -2,6 +2,7 @@ import createTypes from '../utils/create-types';
export default createTypes([
'updateTitle',
'updateAppLang',
'fetchUser',
'addUser',

View File

@ -8,11 +8,11 @@ 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
})
userSelector,
({ user: { languageTag } }) => ({
// send null to prevent redux-form from initialize empty
initialValues: languageTag ? { lang: languageTag } : null
})
);
const actions = { updateMyLang };
const fields = [ 'lang' ];

View File

@ -1,14 +1,17 @@
import { Observable } from 'rx';
import { push } from 'react-router-redux';
import { types } from './actions';
import combineSagas from '../../../utils/combine-sagas';
import { makeToast } from '../../../toasts/redux/actions';
import { fetchChallenges } from '../../challenges/redux/actions';
import {
updateUserFlag,
updateUserEmail,
updateUserLang,
doActionOnError
} from '../../../redux/actions';
import { userSelector } from '../../../redux/selectors';
import { postJSON$ } from '../../../../utils/ajax-stream';
import langs from '../../../../utils/supported-languages';
@ -47,26 +50,33 @@ export function updateUserLangSaga(actions$, getState) {
.filter(({ type, payload }) => (
type === types.updateMyLang && !!langs[payload]
))
.map(({ payload }) => payload);
.map(({ payload }) => {
const state = getState();
const { user: { languageTag } } = userSelector(state);
return { lang: payload, oldLang: languageTag };
});
const ajaxUpdate$ = updateLang$
.flatMap(lang => {
const {
app: { user: username, csrfToken: _csrf },
entities: { user: userMap }
} = getState();
const { languageTag: oldLang } = userMap[username] || {};
const body = {
_csrf,
lang
};
.debounce(250)
.flatMap(({ lang, oldLang }) => {
const { app: { user: username, csrfToken: _csrf } } = getState();
const body = { _csrf, lang };
return postJSON$('/update-my-lang', body)
.map(({ message }) => makeToast({ message }))
.flatMap(({ message }) => {
return Observable.of(
// show user that we have updated their lang
makeToast({ message }),
// update url to reflect change
push(`/${lang}/settings`),
// refetch challenges in new language
fetchChallenges()
);
})
.catch(doActionOnError(() => {
return updateUserLang(username, oldLang);
}));
});
const optimistic$ = updateLang$
.map(lang => {
.map(({ lang }) => {
const { app: { user: username } } = getState();
return updateUserLang(username, lang);
});