From 16972228ea38a02b60f0e4aff4454c687f83b52a Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Sun, 26 Feb 2023 20:46:37 +0200 Subject: [PATCH 1/2] TCA-996 - refactor certificate page layout into it's own component --- .../certificate-view/CertificateView.tsx | 149 +++++------------- .../certificate/Certificate.module.scss | 2 +- .../UserCertificate.module.scss | 5 - .../user-certificate/UserCertificate.tsx | 44 ++---- .../CertificatePageLayout.module.scss} | 0 .../CertificatePageLayout.tsx | 140 ++++++++++++++++ .../certificate-page-layout/index.ts | 1 + src-ts/tools/learn/learn-lib/index.ts | 5 +- .../TCACertificatePreview.tsx | 3 - .../TCACertificate.module.scss | 56 ------- .../tca-certificate/TCACertificate.tsx | 3 +- .../CertificateView.module.scss | 80 ---------- .../certificate-view/CertificateView.tsx | 117 ++++---------- .../my-certificate/MyTCACertificate.tsx | 8 +- .../UserTCACertificate.module.scss | 5 - .../user-certificate/UserTCACertificate.tsx | 53 ++----- 16 files changed, 242 insertions(+), 429 deletions(-) delete mode 100644 src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.module.scss rename src-ts/tools/learn/{course-certificate/certificate-view/CertificateView.module.scss => learn-lib/certificate-page-layout/CertificatePageLayout.module.scss} (100%) create mode 100644 src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.tsx create mode 100644 src-ts/tools/learn/learn-lib/certificate-page-layout/index.ts delete mode 100644 src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.module.scss delete mode 100644 src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.module.scss diff --git a/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx b/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx index eee4dc5f6..05b9a8698 100644 --- a/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx +++ b/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx @@ -1,51 +1,39 @@ -import { FC, MutableRefObject, useCallback, useEffect, useMemo, useRef } from 'react' -import classNames from 'classnames' - import { - FacebookSocialShareBtn, - fileDownloadCanvasAsImage, - IconOutline, - LinkedinSocialShareBtn, - LoadingSpinner, - NavigateBackFunction, - TwitterSocialShareBtn, - useNavigateBack, - UserProfile, -} from '../../../../lib' + FC, + MutableRefObject, + useEffect, + useMemo, + useRef, +} from 'react' + import { - ActionButton, AllCertificationsProviderData, + CertificatePageLayout, CoursesProviderData, - useCertificateCanvas, - useCertificatePrint, - useCertificateScaling, useGetCertification, useGetCourses, useGetUserCompletedCertifications, UserCompletedCertificationsProviderData, } from '../../learn-lib' -import { getCoursePath, getUserCertificateSsr } from '../../learn.routes' - -import { Certificate } from './certificate' -import styles from './CertificateView.module.scss' +import { + getCoursePath, + getUserCertificateSsr, +} from '../../learn.routes' +import { UserProfile } from '../../../../lib' -export type CertificateViewStyle = 'large-container' +import Certificate from './certificate/Certificate' interface CertificateViewProps { - certification: string, - hideActions?: boolean, + certification: string + fullScreenCertLayout?: boolean onCertificationNotCompleted: () => void - profile: UserProfile, - provider: string, - viewStyle?: CertificateViewStyle + profile: UserProfile + provider: string } const CertificateView: FC = (props: CertificateViewProps) => { - - const navigateBack: NavigateBackFunction = useNavigateBack() const coursePath: string = getCoursePath(props.provider, props.certification) const certificateElRef: MutableRefObject = useRef() - const certificateWrapRef: MutableRefObject = useRef() const userName: string = useMemo(() => ( [props.profile.firstName, props.profile.lastName].filter(Boolean) @@ -94,29 +82,6 @@ const CertificateView: FC = (props: CertificateViewProps) completedCertificateReady && courseReady && certificateReady ), [certificateReady, completedCertificateReady, courseReady]) - const readyAndCompletedCertification: boolean = useMemo(() => ( - ready && hasCompletedTheCertification - ), [hasCompletedTheCertification, ready]) - - useCertificateScaling(ready ? certificateWrapRef : undefined, 880, 880) - - const handleBackBtnClick: () => void = useCallback(() => { - navigateBack(coursePath) - }, [coursePath, navigateBack]) - - const getCertificateCanvas: () => Promise = useCertificateCanvas(certificateElRef) - - const handleDownload: () => Promise = useCallback(async () => { - - const canvas: HTMLCanvasElement | void = await getCertificateCanvas() - if (!!canvas) { - fileDownloadCanvasAsImage(canvas, `${certificationTitle}.png`) - } - - }, [certificationTitle, getCertificateCanvas]) - - const handlePrint: () => Promise = useCertificatePrint(certificateElRef, certificationTitle) - useEffect(() => { if (ready && !hasCompletedTheCertification) { props.onCertificationNotCompleted() @@ -124,65 +89,25 @@ const CertificateView: FC = (props: CertificateViewProps) }, [coursePath, hasCompletedTheCertification, props, ready]) return ( - <> - - - {ready && readyAndCompletedCertification && ( -
-
- {!props.hideActions && ( -
- } - onClick={handleBackBtnClick} - /> -
- )} -
-
- -
-
- {!props.hideActions && ( -
- } - onClick={handlePrint} - /> - } - onClick={handleDownload} - /> - - - -
- )} -
-
- )} - + + + ) } diff --git a/src-ts/tools/learn/course-certificate/certificate-view/certificate/Certificate.module.scss b/src-ts/tools/learn/course-certificate/certificate-view/certificate/Certificate.module.scss index dc560fbfb..9ddde408e 100644 --- a/src-ts/tools/learn/course-certificate/certificate-view/certificate/Certificate.module.scss +++ b/src-ts/tools/learn/course-certificate/certificate-view/certificate/Certificate.module.scss @@ -19,7 +19,7 @@ flex-direction: column; } - .wrap:global(.large-container) & { + :global(.large-container) & { padding-left: calc($space-mx + $space-mxx); } diff --git a/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.module.scss b/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.module.scss deleted file mode 100644 index 06821e91a..000000000 --- a/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -.full-screen-cert { - flex: 1 1 auto; - display: flex; - flex-direction: column; -} \ No newline at end of file diff --git a/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.tsx b/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.tsx index 2df909b4d..41ff34798 100644 --- a/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.tsx +++ b/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.tsx @@ -1,22 +1,16 @@ -import { Dispatch, FC, MutableRefObject, SetStateAction, useEffect, useLayoutEffect, useRef, useState } from 'react' -import { Params, useParams, useSearchParams } from 'react-router-dom' +import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react' +import { Params, useParams } from 'react-router-dom' import { LoadingSpinner, profileGetPublicAsync, UserProfile, } from '../../../../lib' -import { getViewStyleParamKey } from '../../learn.routes' -import { CertificateView, CertificateViewStyle } from '../certificate-view' -import { hideSiblings } from '../../learn-lib/functions' - -import styles from './UserCertificate.module.scss' +import { CertificateView } from '../certificate-view' const UserCertificate: FC<{}> = () => { - const wrapElRef: MutableRefObject = useRef() const routeParams: Params = useParams() - const [queryParams]: [URLSearchParams, any] = useSearchParams() const [profile, setProfile]: [ UserProfile | undefined, @@ -37,33 +31,19 @@ const UserCertificate: FC<{}> = () => { } }, [routeParams.memberHandle, setProfileReady]) - useLayoutEffect(() => { - const el: HTMLElement = wrapElRef.current - if (!el) { - return - } - - hideSiblings(el) - hideSiblings(el.parentElement as HTMLElement) - el.classList.add(styles['full-screen-cert']) - }) - return ( <> -
- {profileReady && profile && ( - { }} - hideActions - viewStyle={queryParams.get(getViewStyleParamKey()) as CertificateViewStyle} - /> - )} -
+ {profileReady && profile && ( + { }} + fullScreenCertLayout + /> + )} ) } diff --git a/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.module.scss b/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.module.scss similarity index 100% rename from src-ts/tools/learn/course-certificate/certificate-view/CertificateView.module.scss rename to src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.module.scss diff --git a/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.tsx b/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.tsx new file mode 100644 index 000000000..4e92c4b8c --- /dev/null +++ b/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.tsx @@ -0,0 +1,140 @@ +import { + FC, + MutableRefObject, + ReactNode, + useCallback, + useLayoutEffect, + useRef, +} from 'react' +import { useSearchParams } from 'react-router-dom' +import classNames from 'classnames' + +import { + FacebookSocialShareBtn, + fileDownloadCanvasAsImage, + IconOutline, + LinkedinSocialShareBtn, + LoadingSpinner, + NavigateBackFunction, + TwitterSocialShareBtn, + useNavigateBack, +} from '../../../../lib' +import { useCertificateScaling } from '../use-certificate-scaling-hook' +import { useCertificateCanvas } from '../use-certificate-canvas-hook' +import { useCertificatePrint } from '../use-certificate-print-hook' +import { ActionButton } from '../action-button' +import { hideSiblings } from '../functions' +import { getViewStyleParamKey } from '../../learn.routes' + +import styles from './CertificatePageLayout.module.scss' + +export type CertificatePageLayoutStyle = 'large-container' + +interface CertificatePageLayoutProps { + actions?: ReactNode + certificateElRef: MutableRefObject + children?: ReactNode + fallbackBackUrl?: string + fullScreenCertLayout?: boolean + isCertificateCompleted?: boolean + isReady?: boolean + ssrUrl: string + title?: string +} + +const CertificatePageLayout: FC = (props: CertificatePageLayoutProps) => { + const [queryParams]: [URLSearchParams, any] = useSearchParams() + const viewStyle: CertificatePageLayoutStyle = queryParams.get(getViewStyleParamKey()) as CertificatePageLayoutStyle + + const wrapElRef: MutableRefObject = useRef() + const certificateWrapRef: MutableRefObject = useRef() + const navigateBack: NavigateBackFunction = useNavigateBack() + + useCertificateScaling(props.isReady ? certificateWrapRef : undefined, 880, 880) + + const handleBackBtnClick: () => void = useCallback(() => { + navigateBack(props.fallbackBackUrl ?? '') + }, [props.fallbackBackUrl, navigateBack]) + + const getCertificateCanvas: () => Promise + = useCertificateCanvas(props.certificateElRef) + + const handleDownload: () => Promise = useCallback(async () => { + + const canvas: HTMLCanvasElement | void = await getCertificateCanvas() + if (!!canvas) { + fileDownloadCanvasAsImage(canvas, `${props.title}.png`) + } + + }, [props.title, getCertificateCanvas]) + + const handlePrint: () => Promise + = useCertificatePrint(props.certificateElRef, props.title ?? '') + + useLayoutEffect(() => { + const el: HTMLElement = wrapElRef.current + if (props.fullScreenCertLayout !== true || !el) { + return + } + + hideSiblings(el) + hideSiblings(el.parentElement as HTMLElement) + el.classList.add(styles['full-screen-cert']) + }) + + return ( + <> + + + {props.isReady && props.isCertificateCompleted && ( +
+
+ {!props.fullScreenCertLayout && ( +
+ } + onClick={handleBackBtnClick} + /> +
+ )} +
+
+ {props.children} +
+
+ {!props.fullScreenCertLayout && ( +
+ } + onClick={handlePrint} + /> + } + onClick={handleDownload} + /> + {props.actions} + + + +
+ )} +
+
+ )} + + ) +} + +export default CertificatePageLayout diff --git a/src-ts/tools/learn/learn-lib/certificate-page-layout/index.ts b/src-ts/tools/learn/learn-lib/certificate-page-layout/index.ts new file mode 100644 index 000000000..85fa4eaa8 --- /dev/null +++ b/src-ts/tools/learn/learn-lib/certificate-page-layout/index.ts @@ -0,0 +1 @@ +export { default as CertificatePageLayout, type CertificatePageLayoutStyle } from './CertificatePageLayout' diff --git a/src-ts/tools/learn/learn-lib/index.ts b/src-ts/tools/learn/learn-lib/index.ts index 809c815e3..f75450f39 100755 --- a/src-ts/tools/learn/learn-lib/index.ts +++ b/src-ts/tools/learn/learn-lib/index.ts @@ -1,4 +1,5 @@ export * from './action-button' +export * from './certificate-page-layout' export * from './collapsible-pane' export * from './completion-time-range' export * from './course-badge' @@ -6,8 +7,8 @@ export * from './course-outline' export * from './course-title' export * from './curriculum-summary' export * from './data-providers' -export * from './functions' export * from './dynamic-icons' +export * from './functions' export * from './learn-breadcrumb-provider' export * from './learn-swr' export * from './providers-logo-list' @@ -16,9 +17,9 @@ export * from './skill' export * from './sticky-sidebar' export * from './svgs' export * from './tca-certificate-preview' +export * from './tca-certification-completed-modal' export * from './tca-certification-progress-box' export * from './use-certificate-canvas-hook' export * from './use-certificate-print-hook' export * from './use-certificate-scaling-hook' -export * from './tca-certification-completed-modal' export * from './wave-hero' diff --git a/src-ts/tools/learn/learn-lib/tca-certificate-preview/TCACertificatePreview.tsx b/src-ts/tools/learn/learn-lib/tca-certificate-preview/TCACertificatePreview.tsx index 57aa24a0a..03e953660 100644 --- a/src-ts/tools/learn/learn-lib/tca-certificate-preview/TCACertificatePreview.tsx +++ b/src-ts/tools/learn/learn-lib/tca-certificate-preview/TCACertificatePreview.tsx @@ -15,7 +15,6 @@ interface TCACertificatePreviewProps { completedDate?: string completionUuid?: string validateLink?: string - viewStyle?: 'large-container' | 'small-container' } const TCACertificatePreview: FC = (props: TCACertificatePreviewProps) => { @@ -28,7 +27,6 @@ const TCACertificatePreview: FC = (props: TCACertifi ) } @@ -43,7 +41,6 @@ const TCACertificatePreview: FC = (props: TCACertifi tcHandle={props.tcHandle ?? ''} userName={props.userName} validateLink={props.validateLink} - viewStyle={props.viewStyle ?? 'large-container'} elRef={props.certificateElRef} /> ) diff --git a/src-ts/tools/learn/learn-lib/tca-certificate-preview/tca-certificate/TCACertificate.module.scss b/src-ts/tools/learn/learn-lib/tca-certificate-preview/tca-certificate/TCACertificate.module.scss index 309049479..8c68ba753 100644 --- a/src-ts/tools/learn/learn-lib/tca-certificate-preview/tca-certificate/TCACertificate.module.scss +++ b/src-ts/tools/learn/learn-lib/tca-certificate-preview/tca-certificate/TCACertificate.module.scss @@ -183,62 +183,6 @@ } } -// Small view styles -:global(.small-container) { - max-width: 420px; - max-height: 335px; - - .details { - padding: $space-xxl; - - .headerWrap { - svg { - max-width: 54px; - max-height: 54px; - } - - .logos { - - svg, - .logosDivider { - max-height: 20px; - } - } - } - - .certWrap { - max-width: 250px; - - .certOwner { - font-size: 20px; - line-height: 20px; - margin-top: $space-xxl; - margin-bottom: $space-sm; - } - - .certTitle { - font-size: 30px; - line-height: 30px; - margin: $space-xs 0 $space-xxl - } - - .certText { - font-size: 9px; - line-height: 9px; - margin-bottom: 0; - } - } - - .certInfo { - .sigWrap { - svg { - max-width: 70px; - } - } - } - } -} - // print/download styles :global(.canvas-clone) { .certText { diff --git a/src-ts/tools/learn/learn-lib/tca-certificate-preview/tca-certificate/TCACertificate.tsx b/src-ts/tools/learn/learn-lib/tca-certificate-preview/tca-certificate/TCACertificate.tsx index b4f08d4b3..ff1d68255 100644 --- a/src-ts/tools/learn/learn-lib/tca-certificate-preview/tca-certificate/TCACertificate.tsx +++ b/src-ts/tools/learn/learn-lib/tca-certificate-preview/tca-certificate/TCACertificate.tsx @@ -21,7 +21,6 @@ interface TCACertificateProps { tcHandle?: string userName?: string validateLink?: string - viewStyle?: 'large-container' | 'small-container' } const TCACertificate: FC = (props: TCACertificateProps) => { @@ -45,7 +44,7 @@ const TCACertificate: FC = (props: TCACertificateProps) => return (
diff --git a/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.module.scss b/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.module.scss deleted file mode 100644 index 03b547373..000000000 --- a/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.module.scss +++ /dev/null @@ -1,80 +0,0 @@ -@import '../../../../lib/styles/includes'; - -.wrap { - padding-top: $space-xxxxl; - padding-bottom: calc($space-xxxxl + $space-xs); - flex: 99 1 auto; - display: flex; - - background: $tc-grad15; -} - -.content-wrap { - display: flex; - @include pagePaddings; - margin: auto; - width: 100%; - justify-content: center; - - gap: $space-xxxxl; - - @include ltemd { - flex-direction: column; - margin: 0 auto auto; - } -} - -.btns-wrap { - display: flex; - flex-direction: column; - align-items: center; - - gap: $space-sm; - - &:last-child { - margin-top: auto; - } - - @include ltemd { - flex-direction: row; - &:last-child { - justify-content: center; - } - } -} - -.certificate-wrap { - width: 880px; - background: #fff; - box-shadow: 0 20px 36px rgba($tc-black, 0.22); - - &:global(.large-container) { - @include socialPreviewImg; - } - - @include ltemd { - width: 100%; - } -} - -.share-btn:global(.button.icon) { - @include icon-mxx; - border-radius: 50%; - - color: $tc-white; - border: $border solid $tc-white; - - display: flex; - align-items: center; - justify-content: center; - - padding: $space-sm; - - &:hover { - background: transparent; - } - - svg { - @include icon-xxl; - } -} diff --git a/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.tsx b/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.tsx index e03b33068..a0c0757ad 100644 --- a/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.tsx +++ b/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.tsx @@ -1,45 +1,31 @@ import { FC, MutableRefObject, useCallback, useEffect, useMemo, useRef } from 'react' -import classNames from 'classnames' import { - FacebookSocialShareBtn, - fileDownloadCanvasAsImage, IconOutline, - LinkedinSocialShareBtn, LoadingSpinner, - NavigateBackFunction, - TwitterSocialShareBtn, - useNavigateBack, UserProfile, } from '../../../../lib' import { ActionButton, + CertificatePageLayout, TCACertificatePreview, TCACertification, TCACertificationValidationData, - useCertificateCanvas, - useCertificatePrint, useGetUserTCACompletedCertificationsMOCK, UserCompletedTCACertificationsProviderData, useValidateTCACertification, } from '../../learn-lib' import { getTCACertificationPath, getTCACertificationValidationUrl, getUserTCACertificateSsr } from '../../learn.routes' -import styles from './CertificateView.module.scss' - -export type CertificateViewStyle = 'large-container' | undefined - interface CertificateViewProps { certification: string, - hideActions?: boolean, + fullScreenCertLayout?: boolean, onCertificationNotCompleted: () => void profile: UserProfile, - viewStyle: CertificateViewStyle } const CertificateView: FC = (props: CertificateViewProps) => { - const navigateBack: NavigateBackFunction = useNavigateBack() const tcaCertificationPath: string = getTCACertificationPath(props.certification) const certificateElRef: MutableRefObject = useRef() @@ -76,26 +62,6 @@ const CertificateView: FC = (props: CertificateViewProps) completedCertificateReady && certReady ), [completedCertificateReady, certReady]) - const readyAndCompletedCertification: boolean = useMemo(() => ( - ready && hasCompletedTheCertification - ), [hasCompletedTheCertification, ready]) - - const handleBackBtnClick: () => void = useCallback(() => { - navigateBack(tcaCertificationPath) - }, [tcaCertificationPath, navigateBack]) - - const getCertificateCanvas: () => Promise = useCertificateCanvas(certificateElRef) - - const handleDownload: () => Promise = useCallback(async () => { - - const canvas: HTMLCanvasElement | void = await getCertificateCanvas() - if (!!canvas) { - fileDownloadCanvasAsImage(canvas, `${certificationTitle}.png`) - } - - }, [certificationTitle, getCertificateCanvas]) - - const handlePrint: () => Promise = useCertificatePrint(certificateElRef, certificationTitle) const validateLink: string = getTCACertificationValidationUrl(enrollment?.completionUuid as string) @@ -113,60 +79,31 @@ const CertificateView: FC = (props: CertificateViewProps) <> - {ready && readyAndCompletedCertification && ( -
-
- {!props.hideActions && ( -
- } - onClick={handleBackBtnClick} - /> -
- )} -
- -
- {!props.hideActions && ( -
- } - onClick={handlePrint} - /> - } - onClick={handleDownload} - /> - } - onClick={handleLinkClick} - /> - - - -
- )} -
-
- )} + } + onClick={handleLinkClick} + /> + )} + > + + ) } diff --git a/src-ts/tools/learn/tca-certificate/my-certificate/MyTCACertificate.tsx b/src-ts/tools/learn/tca-certificate/my-certificate/MyTCACertificate.tsx index 268bb1095..418883c66 100644 --- a/src-ts/tools/learn/tca-certificate/my-certificate/MyTCACertificate.tsx +++ b/src-ts/tools/learn/tca-certificate/my-certificate/MyTCACertificate.tsx @@ -1,18 +1,17 @@ import { FC, useCallback, useContext, useEffect } from 'react' -import { NavigateFunction, Params, useNavigate, useParams, useSearchParams } from 'react-router-dom' +import { NavigateFunction, Params, useNavigate, useParams } from 'react-router-dom' import { LoadingSpinner, profileContext, ProfileContextData, } from '../../../../lib' -import { getTCACertificationPath, getViewStyleParamKey } from '../../learn.routes' -import CertificateView, { CertificateViewStyle } from '../certificate-view/CertificateView' +import { getTCACertificationPath } from '../../learn.routes' +import CertificateView from '../certificate-view/CertificateView' const MyTCACertificate: FC<{}> = () => { const routeParams: Params = useParams() const { profile, initialized: profileReady }: ProfileContextData = useContext(profileContext) - const [queryParams]: [URLSearchParams, any] = useSearchParams() const navigate: NavigateFunction = useNavigate() const certificationParam: string = routeParams.certification ?? '' @@ -37,7 +36,6 @@ const MyTCACertificate: FC<{}> = () => { certification={certificationParam} profile={profile} onCertificationNotCompleted={navigateToCertification} - viewStyle={queryParams.get(getViewStyleParamKey()) as CertificateViewStyle} /> )} diff --git a/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.module.scss b/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.module.scss deleted file mode 100644 index 06821e91a..000000000 --- a/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -.full-screen-cert { - flex: 1 1 auto; - display: flex; - flex-direction: column; -} \ No newline at end of file diff --git a/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.tsx b/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.tsx index d2c720b89..444766a12 100644 --- a/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.tsx +++ b/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.tsx @@ -1,22 +1,25 @@ -import { Dispatch, FC, MutableRefObject, SetStateAction, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react' -import { NavigateFunction, Params, useNavigate, useParams, useSearchParams } from 'react-router-dom' +import { + Dispatch, + FC, + SetStateAction, + useCallback, + useEffect, + useState, +} from 'react' +import { NavigateFunction, Params, useNavigate, useParams } from 'react-router-dom' import { LoadingSpinner, profileGetPublicAsync, UserProfile, } from '../../../../lib' -import { getTCACertificationPath, getViewStyleParamKey } from '../../learn.routes' -import { CertificateView, CertificateViewStyle } from '../certificate-view' - -import styles from './UserTCACertificate.module.scss' +import { getTCACertificationPath } from '../../learn.routes' +import { CertificateView } from '../certificate-view' const UserTCACertificate: FC<{}> = () => { const navigate: NavigateFunction = useNavigate() - const wrapElRef: MutableRefObject = useRef() const routeParams: Params = useParams() - const [queryParams]: [URLSearchParams, any] = useSearchParams() const [profile, setProfile]: [ UserProfile | undefined, @@ -27,14 +30,6 @@ const UserTCACertificate: FC<{}> = () => { const certificationParam: string = routeParams.certification ?? '' const tcaCertificationPath: string = getTCACertificationPath(certificationParam) - function hideSiblings(el: HTMLElement): void { - [].forEach.call(el.parentElement?.children ?? [], (c: HTMLElement) => { - if (c !== el) { - Object.assign(c.style, { display: 'none' }) - } - }) - } - useEffect(() => { if (routeParams.memberHandle) { profileGetPublicAsync(routeParams.memberHandle) @@ -45,17 +40,6 @@ const UserTCACertificate: FC<{}> = () => { } }, [routeParams.memberHandle, setProfileReady]) - useLayoutEffect(() => { - const el: HTMLElement = wrapElRef.current - if (!el) { - return - } - - hideSiblings(el) - hideSiblings(el.parentElement as HTMLElement) - el.classList.add(styles['full-screen-cert']) - }) - const navigateToCertification: () => void = useCallback(() => { navigate(tcaCertificationPath) }, [tcaCertificationPath, navigate]) @@ -65,15 +49,12 @@ const UserTCACertificate: FC<{}> = () => { {profileReady && profile && ( -
- -
+ )} ) From 1dacb5e24477772aca0b5472c466ddb7e75a6164 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Mon, 27 Feb 2023 11:57:27 +0200 Subject: [PATCH 2/2] TCA-996 - implement certificate not found error pages for tca certifications and FCC courses --- src-ts/lib/styles/variables/_constants.scss | 2 +- src-ts/lib/svgs/index.ts | 2 + src-ts/lib/svgs/tc-academy-logo-mixed.svg | 24 +++++ .../CertificateNotFound.module.scss | 91 +++++++++++++++++ .../CertificateNotFound.tsx | 37 +++++++ .../certificate-not-found/bg.svg | 38 +++++++ .../certificate-not-found/index.ts | 1 + .../certificate-view/CertificateView.tsx | 41 +++++--- .../certificate/Certificate.module.scss | 1 + .../my-certificate/MyCertificate.tsx | 1 - .../user-certificate/UserCertificate.tsx | 1 - .../action-button/ActionButton.module.scss | 4 + .../CertificateNotFoundContent.module.scss | 43 ++++++++ .../CertificateNotFoundContent.tsx | 41 ++++++++ .../certificate-not-found-content/index.ts | 1 + .../CertificatePageLayout.module.scss | 36 ++++++- .../CertificatePageLayout.tsx | 17 +++- .../learn/learn-lib/data-providers/index.ts | 1 - .../tca-validation-provider.tsx | 4 +- .../index.ts | 3 - .../user-completed-tca-certification.model.ts | 5 - ...-tca-certifications-provider-data.model.ts | 7 -- ...-completed-tca-certifications.provider.tsx | 48 --------- src-ts/tools/learn/learn-lib/index.ts | 1 + .../CertificateNotFound.module.scss | 98 +++++++++++++++++++ .../CertificateNotFound.tsx | 42 ++++++++ .../certificate-not-found/badge.svg | 10 ++ .../certificate-not-found/bg.svg | 7 ++ .../certificate-not-found/index.ts | 1 + .../certificate-view/CertificateView.tsx | 64 ++++++------ .../my-certificate/MyTCACertificate.tsx | 1 - .../user-certificate/UserTCACertificate.tsx | 11 +-- 32 files changed, 551 insertions(+), 133 deletions(-) create mode 100644 src-ts/lib/svgs/tc-academy-logo-mixed.svg create mode 100644 src-ts/tools/learn/course-certificate/certificate-not-found/CertificateNotFound.module.scss create mode 100644 src-ts/tools/learn/course-certificate/certificate-not-found/CertificateNotFound.tsx create mode 100644 src-ts/tools/learn/course-certificate/certificate-not-found/bg.svg create mode 100644 src-ts/tools/learn/course-certificate/certificate-not-found/index.ts create mode 100644 src-ts/tools/learn/learn-lib/certificate-not-found-content/CertificateNotFoundContent.module.scss create mode 100644 src-ts/tools/learn/learn-lib/certificate-not-found-content/CertificateNotFoundContent.tsx create mode 100644 src-ts/tools/learn/learn-lib/certificate-not-found-content/index.ts delete mode 100644 src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/index.ts delete mode 100644 src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certification.model.ts delete mode 100644 src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certifications-provider-data.model.ts delete mode 100644 src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certifications.provider.tsx create mode 100644 src-ts/tools/learn/tca-certificate/certificate-not-found/CertificateNotFound.module.scss create mode 100644 src-ts/tools/learn/tca-certificate/certificate-not-found/CertificateNotFound.tsx create mode 100644 src-ts/tools/learn/tca-certificate/certificate-not-found/badge.svg create mode 100644 src-ts/tools/learn/tca-certificate/certificate-not-found/bg.svg create mode 100644 src-ts/tools/learn/tca-certificate/certificate-not-found/index.ts diff --git a/src-ts/lib/styles/variables/_constants.scss b/src-ts/lib/styles/variables/_constants.scss index 2290e4e3f..3ef3f8739 100644 --- a/src-ts/lib/styles/variables/_constants.scss +++ b/src-ts/lib/styles/variables/_constants.scss @@ -1 +1 @@ -$tca-certif-aspect-ratio: 1.25715; +$tca-certif-aspect-ratio: 1.2571; diff --git a/src-ts/lib/svgs/index.ts b/src-ts/lib/svgs/index.ts index 6d45cf3d4..7d4738adb 100644 --- a/src-ts/lib/svgs/index.ts +++ b/src-ts/lib/svgs/index.ts @@ -21,6 +21,7 @@ import { ReactComponent as SocialIconYoutube } from './social-yt-icon.svg' import { ReactComponent as TooltipArrowIcon } from './tooltip-arrow.svg' import { ReactComponent as TcAcademyLogoSvg } from './tc-academy-logo.svg' import { ReactComponent as TCAcademyLogoWhiteSvg } from './tc-academy-logo-white.svg' +import { ReactComponent as TCAcademyLogoMixedSvg } from './tc-academy-logo-mixed.svg' import { ReactComponent as TcLogoSvg } from './tc-logo.svg' import { ReactComponent as TCLogoSvg } from './tc-logo-white.svg' import { ReactComponent as FccLogoSvg } from './vendor-fcc-logo.svg' @@ -49,6 +50,7 @@ export { IconCheck, TcAcademyLogoSvg, TCAcademyLogoWhiteSvg, + TCAcademyLogoMixedSvg, TcLogoSvg, TCLogoSvg, FccLogoSvg, diff --git a/src-ts/lib/svgs/tc-academy-logo-mixed.svg b/src-ts/lib/svgs/tc-academy-logo-mixed.svg new file mode 100644 index 000000000..261b103e7 --- /dev/null +++ b/src-ts/lib/svgs/tc-academy-logo-mixed.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-ts/tools/learn/course-certificate/certificate-not-found/CertificateNotFound.module.scss b/src-ts/tools/learn/course-certificate/certificate-not-found/CertificateNotFound.module.scss new file mode 100644 index 000000000..c06d33f00 --- /dev/null +++ b/src-ts/tools/learn/course-certificate/certificate-not-found/CertificateNotFound.module.scss @@ -0,0 +1,91 @@ +@import '../../../../lib/styles/includes'; + +.wrap { + display: flex; + height: 100%; + z-index: 1; + overflow: hidden; + + @include ltemd { + border: 1px dashed $blue-25; + border-radius: 8px; + } + > svg { + position: absolute; + top: 50%; + left: 0; + width: 100%; + height: auto; + display: block; + z-index: -1; + transform: translateY(-50%); + + @include ltemd { + :global(.rect-border) { + display: none; + } + } + } +} + +.details { + width: 55%; + padding: calc($space-mx + $space-lg); + display: flex; + flex-direction: column; + flex: 1; + + &Inner { + max-width: 385px; + flex: 1; + display: flex; + flex-direction: column; + } + + h2 { + color: $blue-25; + } + + h3 { + font-size: 48px; + line-height: 50px; + font-weight: 500; + color: $tc-white; + margin-top: $space-sm; + + :global(.nw) { + white-space: nowrap; + } + } +} + +.logos { + margin-top: auto; + display: flex; +} + +.logo { + display: flex; + align-items: center; + height: 52px; + + svg { + width: auto; + + } + &.whiteLogo svg > path { + fill: $tc-white; + } +} + +.divider { + width: $border; + background: $black-10; + margin: 0 $space-lg; + flex: 0 0 auto; +} + +.rightSide { + width: 45%; + +} diff --git a/src-ts/tools/learn/course-certificate/certificate-not-found/CertificateNotFound.tsx b/src-ts/tools/learn/course-certificate/certificate-not-found/CertificateNotFound.tsx new file mode 100644 index 000000000..8bf2a1a89 --- /dev/null +++ b/src-ts/tools/learn/course-certificate/certificate-not-found/CertificateNotFound.tsx @@ -0,0 +1,37 @@ +import { FC } from 'react' +import classNames from 'classnames' + +import { TCAcademyLogoMixedSvg, TcLogoSvg } from '../../../../lib' +import { CertificateNotFoundContent } from '../../learn-lib' + +import { ReactComponent as BackgroundSvg } from './bg.svg' +import styles from './CertificateNotFound.module.scss' + +const CertificateNotFound: FC<{}> = () => ( +
+ +
+
+

Topcoder Academy

+

+ Certificate + {' '} + not found +

+ +
+
+ +
+
+
+ +
+
+
+
+
+
+) + +export default CertificateNotFound diff --git a/src-ts/tools/learn/course-certificate/certificate-not-found/bg.svg b/src-ts/tools/learn/course-certificate/certificate-not-found/bg.svg new file mode 100644 index 000000000..58bebe31b --- /dev/null +++ b/src-ts/tools/learn/course-certificate/certificate-not-found/bg.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-ts/tools/learn/course-certificate/certificate-not-found/index.ts b/src-ts/tools/learn/course-certificate/certificate-not-found/index.ts new file mode 100644 index 000000000..a3ba843a9 --- /dev/null +++ b/src-ts/tools/learn/course-certificate/certificate-not-found/index.ts @@ -0,0 +1 @@ +export { default as CertificateNotFound } from './CertificateNotFound' diff --git a/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx b/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx index 05b9a8698..5f4c555be 100644 --- a/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx +++ b/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx @@ -1,13 +1,14 @@ import { FC, MutableRefObject, - useEffect, + ReactNode, useMemo, useRef, } from 'react' import { AllCertificationsProviderData, + CertificateNotFoundContent, CertificatePageLayout, CoursesProviderData, useGetCertification, @@ -20,13 +21,13 @@ import { getUserCertificateSsr, } from '../../learn.routes' import { UserProfile } from '../../../../lib' +import { CertificateNotFound } from '../certificate-not-found' import Certificate from './certificate/Certificate' interface CertificateViewProps { certification: string fullScreenCertLayout?: boolean - onCertificationNotCompleted: () => void profile: UserProfile provider: string } @@ -81,23 +82,14 @@ const CertificateView: FC = (props: CertificateViewProps) const ready: boolean = useMemo(() => ( completedCertificateReady && courseReady && certificateReady ), [certificateReady, completedCertificateReady, courseReady]) + const certificateNotFoundError: boolean = ready && !hasCompletedTheCertification - useEffect(() => { + function renderCertificate(): ReactNode { if (ready && !hasCompletedTheCertification) { - props.onCertificationNotCompleted() + return } - }, [coursePath, hasCompletedTheCertification, props, ready]) - return ( - + return ( = (props: CertificateViewProps) type={certificate?.certificationCategory.track} userName={userName} /> + ) + } + + return ( + + )} + > + {renderCertificate()} ) } diff --git a/src-ts/tools/learn/course-certificate/certificate-view/certificate/Certificate.module.scss b/src-ts/tools/learn/course-certificate/certificate-view/certificate/Certificate.module.scss index 9ddde408e..fc8f51baa 100644 --- a/src-ts/tools/learn/course-certificate/certificate-view/certificate/Certificate.module.scss +++ b/src-ts/tools/learn/course-certificate/certificate-view/certificate/Certificate.module.scss @@ -3,6 +3,7 @@ .wrap { display: flex; height: 100%; + background: $tc-white; } .details { diff --git a/src-ts/tools/learn/course-certificate/my-certificate/MyCertificate.tsx b/src-ts/tools/learn/course-certificate/my-certificate/MyCertificate.tsx index c9d20a18c..644d414bf 100644 --- a/src-ts/tools/learn/course-certificate/my-certificate/MyCertificate.tsx +++ b/src-ts/tools/learn/course-certificate/my-certificate/MyCertificate.tsx @@ -37,7 +37,6 @@ const MyCertificate: FC<{}> = () => { certification={certificationParam} profile={profile} provider={providerParam} - onCertificationNotCompleted={navigateToCourse} /> )} diff --git a/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.tsx b/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.tsx index 41ff34798..7218dc738 100644 --- a/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.tsx +++ b/src-ts/tools/learn/course-certificate/user-certificate/UserCertificate.tsx @@ -40,7 +40,6 @@ const UserCertificate: FC<{}> = () => { certification={certificationParam} profile={profile} provider={providerParam} - onCertificationNotCompleted={() => { }} fullScreenCertLayout /> )} diff --git a/src-ts/tools/learn/learn-lib/action-button/ActionButton.module.scss b/src-ts/tools/learn/learn-lib/action-button/ActionButton.module.scss index 311d9cffb..20e3ebc3d 100644 --- a/src-ts/tools/learn/learn-lib/action-button/ActionButton.module.scss +++ b/src-ts/tools/learn/learn-lib/action-button/ActionButton.module.scss @@ -18,4 +18,8 @@ svg { @include icon-xxl; } + + @include ltemd { + @include icon-mx; + } } diff --git a/src-ts/tools/learn/learn-lib/certificate-not-found-content/CertificateNotFoundContent.module.scss b/src-ts/tools/learn/learn-lib/certificate-not-found-content/CertificateNotFoundContent.module.scss new file mode 100644 index 000000000..0313f758a --- /dev/null +++ b/src-ts/tools/learn/learn-lib/certificate-not-found-content/CertificateNotFoundContent.module.scss @@ -0,0 +1,43 @@ +@import '../../../../lib/styles/includes'; + +.content { + color: $blue-25; + margin-top: $space-lg; + + @include ltemd { + padding-left: $space-xxl; + padding-right: $space-xxl; + } + + @include ltesm { + padding-left: $space-lg; + padding-right: $space-lg; + } + + p, ol, li { + margin-top: $space-lg; + } + ol { + list-style: decimal; + padding-left: 16px; + } + + ol li a { + display: flex; + align-items: center; + gap: $space-xs; + font-family: $font-roboto; + font-weight: bold; + font-size: 14px; + line-height: 14px; + letter-spacing: 0.03em; + text-transform: uppercase; + color: $tc-white; + margin-top: $space-sm; + svg { + display: block; + width: 14px; + height: 14px; + } + } +} diff --git a/src-ts/tools/learn/learn-lib/certificate-not-found-content/CertificateNotFoundContent.tsx b/src-ts/tools/learn/learn-lib/certificate-not-found-content/CertificateNotFoundContent.tsx new file mode 100644 index 000000000..984be99fb --- /dev/null +++ b/src-ts/tools/learn/learn-lib/certificate-not-found-content/CertificateNotFoundContent.tsx @@ -0,0 +1,41 @@ +import { FC } from 'react' +import classNames from 'classnames' + +import { IconSolid } from '../../../../lib' + +import styles from './CertificateNotFoundContent.module.scss' + +interface CertificateNotFoundContentProps { + className?: string +} + +const CertificateNotFoundContent: FC = (props: CertificateNotFoundContentProps) => ( +
+

+ Hey there! +

+

+ Looks like we don’t have your certificate. + Have you completed the course? If not, keep going at it! If you have: +

+
    +
  1. + Try again in 60 seconds. We might still be generating your certification! +
  2. +
  3. + If you already waited, contact our support team. + Please reference Topcoder Academy and the course you completed. + + + Contact support + + +
  4. +
+

+ Keep Learning away! +

+
+) + +export default CertificateNotFoundContent diff --git a/src-ts/tools/learn/learn-lib/certificate-not-found-content/index.ts b/src-ts/tools/learn/learn-lib/certificate-not-found-content/index.ts new file mode 100644 index 000000000..ce26ba074 --- /dev/null +++ b/src-ts/tools/learn/learn-lib/certificate-not-found-content/index.ts @@ -0,0 +1 @@ +export { default as CertificateNotFoundContent } from './CertificateNotFoundContent' diff --git a/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.module.scss b/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.module.scss index 731865916..9f10896a6 100644 --- a/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.module.scss +++ b/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.module.scss @@ -21,6 +21,7 @@ @include ltemd { flex-direction: column; margin: 0 auto auto; + gap: $space-xxl; } } @@ -38,9 +39,14 @@ @include ltemd { flex-direction: row; &:last-child { - justify-content: center; + justify-content: space-between; } } + + &.disabled { + opacity: 0.3; + pointer-events: none; + } } .certificate-wrap { @@ -67,9 +73,12 @@ width: 880px; aspect-ratio: $tca-certif-aspect-ratio; - background: #fff; box-shadow: 0 20px 36px rgba($tc-black, 0.22); + .wrap:global(.cert-not-found-layout) & { + box-shadow: none; + } + > * { position: absolute; top: 0; @@ -103,4 +112,27 @@ svg { @include icon-xxl; } + + @include ltemd { + @include icon-mx; + } +} + +// Certificate not found layout +.wrap:global(.cert-not-found-layout) { + @include ltemd { + flex-direction: column; + + .certificate-wrap, .certifInnerWrap { + aspect-ratio: 2.09146; + } + + .content-wrap { + margin-bottom: 0; + } + } + + .certifInnerWrap { + box-shadow: none; + } } diff --git a/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.tsx b/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.tsx index 4e92c4b8c..d01a2bc1a 100644 --- a/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.tsx +++ b/src-ts/tools/learn/learn-lib/certificate-page-layout/CertificatePageLayout.tsx @@ -34,6 +34,9 @@ interface CertificatePageLayoutProps { actions?: ReactNode certificateElRef: MutableRefObject children?: ReactNode + afterContent?: ReactNode + className?: string + disableActions?: boolean fallbackBackUrl?: string fullScreenCertLayout?: boolean isCertificateCompleted?: boolean @@ -86,8 +89,8 @@ const CertificatePageLayout: FC = (props: Certificat <> - {props.isReady && props.isCertificateCompleted && ( -
+ {props.isReady && ( +
{!props.fullScreenCertLayout && (
@@ -106,7 +109,14 @@ const CertificatePageLayout: FC = (props: Certificat
{!props.fullScreenCertLayout && ( -
+
} onClick={handlePrint} @@ -131,6 +141,7 @@ const CertificatePageLayout: FC = (props: Certificat
)}
+ {props.afterContent}
)} diff --git a/src-ts/tools/learn/learn-lib/data-providers/index.ts b/src-ts/tools/learn/learn-lib/data-providers/index.ts index 1e892d208..0d0093e10 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/index.ts +++ b/src-ts/tools/learn/learn-lib/data-providers/index.ts @@ -4,5 +4,4 @@ export * from './lesson-provider' export * from './resource-provider-provider' export * from './user-certifications-provider' export * from './user-completed-certifications-provider' -export * from './user-completed-tca-certifications-provider' export * from './tca-certifications-provider' diff --git a/src-ts/tools/learn/learn-lib/data-providers/tca-certifications-provider/tca-certification-validation/tca-validation-provider.tsx b/src-ts/tools/learn/learn-lib/data-providers/tca-certifications-provider/tca-certification-validation/tca-validation-provider.tsx index abbd3d69a..c983582a1 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/tca-certifications-provider/tca-certification-validation/tca-validation-provider.tsx +++ b/src-ts/tools/learn/learn-lib/data-providers/tca-certifications-provider/tca-certification-validation/tca-validation-provider.tsx @@ -9,6 +9,7 @@ export interface TCACertificationValidationData { certification: TCACertification | undefined enrollment: TCACertificationEnrollmentBase | undefined error: boolean + loading: boolean ready: boolean } @@ -34,6 +35,7 @@ export function useValidateTCACertification( certification: data?.certification, enrollment: data?.enrollment, error: !!error, - ready: !!data, + loading: !(data || error), + ready: !!(data || error), } } diff --git a/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/index.ts b/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/index.ts deleted file mode 100644 index 40bf84940..000000000 --- a/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './user-completed-tca-certifications-provider-data.model' -export * from './user-completed-tca-certifications.provider' -export * from './user-completed-tca-certification.model' diff --git a/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certification.model.ts b/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certification.model.ts deleted file mode 100644 index 2e420ed42..000000000 --- a/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certification.model.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface UserCompletedTCACertification { - status: string - completedDate: string - trackType: string -} diff --git a/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certifications-provider-data.model.ts b/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certifications-provider-data.model.ts deleted file mode 100644 index 925715b33..000000000 --- a/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certifications-provider-data.model.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { UserCompletedTCACertification } from './user-completed-tca-certification.model' - -export interface UserCompletedTCACertificationsProviderData { - certifications: ReadonlyArray - loading: boolean - ready: boolean -} diff --git a/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certifications.provider.tsx b/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certifications.provider.tsx deleted file mode 100644 index a7f5b6f6c..000000000 --- a/src-ts/tools/learn/learn-lib/data-providers/user-completed-tca-certifications-provider/user-completed-tca-certifications.provider.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import useSWR, { SWRResponse } from 'swr' - -import { learnUrlGet } from '../../functions' - -import { UserCompletedTCACertification } from './user-completed-tca-certification.model' -import { UserCompletedTCACertificationsProviderData } from './user-completed-tca-certifications-provider-data.model' - -const COMPLETED_CERTS_MOCK = [ - { status: 'comleted', trackType: 'web dev', completedDate: 'Dec 19, 2022' }, -] - -export function useGetUserTCACompletedCertifications( - userId?: number, - certification?: string, -): UserCompletedTCACertificationsProviderData { - - // TODO: update to actual API endpoint URL when ready - const url: string = learnUrlGet('completed-certifications', `${userId}`) - - const { data, error }: SWRResponse> = useSWR(url) - - let certifications: ReadonlyArray = data ?? [] - - if (certification) { - certifications = certifications - .filter(c => (!certification || c.certification === certification)) - } - - return { - certifications, - loading: !data && !error, - ready: !!data || !!error, - } -} - -// TODO: remove when API ready -export function useGetUserTCACompletedCertificationsMOCK( - userId?: number, - certification?: string, -): UserCompletedTCACertificationsProviderData { - const data = COMPLETED_CERTS_MOCK - - return { - certifications: data, - loading: !data, - ready: !!data, - } -} diff --git a/src-ts/tools/learn/learn-lib/index.ts b/src-ts/tools/learn/learn-lib/index.ts index f75450f39..53bdd29e4 100755 --- a/src-ts/tools/learn/learn-lib/index.ts +++ b/src-ts/tools/learn/learn-lib/index.ts @@ -1,4 +1,5 @@ export * from './action-button' +export * from './certificate-not-found-content' export * from './certificate-page-layout' export * from './collapsible-pane' export * from './completion-time-range' diff --git a/src-ts/tools/learn/tca-certificate/certificate-not-found/CertificateNotFound.module.scss b/src-ts/tools/learn/tca-certificate/certificate-not-found/CertificateNotFound.module.scss new file mode 100644 index 000000000..6ea504f69 --- /dev/null +++ b/src-ts/tools/learn/tca-certificate/certificate-not-found/CertificateNotFound.module.scss @@ -0,0 +1,98 @@ +@import '../../../../lib/styles/includes'; + +.wrap { + display: flex; + height: 100%; + z-index: 1; + overflow: hidden; + + @include ltemd { + border: 2px dashed $blue-25; + border-radius: $space-sm; + } + + > svg { + position: absolute; + top: 50%; + left: 0; + width: 100%; + height: auto; + display: block; + z-index: -1; + transform: translateY(-50%); + @include ltemd { + display: none; + } + } +} + +.details { + width: 55%; + padding: calc($space-mx + $space-lg); + display: flex; + flex-direction: column; + flex: 1; + + @include ltemd { + flex-direction: row; + } +} + +.headerWrap { + display: flex; + justify-content: space-between; + align-items: flex-start; + + >svg { + width: 120px; + height: 120px; + } + +} + +.logos { + display: flex; + + &Divider { + width: 2px; + height: 40px; + background-color: $tc-white; + opacity: 0.3; + margin: 0 $space-lg; + } +} + +.contentWrap { + max-width: 528px; + margin-top: $space-mx; + + @include ltemd { + display: flex; + flex-direction: column; + > *:last-child { + margin-top: auto; + } + } + + h2 { + color: $blue-25; + } + + h3 { + font-size: 48px; + line-height: 50px; + font-weight: 500; + color: $tc-white; + margin-top: $space-sm; + } +} + +.mobileBadge { + margin: auto; + margin-right: 0; + width: 30%; + height: auto; + @include gtelg { + display: none; + } +} diff --git a/src-ts/tools/learn/tca-certificate/certificate-not-found/CertificateNotFound.tsx b/src-ts/tools/learn/tca-certificate/certificate-not-found/CertificateNotFound.tsx new file mode 100644 index 000000000..b81b12832 --- /dev/null +++ b/src-ts/tools/learn/tca-certificate/certificate-not-found/CertificateNotFound.tsx @@ -0,0 +1,42 @@ +import { FC } from 'react' +import classNames from 'classnames' + +import { TCAcademyLogoWhiteSvg, TCLogoSvg } from '../../../../lib' +import { CertificateNotFoundContent } from '../../learn-lib' + +import { ReactComponent as BackgroundSvg } from './bg.svg' +import { ReactComponent as BadgeSvg } from './badge.svg' +import styles from './CertificateNotFound.module.scss' + +const CertificateNotFound: FC<{}> = () => ( +
+ +
+
+ +
+ +
+ +
+
+
+

Topcoder Academy

+

+ Certificate +
+ not found +

+ +
+ +
+ +
+
+ +
+
+) + +export default CertificateNotFound diff --git a/src-ts/tools/learn/tca-certificate/certificate-not-found/badge.svg b/src-ts/tools/learn/tca-certificate/certificate-not-found/badge.svg new file mode 100644 index 000000000..dadd53da9 --- /dev/null +++ b/src-ts/tools/learn/tca-certificate/certificate-not-found/badge.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src-ts/tools/learn/tca-certificate/certificate-not-found/bg.svg b/src-ts/tools/learn/tca-certificate/certificate-not-found/bg.svg new file mode 100644 index 000000000..30377b41b --- /dev/null +++ b/src-ts/tools/learn/tca-certificate/certificate-not-found/bg.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src-ts/tools/learn/tca-certificate/certificate-not-found/index.ts b/src-ts/tools/learn/tca-certificate/certificate-not-found/index.ts new file mode 100644 index 000000000..a3ba843a9 --- /dev/null +++ b/src-ts/tools/learn/tca-certificate/certificate-not-found/index.ts @@ -0,0 +1 @@ +export { default as CertificateNotFound } from './CertificateNotFound' diff --git a/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.tsx b/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.tsx index a0c0757ad..1d638a8d8 100644 --- a/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.tsx +++ b/src-ts/tools/learn/tca-certificate/certificate-view/CertificateView.tsx @@ -1,4 +1,4 @@ -import { FC, MutableRefObject, useCallback, useEffect, useMemo, useRef } from 'react' +import { FC, MutableRefObject, ReactNode, useCallback, useRef } from 'react' import { IconOutline, @@ -7,20 +7,19 @@ import { } from '../../../../lib' import { ActionButton, + CertificateNotFoundContent, CertificatePageLayout, TCACertificatePreview, TCACertification, TCACertificationValidationData, - useGetUserTCACompletedCertificationsMOCK, - UserCompletedTCACertificationsProviderData, useValidateTCACertification, } from '../../learn-lib' import { getTCACertificationPath, getTCACertificationValidationUrl, getUserTCACertificateSsr } from '../../learn.routes' +import { CertificateNotFound } from '../certificate-not-found' interface CertificateViewProps { certification: string, fullScreenCertLayout?: boolean, - onCertificationNotCompleted: () => void profile: UserProfile, } @@ -32,10 +31,14 @@ const CertificateView: FC = (props: CertificateViewProps) const { certification, enrollment, - ready: certReady, + error: hasValidationError, + ready, }: TCACertificationValidationData = useValidateTCACertification(props.certification, props.profile.handle) + const hasCompletedTheCertification: boolean = !!certification && !!enrollment && !hasValidationError + const certificateNotFoundError: boolean = ready && !hasCompletedTheCertification + function getCertTitle(user: string): string { return `${user} - ${certification?.title}` } @@ -48,32 +51,29 @@ const CertificateView: FC = (props: CertificateViewProps) const certificationTitle: string = getCertTitle(enrollment?.userName || props.profile.handle) - const { - certifications: [completedCertificate], - ready: completedCertificateReady, - }: UserCompletedTCACertificationsProviderData = useGetUserTCACompletedCertificationsMOCK( - props.profile.userId, - props.certification, - ) - - const hasCompletedTheCertification: boolean = !!completedCertificate - - const ready: boolean = useMemo(() => ( - completedCertificateReady && certReady - ), [completedCertificateReady, certReady]) - - const validateLink: string = getTCACertificationValidationUrl(enrollment?.completionUuid as string) const handleLinkClick: () => void = useCallback(() => { window.open(validateLink, 'blank') }, [validateLink]) - useEffect(() => { - if (ready && !hasCompletedTheCertification) { - props.onCertificationNotCompleted() + function renderCertificate(): ReactNode { + if (certificateNotFoundError) { + return } - }, [tcaCertificationPath, hasCompletedTheCertification, props, ready]) + + return ( + + ) + } return ( <> @@ -82,7 +82,7 @@ const CertificateView: FC = (props: CertificateViewProps) = (props: CertificateViewProps) onClick={handleLinkClick} /> )} + className={certificateNotFoundError ? 'cert-not-found-layout' : ''} + afterContent={certificateNotFoundError && ( + + )} > - + {renderCertificate()} ) diff --git a/src-ts/tools/learn/tca-certificate/my-certificate/MyTCACertificate.tsx b/src-ts/tools/learn/tca-certificate/my-certificate/MyTCACertificate.tsx index 418883c66..b7bdfeec9 100644 --- a/src-ts/tools/learn/tca-certificate/my-certificate/MyTCACertificate.tsx +++ b/src-ts/tools/learn/tca-certificate/my-certificate/MyTCACertificate.tsx @@ -35,7 +35,6 @@ const MyTCACertificate: FC<{}> = () => { )} diff --git a/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.tsx b/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.tsx index 444766a12..548b0f4eb 100644 --- a/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.tsx +++ b/src-ts/tools/learn/tca-certificate/user-certificate/UserTCACertificate.tsx @@ -2,23 +2,20 @@ import { Dispatch, FC, SetStateAction, - useCallback, useEffect, useState, } from 'react' -import { NavigateFunction, Params, useNavigate, useParams } from 'react-router-dom' +import { Params, useParams } from 'react-router-dom' import { LoadingSpinner, profileGetPublicAsync, UserProfile, } from '../../../../lib' -import { getTCACertificationPath } from '../../learn.routes' import { CertificateView } from '../certificate-view' const UserTCACertificate: FC<{}> = () => { - const navigate: NavigateFunction = useNavigate() const routeParams: Params = useParams() const [profile, setProfile]: [ @@ -28,7 +25,6 @@ const UserTCACertificate: FC<{}> = () => { const [profileReady, setProfileReady]: [boolean, Dispatch>] = useState(false) const certificationParam: string = routeParams.certification ?? '' - const tcaCertificationPath: string = getTCACertificationPath(certificationParam) useEffect(() => { if (routeParams.memberHandle) { @@ -40,10 +36,6 @@ const UserTCACertificate: FC<{}> = () => { } }, [routeParams.memberHandle, setProfileReady]) - const navigateToCertification: () => void = useCallback(() => { - navigate(tcaCertificationPath) - }, [tcaCertificationPath, navigate]) - return ( <> @@ -52,7 +44,6 @@ const UserTCACertificate: FC<{}> = () => { )}