Skip to content

Commit 426a69b

Browse files
committed
Merge branch 'TCA-792_tc-certifications-epic' into TCA-870-cert-generation
2 parents 3423eab + 1c83cdc commit 426a69b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1216
-104
lines changed

src-ts/header/Header.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ const Header: FC = () => {
145145

146146
return (
147147
<>
148-
<div id={navElementId} />
149148
<div
150149
id={PageSubheaderPortalId}
151150
className={classNames('full-width-relative', !ready && 'hidden')}

src-ts/lib/page-footer/PageFooter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const PageFooter: FC<{}> = () => {
1919
)
2020
}, 10)
2121

22-
return <div id={navElementId} />
22+
return <></>
2323
}
2424

2525
export default PageFooter

src-ts/lib/styles/_typography.scss

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ h2 {
5353
h3 {
5454
font-size: 22px;
5555
line-height: 26px;
56-
56+
5757
@include ltemd {
5858
font-size: 18px;
5959
line-height: 20px;
@@ -134,13 +134,17 @@ h4 {
134134
font-family: $font-roboto;
135135
font-size: 16px;
136136
line-height: 24px;
137+
&-medium {
138+
@extend .body-main;
139+
font-weight: $font-weight-medium;
140+
}
137141
&-bold {
138142
@extend .body-main;
139143
font-weight: $font-weight-bold;
140144
}
141145

142146
@include ltemd {
143-
&, &-bold {
147+
&, &-medium, &-bold {
144148
font-size: 14px;
145149
line-height: 20px;
146150
}
@@ -177,7 +181,7 @@ h4 {
177181
font-weight: $font-weight-semibold;
178182
font-size: 20px;
179183
line-height: 26px;
180-
184+
181185
@include ltemd {
182186
font-size: 14px;
183187
line-height: 20px;
@@ -188,7 +192,7 @@ h4 {
188192
font-weight: $font-weight-normal;
189193
font-size: 20px;
190194
line-height: 26px;
191-
195+
192196
@include ltemd {
193197
font-size: 14px;
194198
line-height: 20px;
@@ -201,7 +205,7 @@ h4 {
201205
padding: 0;
202206
font-size: 20px;
203207
line-height: 22px;
204-
208+
205209
@include ltemd {
206210
font-size: 14px;
207211
line-height: 20px;
@@ -278,6 +282,14 @@ h4 {
278282
font-style: revert;
279283
}
280284

285+
.quote-main {
286+
font-size: 16px;
287+
line-height: 26px;
288+
font-family: $font-roboto;
289+
font-weight: $font-weight-normal;
290+
font-style: italic;
291+
}
292+
281293
.label {
282294
font-weight: $font-weight-semibold;
283295
font-size: 11px;

src-ts/lib/styles/mixins/_breakpoints.mixins.scss

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,30 @@
8585
}
8686
}
8787

88+
@mixin ltexl {
89+
@media (max-width: #{$xl-max}) {
90+
@content;
91+
}
92+
}
93+
8894
@mixin xl {
8995
@media (min-width: #{$xl-min}) and (max-width: #{$xl-max}){
9096
@content;
9197
}
9298
}
9399

100+
@mixin gtexl {
101+
@media (min-width: #{$xl-min}) {
102+
@content;
103+
}
104+
}
105+
106+
@mixin ltexxl {
107+
@media (max-width: #{$xl-max}) {
108+
@content;
109+
}
110+
}
111+
94112
@mixin xxl {
95113
@media (min-width: #{$xxl-min}){
96114
@content;

src-ts/lib/svgs/icon-level-1.svg

Lines changed: 0 additions & 5 deletions
This file was deleted.

src-ts/lib/svgs/icon-level-2.svg

Lines changed: 0 additions & 5 deletions
This file was deleted.

src-ts/lib/svgs/index.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ import { ReactComponent as TcAcademyLogoSvg } from './tc-academy-logo.svg'
2323
import { ReactComponent as TcLogoSvg } from './tc-logo.svg'
2424
import { ReactComponent as FccLogoSvg } from './vendor-fcc-logo.svg'
2525
import { ReactComponent as FccLogoBlackSvg } from './vendor-fcc-logo-black.svg'
26-
import { ReactComponent as IconLevel1 } from './icon-level-1.svg'
27-
import { ReactComponent as IconLevel2 } from './icon-level-2.svg'
28-
import { ReactComponent as IconLevel3 } from './icon-level-3.svg'
2926

3027
export {
3128
ActiveTabTipIcon,
@@ -51,8 +48,5 @@ export {
5148
TcLogoSvg,
5249
FccLogoSvg,
5350
FccLogoBlackSvg,
54-
IconLevel1,
55-
IconLevel2,
56-
IconLevel3,
5751
}
5852
export * from './icon-wrapper'

src-ts/lib/tooltip/Tooltip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ interface TooltipEvent {
99
}
1010

1111
interface TooltipProps {
12-
content?: string
12+
content?: ReactNode
1313
place?: 'top' | 'right' | 'bottom' | 'left'
1414
trigger: ReactNode
1515
triggerOn?: 'click' | 'hover'
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
@import '../../../lib/styles/includes';
2+
3+
.hero-wrap {
4+
:global(.hero-content) {
5+
flex-direction: column;
6+
gap: $space-xxxxl;
7+
position: relative;
8+
9+
@include gtelg {
10+
padding-right: calc(40vw + $space-xxl);
11+
}
12+
13+
@include gtexl {
14+
padding-right: calc(445px + $space-xxl);
15+
}
16+
}
17+
}
18+
19+
.contentWrap {
20+
.outerContentWrap {
21+
padding-top: $space-mxx;
22+
padding-bottom: 120px;
23+
24+
@include ltexl {
25+
padding-top: $space-xxxxl;
26+
padding-bottom: $space-xxxxl;
27+
}
28+
29+
@include gtelg {
30+
padding-right: calc(40vw + $space-xxl * 2);
31+
}
32+
33+
@include gtexl {
34+
padding-right: calc(445px + $space-xxxl * 2);
35+
}
36+
}
37+
}
38+
39+
.text-section {
40+
margin-top: 80px;
41+
42+
@include ltelg {
43+
margin-top: $space-xxxxl;
44+
}
45+
46+
h2 {
47+
margin-bottom: $space-xxl;
48+
}
49+
50+
ul {
51+
list-style: disc;
52+
padding-left: $space-xxl;
53+
padding-left: $space-xxl;
54+
}
55+
}
56+
57+
.requirement-section {
58+
59+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { FC, ReactNode, useContext } from 'react'
2+
import { Params, useParams } from 'react-router-dom'
3+
4+
import { PageSubheaderPortalId } from '../../../config'
5+
import { TCACertificationsProviderData, useGetTCACertificationMOCK, useLearnBreadcrumb, WaveHero } from '../learn-lib'
6+
import {
7+
Breadcrumb,
8+
BreadcrumbItemModel,
9+
Button,
10+
ContentLayout,
11+
LoadingSpinner,
12+
Portal,
13+
profileContext,
14+
ProfileContextData,
15+
textFormatGetSafeString,
16+
} from '../../../lib'
17+
18+
import { Accordion } from './accordion'
19+
import { FAQs } from './data/faqs.data'
20+
import { HeroTitle } from './hero-title'
21+
import { CertificationDetailsSidebar } from './certification-details-sidebar'
22+
import { PerksSection } from './perks-section'
23+
import { perks } from './data/perks.data'
24+
import styles from './CertificationDetailsPage.module.scss'
25+
26+
function renderBasicList(items: Array<string>): ReactNode {
27+
return (
28+
<ul className='body-main'>
29+
{items.map(item => (
30+
<li key={item}>{item}</li>
31+
))}
32+
</ul>
33+
)
34+
}
35+
36+
const CertificationDetailsPage: FC<{}> = () => {
37+
const routeParams: Params<string> = useParams()
38+
const { certification: dashedName }: Params<string> = routeParams
39+
const { initialized: profileReady }: ProfileContextData = useContext(profileContext)
40+
41+
const {
42+
certifications: [certification],
43+
ready: certificateReady,
44+
}: TCACertificationsProviderData = useGetTCACertificationMOCK(dashedName as string)
45+
46+
const ready: boolean = profileReady && certificateReady
47+
48+
const breadcrumb: Array<BreadcrumbItemModel> = useLearnBreadcrumb([
49+
{
50+
51+
name: textFormatGetSafeString(certification.title),
52+
url: '',
53+
},
54+
])
55+
56+
function renderLearningOutcomeSection(): ReactNode {
57+
return (
58+
<div className={styles['text-section']}>
59+
<h2>What I Will Learn?</h2>
60+
{renderBasicList(certification.learningOutcomes)}
61+
</div>
62+
)
63+
}
64+
65+
function renderRequirementsSection(): ReactNode {
66+
return (
67+
<div className={styles['text-section']}>
68+
<h2>Requirements</h2>
69+
{certification.prerequisites?.length ? (
70+
renderBasicList(certification.prerequisites)
71+
) : (
72+
<p className='body-main'>
73+
No prior knowledge in software development is required
74+
</p>
75+
)}
76+
</div>
77+
)
78+
}
79+
80+
function renderFaqSection(): ReactNode {
81+
return (
82+
<div className={styles['text-section']}>
83+
<h2>Frequently Asked Questions</h2>
84+
<Accordion items={FAQs} />
85+
</div>
86+
)
87+
}
88+
89+
return (
90+
<ContentLayout contentClass={styles.contentWrap} outerClass={styles.outerContentWrap}>
91+
{!ready && (
92+
<div className={styles.wrap}>
93+
<LoadingSpinner />
94+
</div>
95+
)}
96+
<Breadcrumb items={breadcrumb} />
97+
98+
<Portal portalId={PageSubheaderPortalId}>
99+
<div className={styles['hero-wrap']}>
100+
<WaveHero
101+
title={(
102+
<HeroTitle
103+
certTitle={certification.title}
104+
providers={certification.providers}
105+
/>
106+
)}
107+
theme='grey'
108+
text={certification.introText}
109+
>
110+
<Button
111+
buttonStyle='primary'
112+
size='md'
113+
label='Enroll Now'
114+
/>
115+
</WaveHero>
116+
<CertificationDetailsSidebar certification={certification} />
117+
</div>
118+
</Portal>
119+
120+
<PerksSection items={perks} />
121+
{renderLearningOutcomeSection()}
122+
{renderRequirementsSection()}
123+
{renderFaqSection()}
124+
</ContentLayout>
125+
)
126+
}
127+
128+
export default CertificationDetailsPage
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import '../../../../lib/styles/includes';
2+
3+
.wrap {
4+
5+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Dispatch, FC, SetStateAction, useState } from 'react'
2+
3+
import { AccordionItem } from './accordion-item'
4+
import styles from './Accordion.module.scss'
5+
6+
export interface FaqEntry {
7+
title: string
8+
description: string
9+
}
10+
11+
interface AccordionProps {
12+
items: Array<FaqEntry>
13+
}
14+
15+
type ToggledItems = {
16+
[key: string]: boolean
17+
}
18+
19+
const Accordion: FC<AccordionProps> = (props: AccordionProps) => {
20+
21+
const [toggled, setToggled]: [ToggledItems, Dispatch<SetStateAction<ToggledItems>>] = useState({} as ToggledItems)
22+
23+
function toggle(item: FaqEntry): void {
24+
setToggled(t => ({ ...t, [item.title]: !t[item.title] }))
25+
}
26+
27+
return (
28+
<div className={styles.wrap}>
29+
{props.items.map((item: FaqEntry) => (
30+
<AccordionItem
31+
item={item}
32+
toggle={toggle}
33+
isToggled={!!toggled[item.title]}
34+
key={item.title}
35+
/>
36+
))}
37+
</div>
38+
)
39+
}
40+
41+
export default Accordion

0 commit comments

Comments
 (0)