Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src-ts/lib/breadcrumb/breadcrumb-item/BreadcrumbItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const BreadcrumbItem: FC<BreadcrumbItemProps> = (props: BreadcrumbItemProps) =>
<Link
className={classNames(props.item.isElipsis && styles.elipsis)}
to={props.item.url}
state={props.item.state}
>
{props.item.name}
</Link>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export interface BreadcrumbItemModel {
name: string
onClick?: (item: BreadcrumbItemModel) => void
url: string
state?: any
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FC, ReactNode } from 'react'

import { Button, IconSolid, ProgressBar } from '../../../../../../lib'
import { BreadcrumbItemModel, Button, IconSolid, ProgressBar } from '../../../../../../lib'
import {
clearFCCCertificationTitle,
CompletionTimeRange,
Expand All @@ -20,6 +20,7 @@ import {
getCertificatePath,
getCoursePath,
getLessonPathFromCurrentLesson,
getTCACertificationPath,
} from '../../../../learn.routes'
import CurriculumCard from '../CurriculumCard'

Expand All @@ -36,7 +37,16 @@ interface CourseCardProps {
}

const CourseCard: FC<CourseCardProps> = (props: CourseCardProps) => {

function renderCta(): ReactNode {

const routeState: { tcaCertInfo: BreadcrumbItemModel } = {
tcaCertInfo: {
name: props.tcaCertification.title,
url: getTCACertificationPath(props.tcaCertification.dashedName),
},
}

switch (props.progress?.status) {
case UserCertificationProgressStatus.completed:
return (
Expand All @@ -49,12 +59,7 @@ const CourseCard: FC<CourseCardProps> = (props: CourseCardProps) => {
props.provider,
props.certification.certification,
)}
routeState={{
tcaCertInfo: {
dashedName: props.tcaCertification.dashedName,
title: props.tcaCertification.title,
},
}}
routeState={routeState}
/>
<Button
buttonStyle='primary'
Expand All @@ -78,12 +83,7 @@ const CourseCard: FC<CourseCardProps> = (props: CourseCardProps) => {
props.certification.certification,
props.progress?.currentLesson,
)}
routeState={{
tcaCertInfo: {
dashedName: props.tcaCertification.dashedName,
title: props.tcaCertification.title,
},
}}
routeState={routeState}
/>
)
default:
Expand All @@ -96,12 +96,7 @@ const CourseCard: FC<CourseCardProps> = (props: CourseCardProps) => {
props.provider,
props.certification.certification,
)}
routeState={{
tcaCertInfo: {
dashedName: props.tcaCertification.dashedName,
title: props.tcaCertification.title,
},
}}
routeState={routeState}
/>
)
}
Expand Down
55 changes: 17 additions & 38 deletions src-ts/tools/learn/course-completed/CourseCompletedPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FC, useContext, useEffect, useMemo } from 'react'
import { NavigateFunction, Params, useLocation, useNavigate, useParams } from 'react-router-dom'
import { Params, useParams } from 'react-router-dom'

