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
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@

display: flex;

&.large {
padding: $space-xxxxl;
}

@include ltelg {
&, &.large {
padding: $space-lg;
Expand Down Expand Up @@ -119,8 +115,8 @@

.started-date {
font-weight: bold;

@include ltemd {
order: -1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
.wrap {
background: $black-5;
border-radius: $space-sm;
padding: $space-xxl;
padding: $space-xxl $space-xxl $space-lg;
color: $black-100;

display: flex;
flex-direction: column;
gap: $space-lg;
gap: $space-xxl;
width: 100%;

@include ltemd {
padding: $space-lg;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
@import '../../../../../lib/styles/includes';

.slides-wrap {
display: block;
position: relative;
z-index: 1;
overflow: hidden;
}

.slide {
position: absolute;
top: 0;
left: 0;
width: 100%;

opacity: 0;
visibility: hidden;
transition: 0.2s ease;
&:global(:not(.active)) {
pointer-events: none;
}


&:global(.is-prev) {
transform: translateX(-100%);
}

&:global(.is-next) {
transform: translateX(100%);
}

&:global(.active) {
position: relative;
opacity: 1;
transform: translateX(0);
visibility: visible;
}
}

.nav-wrap {
display: flex;
align-items: center;
justify-content: center;
margin-top: $space-xxl;

gap: calc($space-xs + $border-xs);
}

.nav-dot {
display: block;
width: $space-md;
height: $space-md;
background: $black-40;
border-radius: 50%;
cursor: pointer;

&:global(.active) {
width: calc($space-lg + $border);
height: calc($space-lg + $border);
border: $border solid $turq-100;
background: $tc-white;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import classNames from 'classnames'
import { fill } from 'lodash'
import { Children, Dispatch, FC, ReactNode, SetStateAction, useState } from 'react'

import styles from './CardsSlider.module.scss'

interface CardsSliderProps {
children: Array<JSX.Element>
}

const CardsSlider: FC<CardsSliderProps> = (props: CardsSliderProps) => {
const [activeSlide, setActiveSlide]: [number, Dispatch<SetStateAction<number>>] = useState(0)

const wrapSlides: (children: Array<JSX.Element>) => Array<JSX.Element> = (children: Array<JSX.Element>) => {
return Children.map<ReactNode, ReactNode>(children, (child, index) => (
<div
className={
classNames(
styles.slide,
activeSlide === index && 'active',
activeSlide > index && 'is-prev',
activeSlide < index && 'is-next',
)
}
>
{child}
</div>
)) as Array<JSX.Element>
}

return (
<div className={styles.wrap}>
<div className={styles['slides-wrap']}>
{wrapSlides(props.children)}
</div>
<div className={styles['nav-wrap']}>
{fill(Array(props.children.length), '').map((_, i) => (
<span
key={i}
className={classNames(styles['nav-dot'], activeSlide === i && 'active')}
onClick={() => setActiveSlide(i)}
/>
))}
</div>
</div>
)
}

export default CardsSlider
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as CardsSlider } from './CardsSlider'
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { orderBy } from 'lodash'
import { FC, ReactNode, useMemo } from 'react'

import { Button } from '../../../../../lib'
import {
LearnCertification,
LearningHat,
LearnUserCertificationProgress,
MyCourseCompletedCard,
MyCourseInProgressCard,
UserCertificationCompleted,
UserCertificationInProgress,
UserCertificationProgressStatus,
} from '../../../learn-lib'
import { LEARN_PATHS } from '../../../learn.routes'
import { CardsSlider } from '../cards-slider'

import styles from './ProgressAction.module.scss'

Expand All @@ -19,6 +22,12 @@ interface ProgressActionProps {
userInProgressCertifications: ReadonlyArray<UserCertificationInProgress>
}

function isCompleted(cert: LearnUserCertificationProgress): boolean {
return cert.status === UserCertificationProgressStatus.completed
}

const USER_PROGRESS_MAX_SLIDES_COUNT: number = 8

const ProgressAction: FC<ProgressActionProps> = (props: ProgressActionProps) => {

const {
Expand All @@ -45,72 +54,56 @@ const ProgressAction: FC<ProgressActionProps> = (props: ProgressActionProps) =>
}, {} as unknown as { [key: string]: LearnCertification })
), [allCertifications])

// we only want to display the last course that was acted upon
const mostRecentIsCompleted: boolean = myCompletedCertifications?.[0]?.updatedAt > (myInProgressCertifications?.[0]?.updatedAt || 0)

function renderInProgress(): JSX.Element {

// if the most recently acted upon course is completed and not in progress,
// or there are no courses in progress, don't show this block
if (mostRecentIsCompleted || !myInProgressCertifications.length) {
return <></>
}

const courseToDisplay: UserCertificationInProgress = myInProgressCertifications[0]
const recentlyUpdatedCertifications: Array<LearnUserCertificationProgress> = orderBy([
...myCompletedCertifications,
...myInProgressCertifications,
], 'updatedAt', 'desc').slice(0, USER_PROGRESS_MAX_SLIDES_COUNT)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call! this is a much better way to get the most recent item.


function renderInProgress(courseToDisplay: UserCertificationInProgress): JSX.Element {
return (
<>
<div className={styles['title-line']}>
<h4 className='details'>In progress</h4>
<span className='mobile-hide'>
{allMyLearningsLink}
</span>
</div>
<MyCourseInProgressCard
certification={certificationsById[courseToDisplay.certificationId]}
key={courseToDisplay.certificationId}
completedPercentage={courseToDisplay.courseProgressPercentage / 100}
theme='minimum'
currentLesson={courseToDisplay.currentLesson}
/>
</>
<MyCourseInProgressCard
certification={certificationsById[courseToDisplay.certificationId]}
key={courseToDisplay.certificationId}
completedPercentage={courseToDisplay.courseProgressPercentage / 100}
theme='minimum'
currentLesson={courseToDisplay.currentLesson}
/>
)
}

function renderCompleted(): JSX.Element {
function renderCompleted(certToDisplay: UserCertificationCompleted): JSX.Element {
return (
<MyCourseCompletedCard
certification={certificationsById[certToDisplay.certificationId]}
key={certToDisplay.certificationId}
completed={certToDisplay.completedDate}
/>
)
}

// if the most recently acted upon course is in progress rather than completed,
// or there are no completed courses, don't show this block
if (!mostRecentIsCompleted || !myCompletedCertifications.length) {
return <></>
function renderCertificateCards(): Array<JSX.Element> {
if (!recentlyUpdatedCertifications.length) {
return []
}

const certToDisplay: UserCertificationCompleted = myCompletedCertifications[0]

return (
<>
<div className={styles['title-line']}>
<div className={styles.title}>
<LearningHat />
<h4 className='details'>Congratulations!</h4>
</div>
<span className='mobile-hide'>
{allMyLearningsLink}
</span>
</div>
<MyCourseCompletedCard
certification={certificationsById[certToDisplay.certificationId]}
key={certToDisplay.certificationId}
completed={certToDisplay.completedDate}
/>
</>
)
return recentlyUpdatedCertifications.map((cert) => (
isCompleted(cert)
? renderCompleted(cert as UserCertificationCompleted)
: renderInProgress(cert as UserCertificationInProgress)
))
}

return (
<>
{renderInProgress()}
{renderCompleted()}
<div className={styles['title-line']}>
<h4 className='details'>My progress</h4>
<span className='mobile-hide'>
{allMyLearningsLink}
</span>
</div>
<CardsSlider>
{renderCertificateCards()}
</CardsSlider>
<span className='desktop-hide'>
{allMyLearningsLink}
</span>
Expand Down