Files
freeCodeCamp/common/app/routes/challenges/redux/completion-saga.js
Berkeley Martinez 0c07e961a7 Feature(components): fetch user after page load
This makes it easier to serve whole site statically in the future
Feature(redux): Move user state into entities
2016-07-28 23:40:01 -07:00

180 lines
4.7 KiB
JavaScript

import { Observable } from 'rx';
import types from './types';
import { showChallengeComplete, moveToNextChallenge } from './actions';
import {
createErrorObservable,
makeToast,
updateUserPoints
} from '../../../redux/actions';
import { challengeSelector } from './selectors';
import { backEndProject } from '../../../utils/challengeTypes';
import { randomCompliment } from '../../../utils/get-words';
import { postJSON$ } from '../../../../utils/ajax-stream';
// NOTE(@BerkeleyTrue): this file could benefit from some refactoring.
// lots of repeat code
function completedChallenge(state) {
const { challenge: { id } } = challengeSelector(state);
const {
app: { user, csrfToken },
challengesApp: { files }
} = state;
const body = {
id,
_csrf: csrfToken,
files
};
const saveChallenge$ = postJSON$('/modern-challenge-completed', body)
.retry(3)
.flatMap(({ alreadyCompleted, points }) => {
return Observable.of(
makeToast({
message:
'Challenge saved.' +
(alreadyCompleted ? '' : ' First time Completed!'),
title: 'Saved',
type: 'info'
}),
updateUserPoints(user, points)
);
})
.catch(createErrorObservable);
const challengeCompleted$ = Observable.of(
moveToNextChallenge(),
makeToast({
title: 'Congratulations!',
message: user ? ' Saving...' : 'Moving on to next challenge.',
type: 'success'
})
);
return Observable.merge(saveChallenge$, challengeCompleted$);
}
function submitModern(type, state) {
const { tests } = state.challengesApp;
if (tests.length > 0 && tests.every(test => test.pass && !test.err)) {
if (type === types.checkChallenge) {
return Observable.of(
showChallengeComplete()
);
}
if (type === types.submitChallenge) {
return completedChallenge(state);
}
}
return Observable.just(makeToast({
message: 'Not all tests are passing, yet.',
title: 'Almost There!',
type: 'info'
}));
}
function submitProject(type, state, { solution, githubLink }) {
const {
challenge: { id, challengeType }
} = challengeSelector(state);
const {
app: { user, csrfToken }
} = state;
const body = {
id,
challengeType,
solution,
_csrf: csrfToken
};
if (challengeType === backEndProject) {
body.githubLink = githubLink;
}
const saveChallenge$ = postJSON$('/project-completed', body)
.retry(3)
.flatMap(({ alreadyCompleted, points }) => {
return Observable.of(
makeToast({
message:
'Challenge saved.' +
(alreadyCompleted ? '' : ' First time Completed!'),
title: 'Saved',
type: 'info'
}),
updateUserPoints(user, points)
);
})
.catch(createErrorObservable);
const challengeCompleted$ = Observable.of(
makeToast({
title: randomCompliment(),
message: user ? ' Saving...' : 'Moving on to next challenge.',
type: 'success'
})
// moveToNextChallenge()
);
return Observable.merge(saveChallenge$, challengeCompleted$);
}
function submitSimpleChallenge(type, state) {
const {
challenge: { id }
} = challengeSelector(state);
const {
app: { user, csrfToken }
} = state;
const body = {
id,
_csrf: csrfToken
};
const saveChallenge$ = postJSON$('/challenge-completed', body)
.retry(3)
.flatMap(({ alreadyCompleted, points }) => {
return Observable.of(
makeToast({
message:
'Challenge saved.' +
(alreadyCompleted ? '' : ' First time Completed!'),
title: 'Saved',
type: 'info'
}),
updateUserPoints(user, points)
);
})
.catch(createErrorObservable);
const challengeCompleted$ = Observable.of(
makeToast({
title: randomCompliment(),
message: user ? ' Saving...' : 'Moving on to next challenge.',
type: 'success'
}),
moveToNextChallenge()
);
return Observable.merge(saveChallenge$, challengeCompleted$);
}
const submitTypes = {
tests: submitModern,
step: submitSimpleChallenge,
video: submitSimpleChallenge,
'project.frontEnd': submitProject,
'project.backEnd': submitProject,
'project.simple': submitSimpleChallenge
};
export default function completionSaga(actions$, getState) {
return actions$
.filter(({ type }) => (
type === types.checkChallenge ||
type === types.submitChallenge
))
.flatMap(({ type, payload }) => {
const state = getState();
const { submitType } = challengeSelector(state);
const submitter = submitTypes[submitType] ||
(() => Observable.just(null));
return submitter(type, state, payload);
});
}