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.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..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,55 +1,44 @@
-import { FC, MutableRefObject, useCallback, useEffect, useMemo, useRef } from 'react'
-import classNames from 'classnames'
+import { FC, MutableRefObject, ReactNode, useCallback, useRef } from 'react'
import {
- FacebookSocialShareBtn,
- fileDownloadCanvasAsImage,
IconOutline,
- LinkedinSocialShareBtn,
LoadingSpinner,
- NavigateBackFunction,
- TwitterSocialShareBtn,
- useNavigateBack,
UserProfile,
} from '../../../../lib'
import {
ActionButton,
+ CertificateNotFoundContent,
+ 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
+import { CertificateNotFound } from '../certificate-not-found'
interface CertificateViewProps {
certification: string,
- hideActions?: boolean,
- onCertificationNotCompleted: () => void
+ fullScreenCertLayout?: boolean,
profile: UserProfile,
- viewStyle: CertificateViewStyle
}
const CertificateView: FC
= (props: CertificateViewProps) => {
- const navigateBack: NavigateBackFunction = useNavigateBack()
const tcaCertificationPath: string = getTCACertificationPath(props.certification)
const certificateElRef: MutableRefObject = useRef()
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}`
}
@@ -62,111 +51,55 @@ 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 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)
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 (
<>
- {ready && readyAndCompletedCertification && (
-
-
- {!props.hideActions && (
-
-
}
- onClick={handleBackBtnClick}
- />
-
- )}
-
-
-
- {!props.hideActions && (
-
-
}
- onClick={handlePrint}
- />
-
}
- onClick={handleDownload}
- />
-
}
- onClick={handleLinkClick}
- />
-
-
-
-
- )}
-
-
- )}
+ }
+ 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 268bb1095..b7bdfeec9 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 ?? ''
@@ -36,8 +35,6 @@ const MyTCACertificate: FC<{}> = () => {
)}
>
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..548b0f4eb 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,22 @@
-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,
+ useEffect,
+ useState,
+} from 'react'
+import { Params, 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 { 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,
@@ -25,15 +25,6 @@ const UserTCACertificate: FC<{}> = () => {
const [profileReady, setProfileReady]: [boolean, Dispatch>] = useState(false)
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) {
@@ -45,35 +36,16 @@ 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])
-
return (
<>
{profileReady && profile && (
-
-
-
+
)}
>
)