Fix(challenge): update user challenge map on challenge complete

This commit is contained in:
Berkeley Martinez
2016-08-11 16:41:03 -07:00
parent d3dabb1f36
commit 8be0d194a5
6 changed files with 98 additions and 40 deletions

View File

@ -94,6 +94,16 @@ export const updateUserLang = createAction(
types.updateUserLang,
(username, lang) => ({ username, lang })
);
// updateUserChallenge(
// username: String,
// challengeInfo: Object
// ) => Action
export const updateUserChallenge = createAction(
types.updateUserChallenge,
(username, challengeInfo) => ({ username, challengeInfo })
);
export const updateAppLang = createAction(types.updateAppLang);
// used when server needs client to redirect

View File

@ -82,5 +82,22 @@ export default function entities(state = initialState, action) {
}
};
}
if (action.type === types.updateUserChallenge) {
const { challengeInfo } = action.payload;
return {
...state,
user: {
...state.user,
[username]: {
...state.user[username],
challengeMap: {
...state.user[username].challengeMap,
[challengeInfo.id]: challengeInfo
}
}
}
};
}
return state;
}

View File

@ -12,6 +12,7 @@ export default createTypes([
'updateUserFlag',
'updateUserEmail',
'updateUserLang',
'updateUserChallenge',
'showSignIn',
'loadCurrentChallenge',
'updateMyCurrentChallenge',

View File

@ -59,7 +59,10 @@ export const updateFile = createAction(
export const updateFiles = createAction(types.updateFiles);
// rechallenge
export const executeChallenge = createAction(types.executeChallenge);
export const executeChallenge = createAction(
types.executeChallenge,
() => null
);
export const updateMain = createAction(types.updateMain);
export const frameMain = createAction(types.frameMain);

View File

@ -2,22 +2,30 @@ import { Observable } from 'rx';
import types from './types';
import { moveToNextChallenge } from './actions';
import {
createErrorObservable,
updateUserPoints
} from '../../../redux/actions';
import { makeToast } from '../../../toasts/redux/actions';
import { challengeSelector } from './selectors';
import { randomCompliment } from '../../../utils/get-words';
import {
createErrorObservable,
updateUserPoints,
updateUserChallenge
} from '../../../redux/actions';
import { backEndProject } from '../../../utils/challengeTypes';
import { makeToast } from '../../../toasts/redux/actions';
import { postJSON$ } from '../../../../utils/ajax-stream';
function postChallenge(url, body, username) {
function postChallenge(url, username, _csrf, challengeInfo) {
const body = { ...challengeInfo, _csrf };
const saveChallenge$ = postJSON$(url, body)
.retry(3)
.map(({ points }) => {
return updateUserPoints(username, points);
.flatMap(({ points, lastUpdated, completedDate }) => {
return Observable.of(
updateUserPoints(username, points),
updateUserChallenge(
username,
{ ...challengeInfo, lastUpdated, completedDate }
)
);
})
.catch(createErrorObservable);
const challengeCompleted$ = Observable.of(moveToNextChallenge());
@ -44,12 +52,13 @@ function submitModern(type, state) {
app: { user, csrfToken },
challengesApp: { files }
} = state;
const body = {
id,
_csrf: csrfToken,
files
};
return postChallenge('/modern-challenge-completed', body, user);
const challengeInfo = { id, files };
return postChallenge(
'/modern-challenge-completed',
user,
csrfToken,
challengeInfo
);
}
}
return Observable.just(makeToast({ message: 'Not quite there, yet.' }));
@ -62,16 +71,16 @@ function submitProject(type, state, { solution, githubLink }) {
const {
app: { user, csrfToken }
} = state;
const body = {
id,
challengeType,
solution,
_csrf: csrfToken
};
const challengeInfo = { id, challengeType, solution };
if (challengeType === backEndProject) {
body.githubLink = githubLink;
challengeInfo.githubLink = githubLink;
}
return postChallenge('/project-completed', body, user);
return postChallenge(
'/project-completed',
user,
csrfToken,
challengeInfo
);
}
function submitSimpleChallenge(type, state) {
@ -81,11 +90,13 @@ function submitSimpleChallenge(type, state) {
const {
app: { user, csrfToken }
} = state;
const body = {
id,
_csrf: csrfToken
};
return postChallenge('/challenge-completed', body, user);
const challengeInfo = { id };
return postChallenge(
'/challenge-completed',
user,
csrfToken,
challengeInfo
);
}
const submitTypes = {

View File

@ -61,7 +61,12 @@ function buildUserUpdate(
log('user update data', updateData);
return { alreadyCompleted, updateData };
return {
alreadyCompleted,
updateData,
completedDate: finalChallenge.completedDate,
lastUpdated: finalChallenge.lastUpdated
};
}
export default function(app) {
@ -138,14 +143,14 @@ export default function(app) {
files
} = req.body;
const { alreadyCompleted, updateData } = buildUserUpdate(
const {
alreadyCompleted,
updateData,
lastUpdated
} = buildUserUpdate(
user,
id,
{
id,
files,
completedDate
}
{ id, files, completedDate }
);
const points = alreadyCompleted ? user.points : user.points + 1;
@ -156,7 +161,9 @@ export default function(app) {
if (type === 'json') {
return res.json({
points,
alreadyCompleted
alreadyCompleted,
completedDate,
lastUpdated
});
}
return res.sendStatus(200);
@ -184,7 +191,11 @@ export default function(app) {
const completedDate = Date.now();
const { id, solution, timezone } = req.body;
const { alreadyCompleted, updateData } = buildUserUpdate(
const {
alreadyCompleted,
updateData,
lastUpdated
} = buildUserUpdate(
req.user,
id,
{ id, solution, completedDate },
@ -200,7 +211,9 @@ export default function(app) {
if (type === 'json') {
return res.json({
points,
alreadyCompleted
alreadyCompleted,
completedDate,
lastUpdated
});
}
return res.sendStatus(200);
@ -253,7 +266,8 @@ export default function(app) {
.flatMap(() => {
const {
alreadyCompleted,
updateData
updateData,
lastUpdated
} = buildUserUpdate(user, completedChallenge.id, completedChallenge);
return user.update$(updateData)
@ -262,7 +276,9 @@ export default function(app) {
if (type === 'json') {
return res.send({
alreadyCompleted,
points: alreadyCompleted ? user.points : user.points + 1
points: alreadyCompleted ? user.points : user.points + 1,
completedDate: completedChallenge.completedDate,
lastUpdated
});
}
return res.status(200).send(true);