fix(client): update current challenge for all challenges
This commit is contained in:
@ -7,6 +7,7 @@ import { graphql } from 'gatsby';
|
||||
|
||||
import {
|
||||
executeChallenge,
|
||||
challengeMounted,
|
||||
challengeTestsSelector,
|
||||
consoleOutputSelector,
|
||||
initTests,
|
||||
@ -42,12 +43,15 @@ const reduxFormPropTypes = {
|
||||
};
|
||||
|
||||
const propTypes = {
|
||||
challengeMounted: PropTypes.func.isRequired,
|
||||
description: PropTypes.string,
|
||||
executeChallenge: PropTypes.func.isRequired,
|
||||
id: PropTypes.string,
|
||||
initTests: PropTypes.func.isRequired,
|
||||
output: PropTypes.string,
|
||||
tests: PropTypes.array,
|
||||
title: PropTypes.string,
|
||||
updateChallengeMeta: PropTypes.func.isRequired,
|
||||
...reduxFormPropTypes
|
||||
};
|
||||
|
||||
@ -67,6 +71,7 @@ const mapStateToProps = createSelector(
|
||||
);
|
||||
|
||||
const mapDispatchToActions = {
|
||||
challengeMounted,
|
||||
executeChallenge,
|
||||
initTests,
|
||||
updateChallengeMeta
|
||||
@ -89,6 +94,7 @@ export class BackEnd extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
challengeMounted,
|
||||
initTests,
|
||||
updateChallengeMeta,
|
||||
data: {
|
||||
@ -101,6 +107,7 @@ export class BackEnd extends Component {
|
||||
} = this.props;
|
||||
initTests(tests);
|
||||
updateChallengeMeta({ ...challengeMeta, challengeType });
|
||||
challengeMounted(challengeMeta.id);
|
||||
window.addEventListener('resize', this.updateDimensions);
|
||||
}
|
||||
|
||||
@ -119,6 +126,7 @@ export class BackEnd extends Component {
|
||||
}
|
||||
} = prevProps;
|
||||
const {
|
||||
challengeMounted,
|
||||
initTests,
|
||||
updateChallengeMeta,
|
||||
data: {
|
||||
@ -133,6 +141,7 @@ export class BackEnd extends Component {
|
||||
if (prevTitle !== currentTitle) {
|
||||
initTests(tests);
|
||||
updateChallengeMeta({ ...challengeMeta, challengeType });
|
||||
challengeMounted(challengeMeta.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,6 +166,11 @@ class ShowClassic extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { createFiles } = this.props;
|
||||
createFiles({});
|
||||
}
|
||||
|
||||
getChallenge = () => this.props.data.challengeNode;
|
||||
|
||||
getBlockNameTitle() {
|
||||
|
@ -8,8 +8,8 @@ import Helmet from 'react-helmet';
|
||||
import { randomCompliment } from '../utils/get-words';
|
||||
import { ChallengeNode } from '../../../redux/propTypes';
|
||||
import {
|
||||
challengeMounted,
|
||||
updateChallengeMeta,
|
||||
createFiles,
|
||||
updateSuccessMessage,
|
||||
openModal,
|
||||
updateProjectFormValues
|
||||
@ -32,7 +32,7 @@ const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
{
|
||||
updateChallengeMeta,
|
||||
createFiles,
|
||||
challengeMounted,
|
||||
updateProjectFormValues,
|
||||
updateSuccessMessage,
|
||||
openCompletionModal: () => openModal('completion')
|
||||
@ -41,7 +41,7 @@ const mapDispatchToProps = dispatch =>
|
||||
);
|
||||
|
||||
const propTypes = {
|
||||
createFiles: PropTypes.func.isRequired,
|
||||
challengeMounted: PropTypes.func.isRequired,
|
||||
data: PropTypes.shape({
|
||||
challengeNode: ChallengeNode
|
||||
}),
|
||||
@ -57,34 +57,42 @@ const propTypes = {
|
||||
export class Project extends Component {
|
||||
componentDidMount() {
|
||||
const {
|
||||
createFiles,
|
||||
data: { challengeNode: { title, challengeType } },
|
||||
challengeMounted,
|
||||
data: {
|
||||
challengeNode: { title, challengeType }
|
||||
},
|
||||
pageContext: { challengeMeta },
|
||||
updateChallengeMeta,
|
||||
updateSuccessMessage
|
||||
} = this.props;
|
||||
createFiles({});
|
||||
updateSuccessMessage(randomCompliment());
|
||||
return updateChallengeMeta({ ...challengeMeta, title, challengeType });
|
||||
updateChallengeMeta({ ...challengeMeta, title, challengeType });
|
||||
challengeMounted(challengeMeta.id);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { data: { challengeNode: { title: prevTitle } } } = prevProps;
|
||||
const {
|
||||
createFiles,
|
||||
data: { challengeNode: { title: currentTitle, challengeType } },
|
||||
data: {
|
||||
challengeNode: { title: prevTitle }
|
||||
}
|
||||
} = prevProps;
|
||||
const {
|
||||
challengeMounted,
|
||||
data: {
|
||||
challengeNode: { title: currentTitle, challengeType }
|
||||
},
|
||||
pageContext: { challengeMeta },
|
||||
updateChallengeMeta,
|
||||
updateSuccessMessage
|
||||
} = this.props;
|
||||
updateSuccessMessage(randomCompliment());
|
||||
if (prevTitle !== currentTitle) {
|
||||
createFiles({});
|
||||
updateChallengeMeta({
|
||||
...challengeMeta,
|
||||
title: currentTitle,
|
||||
challengeType
|
||||
});
|
||||
challengeMounted(challengeMeta.id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +141,10 @@ export class Project extends Component {
|
||||
Project.displayName = 'Project';
|
||||
Project.propTypes = propTypes;
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Project);
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Project);
|
||||
|
||||
export const query = graphql`
|
||||
query ProjectChallenge($slug: String!) {
|
||||
|
@ -89,6 +89,10 @@ function saveCodeEpic(action$, state$) {
|
||||
function loadCodeEpic(action$, state$) {
|
||||
return action$.pipe(
|
||||
ofType(types.challengeMounted),
|
||||
filter(() => {
|
||||
const files = challengeFilesSelector(state$.value);
|
||||
return Object.keys(files).length > 0;
|
||||
}),
|
||||
switchMap(({ payload: id }) => {
|
||||
let finalFiles;
|
||||
const state = state$.value;
|
||||
|
@ -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;
|
@ -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)
|
||||
];
|
||||
}
|
@ -10,10 +10,10 @@ import completionEpic from './completion-epic';
|
||||
import codeLockEpic from './code-lock-epic';
|
||||
import createQuestionEpic from './create-question-epic';
|
||||
import codeStorageEpic from './code-storage-epic';
|
||||
import currentChallengeEpic from './current-challenge-epic';
|
||||
|
||||
import { createIdToNameMapSaga } from './id-to-name-map-saga';
|
||||
import { createExecuteChallengeSaga } from './execute-challenge-saga';
|
||||
import { createCurrentChallengeSaga } from './current-challenge-saga';
|
||||
|
||||
export const ns = 'challenge';
|
||||
export const backendNS = 'backendChallenge';
|
||||
@ -85,13 +85,13 @@ export const epics = [
|
||||
codeLockEpic,
|
||||
completionEpic,
|
||||
createQuestionEpic,
|
||||
codeStorageEpic,
|
||||
currentChallengeEpic
|
||||
codeStorageEpic
|
||||
];
|
||||
|
||||
export const sagas = [
|
||||
...createIdToNameMapSaga(types),
|
||||
...createExecuteChallengeSaga(types)
|
||||
...createExecuteChallengeSaga(types),
|
||||
...createCurrentChallengeSaga(types)
|
||||
];
|
||||
|
||||
export const createFiles = createAction(types.createFiles, challengeFiles =>
|
||||
@ -300,7 +300,7 @@ export const reducer = handleActions(
|
||||
...state,
|
||||
currentTab: payload
|
||||
}),
|
||||
[types.executeChallenge]: (state, { payload }) => ({
|
||||
[types.executeChallenge]: state => ({
|
||||
...state,
|
||||
currentTab: 3
|
||||
})
|
||||
|
Reference in New Issue
Block a user