fix(client): update current challenge for all challenges

This commit is contained in:
Valeriy S
2019-02-06 14:30:54 +03:00
committed by Stuart Taylor
parent ba9e45023d
commit f6fa754906
7 changed files with 81 additions and 53 deletions

View File

@ -7,6 +7,7 @@ import { graphql } from 'gatsby';
import { import {
executeChallenge, executeChallenge,
challengeMounted,
challengeTestsSelector, challengeTestsSelector,
consoleOutputSelector, consoleOutputSelector,
initTests, initTests,
@ -42,12 +43,15 @@ const reduxFormPropTypes = {
}; };
const propTypes = { const propTypes = {
challengeMounted: PropTypes.func.isRequired,
description: PropTypes.string, description: PropTypes.string,
executeChallenge: PropTypes.func.isRequired, executeChallenge: PropTypes.func.isRequired,
id: PropTypes.string, id: PropTypes.string,
initTests: PropTypes.func.isRequired,
output: PropTypes.string, output: PropTypes.string,
tests: PropTypes.array, tests: PropTypes.array,
title: PropTypes.string, title: PropTypes.string,
updateChallengeMeta: PropTypes.func.isRequired,
...reduxFormPropTypes ...reduxFormPropTypes
}; };
@ -67,6 +71,7 @@ const mapStateToProps = createSelector(
); );
const mapDispatchToActions = { const mapDispatchToActions = {
challengeMounted,
executeChallenge, executeChallenge,
initTests, initTests,
updateChallengeMeta updateChallengeMeta
@ -89,6 +94,7 @@ export class BackEnd extends Component {
componentDidMount() { componentDidMount() {
const { const {
challengeMounted,
initTests, initTests,
updateChallengeMeta, updateChallengeMeta,
data: { data: {
@ -101,6 +107,7 @@ export class BackEnd extends Component {
} = this.props; } = this.props;
initTests(tests); initTests(tests);
updateChallengeMeta({ ...challengeMeta, challengeType }); updateChallengeMeta({ ...challengeMeta, challengeType });
challengeMounted(challengeMeta.id);
window.addEventListener('resize', this.updateDimensions); window.addEventListener('resize', this.updateDimensions);
} }
@ -119,6 +126,7 @@ export class BackEnd extends Component {
} }
} = prevProps; } = prevProps;
const { const {
challengeMounted,
initTests, initTests,
updateChallengeMeta, updateChallengeMeta,
data: { data: {
@ -133,6 +141,7 @@ export class BackEnd extends Component {
if (prevTitle !== currentTitle) { if (prevTitle !== currentTitle) {
initTests(tests); initTests(tests);
updateChallengeMeta({ ...challengeMeta, challengeType }); updateChallengeMeta({ ...challengeMeta, challengeType });
challengeMounted(challengeMeta.id);
} }
} }

View File

@ -166,6 +166,11 @@ class ShowClassic extends Component {
} }
} }
componentWillUnmount() {
const { createFiles } = this.props;
createFiles({});
}
getChallenge = () => this.props.data.challengeNode; getChallenge = () => this.props.data.challengeNode;
getBlockNameTitle() { getBlockNameTitle() {

View File

@ -8,8 +8,8 @@ import Helmet from 'react-helmet';
import { randomCompliment } from '../utils/get-words'; import { randomCompliment } from '../utils/get-words';
import { ChallengeNode } from '../../../redux/propTypes'; import { ChallengeNode } from '../../../redux/propTypes';
import { import {
challengeMounted,
updateChallengeMeta, updateChallengeMeta,
createFiles,
updateSuccessMessage, updateSuccessMessage,
openModal, openModal,
updateProjectFormValues updateProjectFormValues
@ -32,7 +32,7 @@ const mapDispatchToProps = dispatch =>
bindActionCreators( bindActionCreators(
{ {
updateChallengeMeta, updateChallengeMeta,
createFiles, challengeMounted,
updateProjectFormValues, updateProjectFormValues,
updateSuccessMessage, updateSuccessMessage,
openCompletionModal: () => openModal('completion') openCompletionModal: () => openModal('completion')
@ -41,7 +41,7 @@ const mapDispatchToProps = dispatch =>
); );
const propTypes = { const propTypes = {
createFiles: PropTypes.func.isRequired, challengeMounted: PropTypes.func.isRequired,
data: PropTypes.shape({ data: PropTypes.shape({
challengeNode: ChallengeNode challengeNode: ChallengeNode
}), }),
@ -57,34 +57,42 @@ const propTypes = {
export class Project extends Component { export class Project extends Component {
componentDidMount() { componentDidMount() {
const { const {
createFiles, challengeMounted,
data: { challengeNode: { title, challengeType } }, data: {
challengeNode: { title, challengeType }
},
pageContext: { challengeMeta }, pageContext: { challengeMeta },
updateChallengeMeta, updateChallengeMeta,
updateSuccessMessage updateSuccessMessage
} = this.props; } = this.props;
createFiles({});
updateSuccessMessage(randomCompliment()); updateSuccessMessage(randomCompliment());
return updateChallengeMeta({ ...challengeMeta, title, challengeType }); updateChallengeMeta({ ...challengeMeta, title, challengeType });
challengeMounted(challengeMeta.id);
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { data: { challengeNode: { title: prevTitle } } } = prevProps;
const { const {
createFiles, data: {
data: { challengeNode: { title: currentTitle, challengeType } }, challengeNode: { title: prevTitle }
}
} = prevProps;
const {
challengeMounted,
data: {
challengeNode: { title: currentTitle, challengeType }
},
pageContext: { challengeMeta }, pageContext: { challengeMeta },
updateChallengeMeta, updateChallengeMeta,
updateSuccessMessage updateSuccessMessage
} = this.props; } = this.props;
updateSuccessMessage(randomCompliment()); updateSuccessMessage(randomCompliment());
if (prevTitle !== currentTitle) { if (prevTitle !== currentTitle) {
createFiles({});
updateChallengeMeta({ updateChallengeMeta({
...challengeMeta, ...challengeMeta,
title: currentTitle, title: currentTitle,
challengeType challengeType
}); });
challengeMounted(challengeMeta.id);
} }
} }
@ -133,7 +141,10 @@ export class Project extends Component {
Project.displayName = 'Project'; Project.displayName = 'Project';
Project.propTypes = propTypes; Project.propTypes = propTypes;
export default connect(mapStateToProps, mapDispatchToProps)(Project); export default connect(
mapStateToProps,
mapDispatchToProps
)(Project);
export const query = graphql` export const query = graphql`
query ProjectChallenge($slug: String!) { query ProjectChallenge($slug: String!) {

View File

@ -89,6 +89,10 @@ function saveCodeEpic(action$, state$) {
function loadCodeEpic(action$, state$) { function loadCodeEpic(action$, state$) {
return action$.pipe( return action$.pipe(
ofType(types.challengeMounted), ofType(types.challengeMounted),
filter(() => {
const files = challengeFilesSelector(state$.value);
return Object.keys(files).length > 0;
}),
switchMap(({ payload: id }) => { switchMap(({ payload: id }) => {
let finalFiles; let finalFiles;
const state = state$.value; const state = state$.value;

View File

@ -1,36 +0,0 @@
import { of } from 'rxjs';
import { ofType } from 'redux-observable';
import { types } from './';
import { filter, switchMap, catchError, mapTo } from 'rxjs/operators';
import {
isSignedInSelector,
currentChallengeIdSelector,
updateComplete,
updateFailed
} from '../../../redux';
import postUpdate$ from '../utils/postUpdate$';
function currentChallengeEpic(action$, state$) {
return action$.pipe(
ofType(types.challengeMounted),
filter(() => isSignedInSelector(state$.value)),
filter(
({ payload }) => payload !== currentChallengeIdSelector(state$.value)
),
switchMap(({ payload }) => {
const update = {
endpoint: '/update-my-current-challenge',
payload: {
currentChallengeId: payload
}
};
return postUpdate$(update).pipe(
mapTo(updateComplete()),
catchError(() => of(updateFailed(update)))
);
})
);
}
export default currentChallengeEpic;

View File

@ -0,0 +1,35 @@
import { put, select, call, takeEvery } from 'redux-saga/effects';
import {
isSignedInSelector,
currentChallengeIdSelector,
updateComplete,
updateFailed
} from '../../../redux';
import { post } from '../../../utils/ajax';
function* currentChallengeSaga({ payload }) {
const isSignedIn = yield select(isSignedInSelector);
const currentChallengeId = yield select(currentChallengeIdSelector);
if (isSignedIn && payload !== currentChallengeId) {
const update = {
endpoint: '/update-my-current-challenge',
payload: {
currentChallengeId: payload
}
};
try {
yield call(post, update.endpoint, update.payload);
yield put(updateComplete());
} catch {
yield put(updateFailed(update));
}
}
}
export function createCurrentChallengeSaga(types) {
return [
takeEvery(types.challengeMounted, currentChallengeSaga)
];
}

View File

@ -10,10 +10,10 @@ import completionEpic from './completion-epic';
import codeLockEpic from './code-lock-epic'; import codeLockEpic from './code-lock-epic';
import createQuestionEpic from './create-question-epic'; import createQuestionEpic from './create-question-epic';
import codeStorageEpic from './code-storage-epic'; import codeStorageEpic from './code-storage-epic';
import currentChallengeEpic from './current-challenge-epic';
import { createIdToNameMapSaga } from './id-to-name-map-saga'; import { createIdToNameMapSaga } from './id-to-name-map-saga';
import { createExecuteChallengeSaga } from './execute-challenge-saga'; import { createExecuteChallengeSaga } from './execute-challenge-saga';
import { createCurrentChallengeSaga } from './current-challenge-saga';
export const ns = 'challenge'; export const ns = 'challenge';
export const backendNS = 'backendChallenge'; export const backendNS = 'backendChallenge';
@ -85,13 +85,13 @@ export const epics = [
codeLockEpic, codeLockEpic,
completionEpic, completionEpic,
createQuestionEpic, createQuestionEpic,
codeStorageEpic, codeStorageEpic
currentChallengeEpic
]; ];
export const sagas = [ export const sagas = [
...createIdToNameMapSaga(types), ...createIdToNameMapSaga(types),
...createExecuteChallengeSaga(types) ...createExecuteChallengeSaga(types),
...createCurrentChallengeSaga(types)
]; ];
export const createFiles = createAction(types.createFiles, challengeFiles => export const createFiles = createAction(types.createFiles, challengeFiles =>
@ -300,7 +300,7 @@ export const reducer = handleActions(
...state, ...state,
currentTab: payload currentTab: payload
}), }),
[types.executeChallenge]: (state, { payload }) => ({ [types.executeChallenge]: state => ({
...state, ...state,
currentTab: 3 currentTab: 3
}) })