import {
Breadcrumb,
Expand All @@ -19,20 +19,20 @@ import {
useGetCourses,
useGetTCACertification,
useGetUserCertificationProgress,
useLearnBreadcrumb,
UserCertificationProgressProviderData,
UserCertificationProgressStatus,
useTCACertificationCheckCompleted,
} from '../learn-lib'
import { getCoursePath, getTCACertificationPath, LEARN_PATHS } from '../learn.routes'
import { getCoursePath, LEARN_PATHS } from '../learn.routes'
import { CoursePageContextValue, useCoursePageContext } from '../course-page-wrapper'

import { CourseView } from './course-view'
import { TCACertificationView } from './tca-certification-view'
import styles from './CourseCompletedPage.module.scss'

const CourseCompletedPage: FC<{}> = () => {

const navigate: NavigateFunction = useNavigate()
const { buildBreadcrumbs, localNavigate }: CoursePageContextValue = useCoursePageContext()
const routeParams: Params<string> = useParams()
const { profile, initialized: profileReady }: ProfileContextData = useContext(profileContext)
const providerParam: string = textFormatGetSafeString(routeParams.provider)
Expand Down Expand Up @@ -94,45 +94,24 @@ const CourseCompletedPage: FC<{}> = () => {
tcaCertifCompletedCheckReady,
])

const location: any = useLocation()

const breadcrumbItems: BreadcrumbItemModel[] = useMemo(() => {
const bItems: BreadcrumbItemModel[] = [
{
name: courseData?.title ?? '',
url: coursePath,
},
{
name: 'Congratulations!',
url: LEARN_PATHS.completed,
},
]

// if coming path is from TCA certification details page
// then we need to add the certification to the navi list
if (location.state?.tcaCertInfo) {
bItems.unshift({
name: location.state.tcaCertInfo.title,
url: getTCACertificationPath(location.state.tcaCertInfo.dashedName),
})
}

return bItems
}, [
location.state,
courseData?.title,
coursePath,
])

const breadcrumb: Array<BreadcrumbItemModel> = useLearnBreadcrumb(breadcrumbItems)
const breadcrumbs: Array<BreadcrumbItemModel> = useMemo(() => buildBreadcrumbs([
{
name: courseData?.title ?? '',
url: coursePath,
},
{
name: 'Congratulations!',
url: LEARN_PATHS.completed,
},
]), [buildBreadcrumbs, courseData?.title, coursePath])

useEffect(() => {
if (ready && progress?.status !== UserCertificationProgressStatus.completed) {
navigate(coursePath)
localNavigate(coursePath)
}
}, [
coursePath,
navigate,
localNavigate,
progress,
ready,
])
Expand All @@ -147,7 +126,7 @@ const CourseCompletedPage: FC<{}> = () => {

{ready && courseData && (
<>
<Breadcrumb items={breadcrumb} />
<Breadcrumb items={breadcrumbs} />
<div className={styles['main-wrap']}>
<div className={styles['course-frame']}>
{tcaCertificationName && tcaCertification ? (
Expand Down
40 changes: 10 additions & 30 deletions src-ts/tools/learn/course-details/CourseDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable react/no-danger */
import { FC, ReactNode, useContext, useMemo } from 'react'
import { Params, useLocation, useParams } from 'react-router-dom'
import { Params, useParams } from 'react-router-dom'

import {
Breadcrumb,
Expand All @@ -23,17 +23,17 @@ import {
useGetCourses,
useGetResourceProvider,
useGetUserCertificationProgress,
useLearnBreadcrumb,
UserCertificationProgressProviderData,
UserCertificationProgressStatus,
} from '../learn-lib'
import { getCoursePath, getTCACertificationPath } from '../learn.routes'
import { getCoursePath } from '../learn.routes'
import { CoursePageContextValue, useCoursePageContext } from '../course-page-wrapper'

import { CourseCurriculum } from './course-curriculum'
import styles from './CourseDetailsPage.module.scss'

const CourseDetailsPage: FC<{}> = () => {

const { buildBreadcrumbs }: CoursePageContextValue = useCoursePageContext()
const routeParams: Params<string> = useParams()
const { profile, initialized: profileReady }: ProfileContextData = useContext(profileContext)

Expand Down Expand Up @@ -69,36 +69,16 @@ const CourseDetailsPage: FC<{}> = () => {

const ready: boolean = profileReady && courseReady && certificateReady && (!profile || progressReady)

const location: any = useLocation()

const breadcrumbItems: BreadcrumbItemModel[] = useMemo(() => {
const bItems: BreadcrumbItemModel[] = [
{

name: textFormatGetSafeString(course?.title),
url: getCoursePath(routeParams.provider as string, textFormatGetSafeString(routeParams.certification)),
},
]

// if coming path is from TCA certification details page
// then we need to add the certification to the navi list
if (location.state?.tcaCertInfo) {
bItems.unshift({
name: location.state.tcaCertInfo.title,
url: getTCACertificationPath(location.state.tcaCertInfo.dashedName),
})
}

return bItems
}, [
const breadcrumbs: Array<BreadcrumbItemModel> = useMemo(() => buildBreadcrumbs([{
name: textFormatGetSafeString(course?.title),
url: getCoursePath(routeParams.provider as string, textFormatGetSafeString(routeParams.certification)),
}]), [
buildBreadcrumbs,
course?.title,
routeParams.certification,
routeParams.provider,
location.state,
])

const breadcrumb: Array<BreadcrumbItemModel> = useLearnBreadcrumb(breadcrumbItems)

function getDescription(): ReactNode {

if (!course) {
Expand Down Expand Up @@ -207,7 +187,7 @@ const CourseDetailsPage: FC<{}> = () => {
<LoadingSpinner />
</div>
)}
<Breadcrumb items={breadcrumb} />
<Breadcrumb items={breadcrumbs} />
{ready && course && certificate && (
<>
<div className={styles.wrap}>
Expand Down
90 changes: 90 additions & 0 deletions src-ts/tools/learn/course-page-wrapper/CoursePage.context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Context, createContext, FC, ReactNode, useCallback, useContext, useMemo } from 'react'
import { NavigateFunction, useLocation, useNavigate } from 'react-router-dom'
import { pick } from 'lodash'

import { rootRoute } from '../learn.routes'
import { BreadcrumbItemModel } from '../../../lib'

export interface CoursePageContextProviderProps {
children: ReactNode
}

export interface CoursePageContextValue {
buildBreadcrumbs: (items: BreadcrumbItemModel[]) => BreadcrumbItemModel[]
localNavigate: NavigateFunction
navState: { tcaCertInfo: BreadcrumbItemModel } | undefined
}

const CoursePageContext: Context<CoursePageContextValue> = createContext(
{} as CoursePageContextValue,
)

/**
* Page context provider for Course pages: details, fcc, completed
*
* It keeps into account the navigation path the user took to get here
*
* Eg. if user clicked the course directly, there's nothing to do, but
* if the user clicked the course from inside the TCA certification page
* we need to show an extra breadcrumb specific to TCA certification page
*/

export const CoursePageContextProvider: FC<CoursePageContextProviderProps> = props => {
const location: any = useLocation()
const navigate: NavigateFunction = useNavigate()

const parentTcaCert: BreadcrumbItemModel | undefined = useMemo(() => (
(
location.state
&& Object.prototype.hasOwnProperty.call(location.state, 'tcaCertInfo')
&& location.state.tcaCertInfo && pick(location.state.tcaCertInfo, ['name', 'url'])
) || undefined
), [location.state])

const buildBreadcrumbs: (items: BreadcrumbItemModel[]) => BreadcrumbItemModel[]
= useCallback(items => {
const breadcrumbs: BreadcrumbItemModel[] = [
{
name: 'Topcoder Academy',
url: rootRoute,
},
...(!parentTcaCert ? [] : [parentTcaCert]),
...items,
]

return !parentTcaCert ? breadcrumbs : breadcrumbs.map(item => Object.assign(item, {
state: { tcaCertInfo: pick(parentTcaCert, ['name', 'url']) },
}))
}, [parentTcaCert])

const localNavigate: NavigateFunction = useCallback((to, options) => (
navigate(to, {
...options,
state: {
...options?.state,
tcaCertInfo: parentTcaCert,
},
})
), [navigate, parentTcaCert]) as NavigateFunction

const ctxValue: CoursePageContextValue = useMemo(() => ({
buildBreadcrumbs,
localNavigate,
navState: parentTcaCert ? { tcaCertInfo: parentTcaCert } : undefined,
}), [
buildBreadcrumbs,
localNavigate,
parentTcaCert,
])

return (
<CoursePageContext.Provider
value={ctxValue}
>
{props.children}
</CoursePageContext.Provider>
)
}

export const useCoursePageContext: () => CoursePageContextValue
= () => useContext(CoursePageContext)
27 changes: 27 additions & 0 deletions src-ts/tools/learn/course-page-wrapper/CoursePageWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { FC, ReactElement, useContext, useMemo } from 'react'
import { Outlet, Routes } from 'react-router-dom'

import { routeContext, RouteContextData } from '../../../lib'
import { learnRoutes } from '../learn.routes'

import { CoursePageContextProvider } from './CoursePage.context'

const CoursePageWrapper: FC<{}> = () => {
const { getRouteElement }: RouteContextData = useContext(routeContext)

// Get all the CoursePage child routes and render them as a route element
const childRoutes: ReactElement[] = useMemo(() => (
learnRoutes[0].children?.find(route => route.id === 'CoursePage')?.children ?? []
).map(getRouteElement), [getRouteElement])

return (
<CoursePageContextProvider>
<Outlet />
<Routes>
{childRoutes}
</Routes>
</CoursePageContextProvider>
)
}

export default CoursePageWrapper
2 changes: 2 additions & 0 deletions src-ts/tools/learn/course-page-wrapper/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as CoursePageWrapper } from './CoursePageWrapper'
export * from './CoursePage.context'
Loading