Skip to content

Commit 6233f09

Browse files
authored
Merge pull request #296 from topcoder-platform/TCA-440_certificate-progress
Tca 445 Landing Progress slider
2 parents 1468545 + dbeb9ad commit 6233f09

File tree

6 files changed

+166
-64
lines changed

6 files changed

+166
-64
lines changed

src-ts/tools/learn/learn-lib/my-course-card/in-progress/InProgress.module.scss

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@
88

99
display: flex;
1010

11-
&.large {
12-
padding: $space-xxxxl;
13-
}
14-
1511
@include ltelg {
1612
&, &.large {
1713
padding: $space-lg;
@@ -119,8 +115,8 @@
119115

120116
.started-date {
121117
font-weight: bold;
122-
118+
123119
@include ltemd {
124120
order: -1;
125121
}
126-
}
122+
}

src-ts/tools/learn/welcome/progress-block/ProgressBlock.module.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
.wrap {
55
background: $black-5;
66
border-radius: $space-sm;
7-
padding: $space-xxl;
7+
padding: $space-xxl $space-xxl $space-lg;
88
color: $black-100;
99

1010
display: flex;
1111
flex-direction: column;
12-
gap: $space-lg;
12+
gap: $space-xxl;
1313
width: 100%;
14-
14+
1515
@include ltemd {
1616
padding: $space-lg;
1717
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
@import '../../../../../lib/styles/includes';
2+
3+
.slides-wrap {
4+
display: block;
5+
position: relative;
6+
z-index: 1;
7+
overflow: hidden;
8+
}
9+
10+
.slide {
11+
position: absolute;
12+
top: 0;
13+
left: 0;
14+
width: 100%;
15+
16+
opacity: 0;
17+
visibility: hidden;
18+
transition: 0.2s ease;
19+
&:global(:not(.active)) {
20+
pointer-events: none;
21+
}
22+
23+
24+
&:global(.is-prev) {
25+
transform: translateX(-100%);
26+
}
27+
28+
&:global(.is-next) {
29+
transform: translateX(100%);
30+
}
31+
32+
&:global(.active) {
33+
position: relative;
34+
opacity: 1;
35+
transform: translateX(0);
36+
visibility: visible;
37+
}
38+
}
39+
40+
.nav-wrap {
41+
display: flex;
42+
align-items: center;
43+
justify-content: center;
44+
margin-top: $space-xxl;
45+
46+
gap: calc($space-xs + $border-xs);
47+
}
48+
49+
.nav-dot {
50+
display: block;
51+
width: $space-md;
52+
height: $space-md;
53+
background: $black-40;
54+
border-radius: 50%;
55+
cursor: pointer;
56+
57+
&:global(.active) {
58+
width: calc($space-lg + $border);
59+
height: calc($space-lg + $border);
60+
border: $border solid $turq-100;
61+
background: $tc-white;
62+
}
63+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import classNames from 'classnames'
2+
import { fill } from 'lodash'
3+
import { Children, Dispatch, FC, ReactNode, SetStateAction, useState } from 'react'
4+
5+
import styles from './CardsSlider.module.scss'
6+
7+
interface CardsSliderProps {
8+
children: Array<JSX.Element>
9+
}
10+
11+
const CardsSlider: FC<CardsSliderProps> = (props: CardsSliderProps) => {
12+
const [activeSlide, setActiveSlide]: [number, Dispatch<SetStateAction<number>>] = useState(0)
13+
14+
const wrapSlides: (children: Array<JSX.Element>) => Array<JSX.Element> = (children: Array<JSX.Element>) => {
15+
return Children.map<ReactNode, ReactNode>(children, (child, index) => (
16+
<div
17+
className={
18+
classNames(
19+
styles.slide,
20+
activeSlide === index && 'active',
21+
activeSlide > index && 'is-prev',
22+
activeSlide < index && 'is-next',
23+
)
24+
}
25+
>
26+
{child}
27+
</div>
28+
)) as Array<JSX.Element>
29+
}
30+
31+
return (
32+
<div className={styles.wrap}>
33+
<div className={styles['slides-wrap']}>
34+
{wrapSlides(props.children)}
35+
</div>
36+
<div className={styles['nav-wrap']}>
37+
{fill(Array(props.children.length), '').map((_, i) => (
38+
<span
39+
key={i}
40+
className={classNames(styles['nav-dot'], activeSlide === i && 'active')}
41+
onClick={() => setActiveSlide(i)}
42+
/>
43+
))}
44+
</div>
45+
</div>
46+
)
47+
}
48+
49+
export default CardsSlider
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as CardsSlider } from './CardsSlider'

src-ts/tools/learn/welcome/progress-block/progress-action/ProgressAction.tsx

Lines changed: 48 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
import { orderBy } from 'lodash'
12
import { FC, ReactNode, useMemo } from 'react'
23

34
import { Button } from '../../../../../lib'
45
import {
56
LearnCertification,
6-
LearningHat,
7+
LearnUserCertificationProgress,
78
MyCourseCompletedCard,
89
MyCourseInProgressCard,
910
UserCertificationCompleted,
1011
UserCertificationInProgress,
12+
UserCertificationProgressStatus,
1113
} from '../../../learn-lib'
1214
import { LEARN_PATHS } from '../../../learn.routes'
15+
import { CardsSlider } from '../cards-slider'
1316

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

@@ -19,6 +22,12 @@ interface ProgressActionProps {
1922
userInProgressCertifications: ReadonlyArray<UserCertificationInProgress>
2023
}
2124

25+
function isCompleted(cert: LearnUserCertificationProgress): boolean {
26+
return cert.status === UserCertificationProgressStatus.completed
27+
}
28+
29+
const USER_PROGRESS_MAX_SLIDES_COUNT: number = 8
30+
2231
const ProgressAction: FC<ProgressActionProps> = (props: ProgressActionProps) => {
2332

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

48-
// we only want to display the last course that was acted upon
49-
const mostRecentIsCompleted: boolean = myCompletedCertifications?.[0]?.updatedAt > (myInProgressCertifications?.[0]?.updatedAt || 0)
50-
51-
function renderInProgress(): JSX.Element {
52-
53-
// if the most recently acted upon course is completed and not in progress,
54-
// or there are no courses in progress, don't show this block
55-
if (mostRecentIsCompleted || !myInProgressCertifications.length) {
56-
return <></>
57-
}
58-
59-
const courseToDisplay: UserCertificationInProgress = myInProgressCertifications[0]
57+
const recentlyUpdatedCertifications: Array<LearnUserCertificationProgress> = orderBy([
58+
...myCompletedCertifications,
59+
...myInProgressCertifications,
60+
], 'updatedAt', 'desc').slice(0, USER_PROGRESS_MAX_SLIDES_COUNT)
6061

62+
function renderInProgress(courseToDisplay: UserCertificationInProgress): JSX.Element {
6163
return (
62-
<>
63-
<div className={styles['title-line']}>
64-
<h4 className='details'>In progress</h4>
65-
<span className='mobile-hide'>
66-
{allMyLearningsLink}
67-
</span>
68-
</div>
69-
<MyCourseInProgressCard
70-
certification={certificationsById[courseToDisplay.certificationId]}
71-
key={courseToDisplay.certificationId}
72-
completedPercentage={courseToDisplay.courseProgressPercentage / 100}
73-
theme='minimum'
74-
currentLesson={courseToDisplay.currentLesson}
75-
/>
76-
</>
64+
<MyCourseInProgressCard
65+
certification={certificationsById[courseToDisplay.certificationId]}
66+
key={courseToDisplay.certificationId}
67+
completedPercentage={courseToDisplay.courseProgressPercentage / 100}
68+
theme='minimum'
69+
currentLesson={courseToDisplay.currentLesson}
70+
/>
7771
)
7872
}
7973

80-
function renderCompleted(): JSX.Element {
74+
function renderCompleted(certToDisplay: UserCertificationCompleted): JSX.Element {
75+
return (
76+
<MyCourseCompletedCard
77+
certification={certificationsById[certToDisplay.certificationId]}
78+
key={certToDisplay.certificationId}
79+
completed={certToDisplay.completedDate}
80+
/>
81+
)
82+
}
8183

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

88-
const certToDisplay: UserCertificationCompleted = myCompletedCertifications[0]
89-
90-
return (
91-
<>
92-
<div className={styles['title-line']}>
93-
<div className={styles.title}>
94-
<LearningHat />
95-
<h4 className='details'>Congratulations!</h4>
96-
</div>
97-
<span className='mobile-hide'>
98-
{allMyLearningsLink}
99-
</span>
100-
</div>
101-
<MyCourseCompletedCard
102-
certification={certificationsById[certToDisplay.certificationId]}
103-
key={certToDisplay.certificationId}
104-
completed={certToDisplay.completedDate}
105-
/>
106-
</>
107-
)
89+
return recentlyUpdatedCertifications.map((cert) => (
90+
isCompleted(cert)
91+
? renderCompleted(cert as UserCertificationCompleted)
92+
: renderInProgress(cert as UserCertificationInProgress)
93+
))
10894
}
10995

11096
return (
11197
<>
112-
{renderInProgress()}
113-
{renderCompleted()}
98+
<div className={styles['title-line']}>
99+
<h4 className='details'>My progress</h4>
100+
<span className='mobile-hide'>
101+
{allMyLearningsLink}
102+
</span>
103+
</div>
104+
<CardsSlider>
105+
{renderCertificateCards()}
106+
</CardsSlider>
114107
<span className='desktop-hide'>
115108
{allMyLearningsLink}
116109
</span>

0 commit comments

Comments
 (0)