diff --git a/client/src/templates/Challenges/components/project-preview-modal.css b/client/src/templates/Challenges/components/project-preview-modal.css index 4b436f27467..c54a516b060 100644 --- a/client/src/templates/Challenges/components/project-preview-modal.css +++ b/client/src/templates/Challenges/components/project-preview-modal.css @@ -1,6 +1,22 @@ .project-preview-modal-body { + position: relative; line-height: 0; padding: 0; min-height: 70vh; height: 70vh; } + +.project-preview-modal-loader { + position: absolute; + inset: 0; + z-index: 1; + background-color: var(--primary-background); +} + +.project-preview-modal-content { + height: 100%; +} + +.project-preview-modal-content.is-loading { + opacity: 0; +} diff --git a/client/src/templates/Challenges/components/project-preview-modal.tsx b/client/src/templates/Challenges/components/project-preview-modal.tsx index 23d1caa1a42..dc93a3c52bd 100644 --- a/client/src/templates/Challenges/components/project-preview-modal.tsx +++ b/client/src/templates/Challenges/components/project-preview-modal.tsx @@ -1,14 +1,18 @@ -import React, { useEffect } from 'react'; +import React, { useCallback, useEffect } from 'react'; import { connect } from 'react-redux'; import { Button, Modal } from '@freecodecamp/ui'; +import { Loader } from '../../../components/helpers'; import type { ChallengeData } from '../../../redux/prop-types'; import { closeModal, setEditorFocusability, projectPreviewMounted } from '../redux/actions'; -import { isProjectPreviewModalOpenSelector } from '../redux/selectors'; +import { + isProjectPreviewLoadingSelector, + isProjectPreviewModalOpenSelector +} from '../redux/selectors'; import { projectPreviewId } from '../utils/frame'; import Preview from './preview'; @@ -21,6 +25,7 @@ interface ProjectPreviewMountedPayload { interface Props { closeModal: (arg: string) => void; isOpen: boolean; + isLoading: boolean; projectPreviewMounted: (payload: ProjectPreviewMountedPayload) => void; challengeData?: ChallengeData | null; setEditorFocusability: (focusability: boolean) => void; @@ -29,7 +34,8 @@ interface Props { } const mapStateToProps = (state: unknown) => ({ - isOpen: isProjectPreviewModalOpenSelector(state) as boolean + isOpen: isProjectPreviewModalOpenSelector(state) as boolean, + isLoading: isProjectPreviewLoadingSelector(state) as boolean }); const mapDispatchToProps = { closeModal, @@ -40,6 +46,7 @@ const mapDispatchToProps = { function ProjectPreviewModal({ closeModal, isOpen, + isLoading, projectPreviewMounted, challengeData = null, setEditorFocusability, @@ -48,7 +55,11 @@ function ProjectPreviewModal({ }: Props): JSX.Element { useEffect(() => { if (isOpen) setEditorFocusability(false); - }); + }, [isOpen, setEditorFocusability]); + + const handlePreviewMounted = useCallback(() => { + projectPreviewMounted({ challengeData }); + }, [projectPreviewMounted, challengeData]); return ( {previewTitle} - projectPreviewMounted({ challengeData })} - /> + {isLoading ? ( +
+ +
+ ) : null} +
+ +