From f9e0303c32852a8a0c333f01bed1b0f752de974c Mon Sep 17 00:00:00 2001 From: DEVelooper29 <101932255+DEVelooper29@users.noreply.github.com> Date: Fri, 23 Jun 2023 02:49:01 +0530 Subject: [PATCH] feat(UI): take back to learn map after finishing a block (#50011) Co-authored-by: moT01 <20648924+moT01@users.noreply.github.com> --- .../Challenges/redux/completion-epic.js | 22 ++++++----- .../src/templates/Challenges/redux/index.js | 6 +++ client/utils/gatsby/challenge-page-creator.js | 31 +++++++++++++++ .../default/learn/challenges/navigation.ts | 38 +++++++++++++++++++ 4 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 cypress/e2e/default/learn/challenges/navigation.ts diff --git a/client/src/templates/Challenges/redux/completion-epic.js b/client/src/templates/Challenges/redux/completion-epic.js index 0e9aaf692f1..03be35efe6a 100644 --- a/client/src/templates/Challenges/redux/completion-epic.js +++ b/client/src/templates/Challenges/redux/completion-epic.js @@ -188,8 +188,14 @@ export default function completionEpic(action$, state$) { switchMap(({ type }) => { const state = state$.value; - const { nextChallengePath, challengeType, superBlock, block } = - challengeMetaSelector(state); + const { + nextChallengeMeta: { block: nextBlock }, + nextChallengePath, + challengeType, + superBlock, + block, + blockHashSlug + } = challengeMetaSelector(state); let submitter = () => of({ type: 'no-user-signed-in' }); if ( @@ -206,19 +212,17 @@ export default function completionEpic(action$, state$) { submitter = submitters[submitTypes[challengeType]]; } - const isNextChallengeInSameSuperBlock = - nextChallengePath.includes(superBlock); - - const pathToNavigateTo = isNextChallengeInSameSuperBlock - ? nextChallengePath - : `/learn/${superBlock}/#${superBlock}-projects`; + const lastChallengeInBlock = block !== nextBlock; + let pathToNavigateTo = lastChallengeInBlock + ? blockHashSlug + : nextChallengePath; const canAllowDonationRequest = (state, action) => isBlockNewlyCompletedSelector(state) && action.type === submitActionTypes.submitComplete; return submitter(type, state).pipe( - concat(of(setIsAdvancing(isNextChallengeInSameSuperBlock))), + concat(of(setIsAdvancing(!lastChallengeInBlock))), mergeMap(x => canAllowDonationRequest(state, x) ? of(x, allowBlockDonationRequests({ superBlock, block })) diff --git a/client/src/templates/Challenges/redux/index.js b/client/src/templates/Challenges/redux/index.js index 5dabd1fa7af..0700ff75250 100644 --- a/client/src/templates/Challenges/redux/index.js +++ b/client/src/templates/Challenges/redux/index.js @@ -20,7 +20,13 @@ const initialState = { challengeMeta: { superBlock: '', block: '', + blockHashSlug: '/', id: '', + nextChallengeMeta: { + superBlock: '', + block: '', + blockHashSlug: '/' + }, nextChallengePath: '/', prevChallengePath: '/', challengeType: -1 diff --git a/client/utils/gatsby/challenge-page-creator.js b/client/utils/gatsby/challenge-page-creator.js index 423d7b5c04b..5b4ccff6487 100644 --- a/client/utils/gatsby/challenge-page-creator.js +++ b/client/utils/gatsby/challenge-page-creator.js @@ -75,6 +75,31 @@ function getTemplateComponent(challengeType) { return views[viewTypes[challengeType]]; } +function getNextChallengeMeta(_node, index, nodeArray) { + const next = nodeArray[index + 1]; + if (next) { + const { superBlock, block } = next.node.challenge; + return { + superBlock, + block, + blockHashSlug: createBlockHashSlug(_node) + }; + } + return null; +} + +function createBlockHashSlug(_node) { + if (_node) { + const { + block, + fields: { slug } + } = _node; + const re = new RegExp(`${block}.*`); + return slug.replace(re, `#${block}`); + } + return null; +} + exports.createChallengePages = function (createPage) { return function ({ node: { challenge } }, index, allChallengeEdges) { const { @@ -96,6 +121,7 @@ exports.createChallengePages = function (createPage) { component: getTemplateComponent(challengeType), context: { challengeMeta: { + blockHashSlug: createBlockHashSlug(challenge), dashedName, certification, superBlock, @@ -103,6 +129,11 @@ exports.createChallengePages = function (createPage) { isFirstStep: getIsFirstStep(challenge, index, allChallengeEdges), template, required, + nextChallengeMeta: getNextChallengeMeta( + challenge, + index, + allChallengeEdges + ), nextChallengePath: getNextChallengePath( challenge, index, diff --git a/cypress/e2e/default/learn/challenges/navigation.ts b/cypress/e2e/default/learn/challenges/navigation.ts new file mode 100644 index 00000000000..7a5de059baf --- /dev/null +++ b/cypress/e2e/default/learn/challenges/navigation.ts @@ -0,0 +1,38 @@ +// middle of block +const challenge1 = { + url: '/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-javascript-calculator', + nextUrl: + '/learn/front-end-development-libraries/front-end-development-libraries-projects/build-a-25--5-clock' +}; + +// last in superblock +const challenge2 = { + url: '/learn/college-algebra-with-python/build-a-data-graph-explorer-project/build-a-data-graph-explorer', + nextUrl: + '/learn/college-algebra-with-python/#build-a-data-graph-explorer-project' +}; + +describe('submitting a challenge', () => { + before(() => { + cy.exec('pnpm run seed'); + cy.login(); + }); + + beforeEach(() => { + cy.preserveSession(); + }); + + it('in the middle of a block should take you to the next challenge', () => { + cy.visit(challenge1.url); + cy.get('#solution').type('https://example.com').type('{enter}'); + cy.contains('Submit and go to next challenge').click(); + cy.url().should('include', challenge1.nextUrl); + }); + + it('at the end of a superblock should take you to the superblock page with the current block hash', () => { + cy.visit(challenge2.url); + cy.get('#solution').type('https://example.com').type('{enter}'); + cy.contains('Submit and go to next challenge').click(); + cy.url().should('include', challenge2.nextUrl); + }); +});