diff --git a/client/src/redux/prop-types.ts b/client/src/redux/prop-types.ts index aed72b85469..624cec20485 100644 --- a/client/src/redux/prop-types.ts +++ b/client/src/redux/prop-types.ts @@ -342,6 +342,7 @@ export type ChallengeMeta = { block: string; id: string; introPath: string; + isFirstStep: boolean; nextChallengePath: string; prevChallengePath: string; removeComments: boolean; diff --git a/client/src/templates/Challenges/classic/desktop-layout.tsx b/client/src/templates/Challenges/classic/desktop-layout.tsx index e14dea63e1e..f607a1ccfca 100644 --- a/client/src/templates/Challenges/classic/desktop-layout.tsx +++ b/client/src/templates/Challenges/classic/desktop-layout.tsx @@ -1,5 +1,5 @@ import { first } from 'lodash-es'; -import React, { useState, ReactElement } from 'react'; +import React, { useState, useEffect, ReactElement } from 'react'; import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex'; import { createSelector } from 'reselect'; import { connect } from 'react-redux'; @@ -29,6 +29,7 @@ interface DesktopLayoutProps { hasNotes: boolean; hasPreview: boolean; instructions: ReactElement; + isFirstStep: boolean; layoutState: { codePane: Pane; editorPane: Pane; @@ -90,12 +91,12 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => { const togglePane = (pane: string): void => { switch (pane) { case 'showPreviewPane': - if (!showPreviewPane && showPreviewPortal) setShowPreviewPortal(false); - setShowPreviewPane(!showPreviewPane); + if (showPreviewPortal) setShowPreviewPortal(false); portalWindow?.close(); + setShowPreviewPane(!showPreviewPane); break; case 'showPreviewPortal': - if (!showPreviewPortal && showPreviewPane) setShowPreviewPane(false); + if (showPreviewPane) setShowPreviewPane(false); setShowPreviewPortal(!showPreviewPortal); if (showPreviewPortal) portalWindow?.close(); break; @@ -130,6 +131,7 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => { testOutput, hasNotes, hasPreview, + isFirstStep, layoutState, notes, preview, @@ -137,6 +139,16 @@ const DesktopLayout = (props: DesktopLayoutProps): JSX.Element => { windowTitle } = props; + // on mount + useEffect(() => { + if (isFirstStep) { + setShowPreviewPortal(false); + portalWindow?.close(); + setShowPreviewPane(true); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const challengeFile = getChallengeFile(); const projectBasedChallenge = hasEditableBoundaries; const isMultifileCertProject = diff --git a/client/src/templates/Challenges/classic/show.tsx b/client/src/templates/Challenges/classic/show.tsx index 82605a74c79..e274e41e74c 100644 --- a/client/src/templates/Challenges/classic/show.tsx +++ b/client/src/templates/Challenges/classic/show.tsx @@ -480,7 +480,7 @@ class ShowClassic extends Component { const { executeChallenge, pageContext: { - challengeMeta: { nextChallengePath, prevChallengePath }, + challengeMeta: { isFirstStep, nextChallengePath, prevChallengePath }, projectPreview: { challengeData, showProjectPreview } }, challengeFiles, @@ -539,6 +539,7 @@ class ShowClassic extends Component { instructions={this.renderInstructionsPanel({ showToolPanel: true })} + isFirstStep={isFirstStep} layoutState={this.state.layout} notes={this.renderNotes(notes)} preview={this.renderPreview()} diff --git a/client/src/templates/Challenges/components/preview-portal.tsx b/client/src/templates/Challenges/components/preview-portal.tsx index ab785ad11bd..0868ade4300 100644 --- a/client/src/templates/Challenges/components/preview-portal.tsx +++ b/client/src/templates/Challenges/components/preview-portal.tsx @@ -6,11 +6,13 @@ import { createSelector } from 'reselect'; import { storePortalWindow, removePortalWindow, - setIsAdvancing + setShowPreviewPane, + setShowPreviewPortal } from '../redux/actions'; import { portalWindowSelector, - isAdvancingToChallengeSelector + showPreviewPaneSelector, + showPreviewPortalSelector } from '../redux/selectors'; interface PreviewPortalProps { @@ -21,21 +23,30 @@ interface PreviewPortalProps { storePortalWindow: (window: Window | null) => void; removePortalWindow: () => void; portalWindow: null | Window; - setIsAdvancing: (arg: boolean) => void; - isAdvancing: boolean; + setShowPreviewPane: (arg: boolean) => void; + setShowPreviewPortal: (arg: boolean) => void; + showPreviewPane: boolean; + showPreviewPortal: boolean; } const mapDispatchToProps = { storePortalWindow, removePortalWindow, - setIsAdvancing + setShowPreviewPane, + setShowPreviewPortal }; const mapStateToProps = createSelector( - isAdvancingToChallengeSelector, + showPreviewPaneSelector, + showPreviewPortalSelector, portalWindowSelector, - (isAdvancing: boolean, portalWindow: null | Window) => ({ - isAdvancing, + ( + showPreviewPane: boolean, + showPreviewPortal: boolean, + portalWindow: null | Window + ) => ({ + showPreviewPane, + showPreviewPortal, portalWindow }) ); @@ -44,7 +55,8 @@ class PreviewPortal extends Component { static displayName = 'PreviewPortal'; mainWindow: Window; externalWindow: Window | null = null; - isAdvancing: boolean; + showPreviewPane: boolean; + showPreviewPortal: boolean; containerEl; titleEl; styleEl; @@ -53,7 +65,8 @@ class PreviewPortal extends Component { super(props); this.mainWindow = window; this.externalWindow = this.props.portalWindow; - this.isAdvancing = this.props.isAdvancing; + this.showPreviewPane = this.props.showPreviewPane; + this.showPreviewPortal = this.props.showPreviewPortal; this.containerEl = document.createElement('div'); this.titleEl = document.createElement('title'); this.styleEl = document.createElement('style'); @@ -109,11 +122,8 @@ class PreviewPortal extends Component { } componentWillUnmount() { - if (!this.props.isAdvancing) { - this.externalWindow?.close(); - } + this.externalWindow?.close(); this.props.removePortalWindow(); - this.props.setIsAdvancing(false); } render() { diff --git a/client/src/templates/Challenges/redux/action-types.js b/client/src/templates/Challenges/redux/action-types.js index 22e7509f8c8..1dafc336d31 100644 --- a/client/src/templates/Challenges/redux/action-types.js +++ b/client/src/templates/Challenges/redux/action-types.js @@ -33,7 +33,6 @@ export const actionTypes = createTypes( 'setShowPreviewPortal', 'closeModal', 'openModal', - 'setIsAdvancing', 'previewMounted', 'projectPreviewMounted', diff --git a/client/src/templates/Challenges/redux/actions.js b/client/src/templates/Challenges/redux/actions.js index 92d9f2e8e79..0625fda7b79 100644 --- a/client/src/templates/Challenges/redux/actions.js +++ b/client/src/templates/Challenges/redux/actions.js @@ -52,7 +52,6 @@ export const disableBuildOnError = createAction( export const storedCodeFound = createAction(actionTypes.storedCodeFound); export const noStoredCodeFound = createAction(actionTypes.noStoredCodeFound); export const saveEditorContent = createAction(actionTypes.saveEditorContent); -export const setIsAdvancing = createAction(actionTypes.setIsAdvancing); export const closeModal = createAction(actionTypes.closeModal); export const openModal = createAction(actionTypes.openModal); diff --git a/client/src/templates/Challenges/redux/completion-epic.js b/client/src/templates/Challenges/redux/completion-epic.js index a8c534b7f26..0fce835555a 100644 --- a/client/src/templates/Challenges/redux/completion-epic.js +++ b/client/src/templates/Challenges/redux/completion-epic.js @@ -3,7 +3,6 @@ import { omit } from 'lodash-es'; import { ofType } from 'redux-observable'; import { empty, of } from 'rxjs'; import { catchError, concat, retry, switchMap, tap } from 'rxjs/operators'; -import { isChallenge } from '../../../utils/path-parsers'; import { challengeTypes, submitTypes } from '../../../../utils/challenge-types'; import { actionTypes as submitActionTypes } from '../../../redux/action-types'; import { @@ -16,11 +15,7 @@ import { mapFilesToChallengeFiles } from '../../../utils/ajax'; import { standardizeRequestBody } from '../../../utils/challenge-request-helpers'; import postUpdate$ from '../utils/post-update'; import { actionTypes } from './action-types'; -import { - closeModal, - updateSolutionFormValues, - setIsAdvancing -} from './actions'; +import { closeModal, updateSolutionFormValues } from './actions'; import { challengeFilesSelector, challengeMetaSelector, @@ -177,7 +172,6 @@ export default function completionEpic(action$, state$) { }; return submitter(type, state).pipe( - concat(of(setIsAdvancing(isChallenge(pathToNavigateTo())))), tap(res => { if (res.type !== submitActionTypes.updateFailed) { navigate(pathToNavigateTo()); diff --git a/client/src/templates/Challenges/redux/index.js b/client/src/templates/Challenges/redux/index.js index e167a0c2eb4..297e4e62928 100644 --- a/client/src/templates/Challenges/redux/index.js +++ b/client/src/templates/Challenges/redux/index.js @@ -45,8 +45,7 @@ const initialState = { showPreviewPortal: false, showPreviewPane: true, projectFormValues: {}, - successMessage: 'Happy Coding!', - isAdvancing: false + successMessage: 'Happy Coding!' }; export const epics = [ @@ -201,10 +200,6 @@ export const reducer = handleActions( ...state, successMessage: payload }), - [actionTypes.setIsAdvancing]: (state, { payload }) => ({ - ...state, - isAdvancing: payload - }), [actionTypes.closeModal]: (state, { payload }) => ({ ...state, modal: { diff --git a/client/src/templates/Challenges/redux/selectors.js b/client/src/templates/Challenges/redux/selectors.js index edec1f2df0c..8e416929cd9 100644 --- a/client/src/templates/Challenges/redux/selectors.js +++ b/client/src/templates/Challenges/redux/selectors.js @@ -30,7 +30,6 @@ export const successMessageSelector = state => state[ns].successMessage; export const projectFormValuesSelector = state => state[ns].projectFormValues || {}; -export const isAdvancingToChallengeSelector = state => state[ns].isAdvancing; export const portalDocumentSelector = state => state[ns].portalWindow?.document; export const portalWindowSelector = state => state[ns].portalWindow; diff --git a/client/utils/gatsby/challenge-page-creator.js b/client/utils/gatsby/challenge-page-creator.js index bcc334f56ec..4d5b71ff434 100644 --- a/client/utils/gatsby/challenge-page-creator.js +++ b/client/utils/gatsby/challenge-page-creator.js @@ -42,6 +42,14 @@ const views = { // quiz: Quiz }; +function getIsFirstStep(_node, index, nodeArray) { + const current = nodeArray[index]; + const previous = nodeArray[index - 1]; + + if (!previous) return true; + return previous.node.challenge.block !== current.node.challenge.block; +} + function getNextChallengePath(_node, index, nodeArray) { const next = nodeArray[index + 1]; return next ? next.node.challenge.fields.slug : '/learn'; @@ -79,6 +87,7 @@ exports.createChallengePages = function (createPage) { certification, superBlock, block, + isFirstStep: getIsFirstStep(challenge, index, allChallengeEdges), template, required, nextChallengePath: getNextChallengePath(