Feature(settings): Update url/challenge lang onChange
This commit is contained in:
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -25,6 +25,10 @@ export default handleActions(
|
||||
user,
|
||||
shouldShowSignIn: true
|
||||
}),
|
||||
[types.updateAppLang]: (state, { payload = 'en' }) =>({
|
||||
...state,
|
||||
lang: payload
|
||||
}),
|
||||
[types.showSignIn]: state => ({
|
||||
...state,
|
||||
shouldShowSignIn: true
|
||||
|
@ -2,6 +2,7 @@ import createTypes from '../utils/create-types';
|
||||
|
||||
export default createTypes([
|
||||
'updateTitle',
|
||||
'updateAppLang',
|
||||
|
||||
'fetchUser',
|
||||
'addUser',
|
||||
|
@ -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' ];
|
||||
|
@ -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);
|
||||
});
|
||||
|
Reference in New Issue
Block a user