2018-09-30 11:37:19 +01:00
|
|
|
import { of, empty } from 'rxjs';
|
2018-05-24 19:45:38 +01:00
|
|
|
import {
|
|
|
|
switchMap,
|
|
|
|
retry,
|
|
|
|
catchError,
|
|
|
|
concat,
|
2018-09-12 15:58:08 +03:00
|
|
|
filter,
|
|
|
|
tap
|
2018-05-24 19:45:38 +01:00
|
|
|
} from 'rxjs/operators';
|
2018-04-06 14:51:52 +01:00
|
|
|
import { ofType } from 'redux-observable';
|
2018-09-12 15:58:08 +03:00
|
|
|
import { navigate } from 'gatsby';
|
2018-04-06 14:51:52 +01:00
|
|
|
|
|
|
|
import {
|
2018-05-24 19:45:38 +01:00
|
|
|
backendFormValuesSelector,
|
2018-09-27 14:19:03 +03:00
|
|
|
projectFormValuesSelector,
|
2018-05-24 19:45:38 +01:00
|
|
|
submitComplete,
|
2018-04-06 14:51:52 +01:00
|
|
|
types,
|
2018-05-24 19:45:38 +01:00
|
|
|
challengeMetaSelector,
|
|
|
|
challengeTestsSelector,
|
2018-06-12 16:42:39 +01:00
|
|
|
closeModal,
|
2018-09-21 17:30:16 +03:00
|
|
|
challengeFilesSelector,
|
|
|
|
updateProjectFormValues
|
2018-04-06 14:51:52 +01:00
|
|
|
} from './';
|
2018-06-07 23:13:33 +01:00
|
|
|
import {
|
|
|
|
userSelector,
|
|
|
|
isSignedInSelector,
|
|
|
|
openDonationModal,
|
2018-09-30 11:37:19 +01:00
|
|
|
showDonationSelector,
|
2018-07-26 14:37:10 +01:00
|
|
|
updateComplete,
|
2018-07-27 12:57:25 +01:00
|
|
|
updateFailed
|
2018-09-30 11:37:19 +01:00
|
|
|
} from '../../../redux';
|
2018-04-06 14:51:52 +01:00
|
|
|
|
2018-07-26 14:37:10 +01:00
|
|
|
import postUpdate$ from '../utils/postUpdate$';
|
2018-05-24 19:45:38 +01:00
|
|
|
import { challengeTypes, submitTypes } from '../../../../utils/challengeTypes';
|
2018-04-06 14:51:52 +01:00
|
|
|
|
2018-07-26 14:37:10 +01:00
|
|
|
function postChallenge(update, username) {
|
|
|
|
const saveChallenge = postUpdate$(update).pipe(
|
2018-05-24 19:45:38 +01:00
|
|
|
retry(3),
|
2018-07-26 14:37:10 +01:00
|
|
|
switchMap(({ points }) =>
|
|
|
|
of(
|
|
|
|
submitComplete({
|
|
|
|
username,
|
|
|
|
points,
|
|
|
|
...update.payload
|
|
|
|
}),
|
|
|
|
updateComplete()
|
|
|
|
)
|
2018-05-24 19:45:38 +01:00
|
|
|
),
|
2018-07-27 12:57:25 +01:00
|
|
|
catchError(() => of(updateFailed(update)))
|
2018-05-24 19:45:38 +01:00
|
|
|
);
|
|
|
|
return saveChallenge;
|
|
|
|
}
|
2018-04-06 14:51:52 +01:00
|
|
|
|
2018-05-24 19:45:38 +01:00
|
|
|
function submitModern(type, state) {
|
|
|
|
const tests = challengeTestsSelector(state);
|
|
|
|
if (tests.length > 0 && tests.every(test => test.pass && !test.err)) {
|
|
|
|
if (type === types.checkChallenge) {
|
|
|
|
return of({ type: 'this was a check challenge' });
|
|
|
|
}
|
2018-04-06 14:51:52 +01:00
|
|
|
|
2018-05-24 19:45:38 +01:00
|
|
|
if (type === types.submitChallenge) {
|
|
|
|
const { id } = challengeMetaSelector(state);
|
2018-06-12 16:42:39 +01:00
|
|
|
const files = challengeFilesSelector(state);
|
2018-05-24 19:45:38 +01:00
|
|
|
const { username } = userSelector(state);
|
2018-07-26 14:37:10 +01:00
|
|
|
const challengeInfo = {
|
|
|
|
id,
|
|
|
|
files
|
|
|
|
};
|
|
|
|
const update = {
|
2018-09-30 12:19:37 +01:00
|
|
|
endpoint: '/modern-challenge-completed',
|
2018-07-26 14:37:10 +01:00
|
|
|
payload: challengeInfo
|
|
|
|
};
|
2018-07-27 12:57:25 +01:00
|
|
|
return postChallenge(update, username);
|
2018-05-24 19:45:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return empty();
|
|
|
|
}
|
2018-04-06 14:51:52 +01:00
|
|
|
|
2018-05-24 19:45:38 +01:00
|
|
|
function submitProject(type, state) {
|
|
|
|
if (type === types.checkChallenge) {
|
|
|
|
return empty();
|
|
|
|
}
|
2018-04-06 14:51:52 +01:00
|
|
|
|
2018-09-27 14:19:03 +03:00
|
|
|
const { solution, githubLink } = projectFormValuesSelector(state);
|
2018-05-24 19:45:38 +01:00
|
|
|
const { id, challengeType } = challengeMetaSelector(state);
|
|
|
|
const { username } = userSelector(state);
|
|
|
|
const challengeInfo = { id, challengeType, solution };
|
|
|
|
if (challengeType === challengeTypes.backEndProject) {
|
|
|
|
challengeInfo.githubLink = githubLink;
|
|
|
|
}
|
2018-07-26 14:37:10 +01:00
|
|
|
|
|
|
|
const update = {
|
2018-09-30 12:19:37 +01:00
|
|
|
endpoint: '/project-completed',
|
2018-07-26 14:37:10 +01:00
|
|
|
payload: challengeInfo
|
|
|
|
};
|
2018-07-27 12:57:25 +01:00
|
|
|
return postChallenge(update, username).pipe(
|
|
|
|
concat(of(updateProjectFormValues({})))
|
2018-05-24 19:45:38 +01:00
|
|
|
);
|
|
|
|
}
|
2018-04-06 14:51:52 +01:00
|
|
|
|
2018-05-24 19:45:38 +01:00
|
|
|
function submitBackendChallenge(type, state) {
|
|
|
|
const tests = challengeTestsSelector(state);
|
|
|
|
if (tests.length > 0 && tests.every(test => test.pass && !test.err)) {
|
|
|
|
if (type === types.submitChallenge) {
|
|
|
|
const { id } = challengeMetaSelector(state);
|
|
|
|
const { username } = userSelector(state);
|
|
|
|
const { solution: { value: solution } } = backendFormValuesSelector(
|
|
|
|
state
|
|
|
|
);
|
|
|
|
const challengeInfo = { id, solution };
|
2018-07-26 14:37:10 +01:00
|
|
|
|
|
|
|
const update = {
|
2018-09-30 12:19:37 +01:00
|
|
|
endpoint: '/backend-challenge-completed',
|
2018-07-26 14:37:10 +01:00
|
|
|
payload: challengeInfo
|
|
|
|
};
|
2018-07-27 12:57:25 +01:00
|
|
|
return postChallenge(update, username);
|
2018-05-24 19:45:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return empty();
|
|
|
|
}
|
2018-04-06 14:51:52 +01:00
|
|
|
|
2018-05-24 19:45:38 +01:00
|
|
|
const submitters = {
|
|
|
|
tests: submitModern,
|
|
|
|
backend: submitBackendChallenge,
|
|
|
|
'project.frontEnd': submitProject,
|
|
|
|
'project.backEnd': submitProject
|
|
|
|
};
|
2018-04-06 14:51:52 +01:00
|
|
|
|
2018-06-07 23:13:33 +01:00
|
|
|
function shouldShowDonate(state) {
|
2018-09-30 11:37:19 +01:00
|
|
|
return showDonationSelector(state) ? of(openDonationModal()) : empty();
|
2018-06-07 23:13:33 +01:00
|
|
|
}
|
|
|
|
|
2018-09-30 11:37:19 +01:00
|
|
|
export default function completionEpic(action$, state$) {
|
2018-04-06 14:51:52 +01:00
|
|
|
return action$.pipe(
|
|
|
|
ofType(types.submitChallenge),
|
|
|
|
switchMap(({ type }) => {
|
2018-09-30 11:37:19 +01:00
|
|
|
const state = state$.value;
|
2018-05-24 19:45:38 +01:00
|
|
|
const meta = challengeMetaSelector(state);
|
2018-06-07 23:13:33 +01:00
|
|
|
const { isDonating } = userSelector(state);
|
2018-05-24 19:45:38 +01:00
|
|
|
const { nextChallengePath, introPath, challengeType } = meta;
|
2018-06-07 23:13:33 +01:00
|
|
|
const showDonate = isDonating ? empty() : shouldShowDonate(state);
|
2018-05-24 19:45:38 +01:00
|
|
|
const closeChallengeModal = of(closeModal('completion'));
|
2018-05-26 21:32:40 +01:00
|
|
|
let submitter = () => of({ type: 'no-user-signed-in' });
|
2018-05-24 19:45:38 +01:00
|
|
|
if (
|
|
|
|
!(challengeType in submitTypes) ||
|
|
|
|
!(submitTypes[challengeType] in submitters)
|
|
|
|
) {
|
|
|
|
throw new Error(
|
|
|
|
'Unable to find the correct submit function for challengeType ' +
|
|
|
|
challengeType
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (isSignedInSelector(state)) {
|
|
|
|
submitter = submitters[submitTypes[challengeType]];
|
|
|
|
}
|
|
|
|
|
|
|
|
return submitter(type, state).pipe(
|
2018-09-12 15:58:08 +03:00
|
|
|
tap(() => navigate(introPath ? introPath : nextChallengePath)),
|
2018-05-24 19:45:38 +01:00
|
|
|
concat(closeChallengeModal),
|
2018-06-07 23:13:33 +01:00
|
|
|
concat(showDonate),
|
2018-05-24 19:45:38 +01:00
|
|
|
filter(Boolean)
|
|
|
|
);
|
2018-04-06 14:51:52 +01:00
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|