Feature(challenges): save users current challenge to db
This allows us to automatically load their current challenge
This commit is contained in:
@ -61,6 +61,10 @@ export const addUser = createAction(
|
||||
export const updateThisUser = createAction(types.updateThisUser);
|
||||
export const showSignIn = createAction(types.showSignIn);
|
||||
export const loadCurrentChallenge = createAction(types.loadCurrentChallenge);
|
||||
export const updateMyCurrentChallenge = createAction(
|
||||
types.updateMyCurrentChallenge,
|
||||
(username, currentChallengeId) => ({ username, currentChallengeId })
|
||||
);
|
||||
|
||||
// updateUserPoints(username: String, points: Number) => Action
|
||||
export const updateUserPoints = createAction(
|
||||
|
@ -85,5 +85,18 @@ export default function entities(state = initialState, action) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === types.updateMyCurrentChallenge) {
|
||||
return {
|
||||
...state,
|
||||
user: {
|
||||
...state.user,
|
||||
[username]: {
|
||||
...state.user[username],
|
||||
currentChallengeId: action.payload.currentChallengeId
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
@ -1,15 +1,51 @@
|
||||
import { Observable } from 'rx';
|
||||
import debug from 'debug';
|
||||
import { push } from 'react-router-redux';
|
||||
|
||||
import types from './types';
|
||||
import {
|
||||
updateMyCurrentChallenge,
|
||||
createErrorObservable
|
||||
} from './actions';
|
||||
import {
|
||||
userSelector,
|
||||
firstChallengeSelector
|
||||
} from './selectors';
|
||||
import getActionsOfType from '../../utils/get-actions-of-type';
|
||||
import { updateCurrentChallenge } from '../routes/challenges/redux/actions';
|
||||
import getActionsOfType from '../../utils/get-actions-of-type';
|
||||
import combineSagas from '../utils/combine-sagas';
|
||||
import { postJSON$ } from '../../utils/ajax-stream';
|
||||
|
||||
export default function loadCurrentChallengeSaga(actions, getState) {
|
||||
const log = debug('fcc:app/redux/load-current-challenge-saga');
|
||||
export function updateMyCurrentChallengeSaga(actions, getState) {
|
||||
const updateChallenge$ = getActionsOfType(
|
||||
actions,
|
||||
updateCurrentChallenge.toString()
|
||||
)
|
||||
.map(({ payload: { id } }) => id)
|
||||
.filter(() => {
|
||||
const { app: { user: username } } = getState();
|
||||
return !!username;
|
||||
});
|
||||
const optimistic = updateChallenge$.map(id => {
|
||||
const { app: { user: username } } = getState();
|
||||
return updateMyCurrentChallenge(username, id);
|
||||
});
|
||||
const ajaxUpdate = updateChallenge$
|
||||
.debounce(250)
|
||||
.flatMapLatest(currentChallengeId => {
|
||||
const { app: { csrfToken: _csrf } } = getState();
|
||||
return postJSON$(
|
||||
'/update-my-current-challenge',
|
||||
{ _csrf, currentChallengeId }
|
||||
)
|
||||
.map(({ message }) => log(message))
|
||||
.catch(createErrorObservable);
|
||||
});
|
||||
return Observable.merge(optimistic, ajaxUpdate);
|
||||
}
|
||||
|
||||
export function loadCurrentChallengeSaga(actions, getState) {
|
||||
return getActionsOfType(actions, types.loadCurrentChallenge)
|
||||
.flatMap(() => {
|
||||
let finalChallenge;
|
||||
@ -40,3 +76,8 @@ export default function loadCurrentChallengeSaga(actions, getState) {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default combineSagas(
|
||||
updateMyCurrentChallengeSaga,
|
||||
loadCurrentChallengeSaga
|
||||
);
|
||||
|
@ -15,6 +15,7 @@ export default createTypes([
|
||||
'updateCompletedChallenges',
|
||||
'showSignIn',
|
||||
'loadCurrentChallenge',
|
||||
'updateMyCurrentChallenge',
|
||||
|
||||
'handleError',
|
||||
'toggleNightMode',
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ifNoUser401 } from '../utils/middleware';
|
||||
import { isMongoId } from 'validator';
|
||||
import supportedLanguages from '../../common/utils/supported-languages.js';
|
||||
|
||||
export default function settingsController(app) {
|
||||
@ -49,6 +50,20 @@ export default function settingsController(app) {
|
||||
);
|
||||
}
|
||||
|
||||
function updateMyCurrentChallenge(req, res, next) {
|
||||
const { user, body: { currentChallengeId } } = req;
|
||||
if (!isMongoId('' + currentChallengeId)) {
|
||||
return next(new Error(`${currentChallengeId} is not a valid ObjectId`));
|
||||
}
|
||||
return user.update$({ currentChallengeId }).subscribe(
|
||||
() => res.json({
|
||||
message:
|
||||
`your current challenge has been updated to ${currentChallengeId}`
|
||||
}),
|
||||
next
|
||||
);
|
||||
}
|
||||
|
||||
api.post(
|
||||
'/toggle-lockdown',
|
||||
toggleUserFlag('isLocked')
|
||||
@ -78,5 +93,11 @@ export default function settingsController(app) {
|
||||
ifNoUser401,
|
||||
updateMyLang
|
||||
);
|
||||
|
||||
api.post(
|
||||
'/update-my-current-challenge',
|
||||
ifNoUser401,
|
||||
updateMyCurrentChallenge
|
||||
);
|
||||
app.use(api);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ const publicUserProps = [
|
||||
'sendNotificationEmail',
|
||||
'sendQuincyEmail',
|
||||
|
||||
'currentChallenge',
|
||||
'currentChallengeId',
|
||||
'challengeMap'
|
||||
];
|
||||
const log = debug('fcc:services:user');
|
||||
|
Reference in New Issue
Block a user