Skip to content

Commit 8ec4053

Browse files
moT01ahmaxed
andauthored
feat(client/curriculum): release new superblocks, certs coming soon (freeCodeCamp#63574)
Co-authored-by: ahmad abdolsaheb <ahmad.abdolsaheb@gmail.com>
1 parent 4352a5b commit 8ec4053

25 files changed

Lines changed: 520 additions & 101 deletions

api/src/routes/protected/certificate.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ describe('certificate routes', () => {
5252
isMachineLearningPyCertV7: false,
5353
isCollegeAlgebraPyCertV8: false,
5454
isFoundationalCSharpCertV8: false,
55+
// isJavascriptCertV9: false,
56+
// isRespWebDesignCertV9: false,
5557
username: 'fcc'
5658
}
5759
});
@@ -241,6 +243,8 @@ describe('certificate routes', () => {
241243
isMachineLearningPyCertV7: true,
242244
isCollegeAlgebraPyCertV8: true,
243245
isFoundationalCSharpCertV8: true,
246+
// isJavascriptCertV9: true,
247+
// isRespWebDesignCertV9: true,
244248
isA2EnglishCert: true
245249
}
246250
});

client/i18n/locales/english/intro.json

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5087,6 +5087,7 @@
50875087
},
50885088
"javascript-v9": {
50895089
"title": "JavaScript Certification",
5090+
"note": "This certification is currently in development and will be available soon. We recommend completing the available courses below to prepare for the certification exam once it is released.",
50905091
"intro": [
50915092
"This course teaches you core JavaScript programming concepts such as working with variables, functions, objects, arrays, and control flow. You'll also learn how to manipulate the DOM, handle events, and apply techniques like asynchronous programming, functional programming, and accessibility best practices.",
50925093
"To qualify for the exam, you must complete the following projects:",
@@ -5101,6 +5102,12 @@
51015102
"javascript": "JavaScript",
51025103
"javascript-certification-exam": "JavaScript Certification Exam"
51035104
},
5105+
"module-intros": {
5106+
"javascript-certification-exam": {
5107+
"note": "Coming Winter 2025",
5108+
"intro": ["Pass this exam to earn your JavaScript Certification."]
5109+
}
5110+
},
51045111
"modules": {
51055112
"javascript-variables-and-strings": "Variables and Strings",
51065113
"javascript-booleans-and-numbers": "Booleans and Numbers",
@@ -7483,6 +7490,12 @@
74837490
"intro": [
74847491
"Learn the fundamentals of how web communication works through the HTTP request-response model, explore different types of web assets and responses, and understand how forms handle data submission using various HTTP methods."
74857492
]
7493+
},
7494+
"exam-back-end-development-and-apis-certification": {
7495+
"title": "Back End Development and APIs Certification Exam",
7496+
"intro": [
7497+
"Pass this exam to earn your Back End Development and APIs Certification"
7498+
]
74867499
}
74877500
}
74887501
},
@@ -7491,14 +7504,7 @@
74917504
"note": "If you were previously working through our full stack curriculum, don't worry - you're progress is saved. We split it into smaller certifications for you to earn along your journey. This certification is currently in development and will be available soon. Start earning the required certifications so you're ready when it launches.",
74927505
"intro": [
74937506
"This certification represents the culmination of your full stack developer journey. It demonstrates your ability to build complete, modern web applications from start to finish.",
7494-
"To qualify for the exam, you must earn the following certifications:",
7495-
"- Responsive Web Design Certification",
7496-
"- JavaScript Certification",
7497-
"- Front End Development Libraries Certification",
7498-
"- Python Certification",
7499-
"- Relational Databases Certification",
7500-
"- Back End Development and APIs Certification",
7501-
"Pass the exam to earn your Full Stack Developer Certification."
7507+
"To qualify for the exam, you must earn the certifications below. Pass the exam to earn your Full Stack Developer Certification."
75027508
],
75037509
"chapters": {
75047510
"certified-full-stack-developer-exam": "Certified Full Stack Developer Exam"
@@ -7510,7 +7516,7 @@
75107516
"certified-full-stack-developer-exam": {
75117517
"note": "Coming Late 2026",
75127518
"intro": [
7513-
"This will be a 90 question exam testing what you have learned throughout this certification."
7519+
"This exam will test what you have learned throughout the previous six certifications."
75147520
]
75157521
}
75167522
},
@@ -7658,6 +7664,7 @@
76587664
},
76597665
"responsive-web-design-v9": {
76607666
"title": "Responsive Web Design Certification",
7667+
"note": "This certification is currently in development and will be available soon. We recommend completing the available courses below to prepare for the certification exam once it is released.",
76617668
"intro": [
76627669
"This course teaches the fundamentals of HTML and CSS, including modern layout, design, accessibility, and responsive web development. You'll build practical projects and gain the skills to create professional, user-friendly webpages.",
76637670
"To qualify for the exam, you must complete the following projects:",
@@ -7673,6 +7680,14 @@
76737680
"css": "CSS",
76747681
"responsive-web-design-certification-exam": "Responsive Web Design Certification Exam"
76757682
},
7683+
"module-intros": {
7684+
"responsive-web-design-certification-exam": {
7685+
"note": "Coming Winter 2025",
7686+
"intro": [
7687+
"Pass this exam to earn your Responsive Web Design Certification."
7688+
]
7689+
}
7690+
},
76767691
"modules": {
76777692
"basic-html": "Basic HTML",
76787693
"semantic-html": "Semantic HTML",
@@ -9023,6 +9038,7 @@
90239038
"misc-text": {
90249039
"browse-other": "Browse our other free certifications",
90259040
"courses": "Courses",
9041+
"requirements": "Requirements",
90269042
"steps": "Steps",
90279043
"expand": "Expand course",
90289044
"collapse": "Collapse course",

client/i18n/locales/english/translations.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
"next-heading": "Try our beta curriculum:",
214214
"upcoming-heading": "Upcoming curriculum:",
215215
"catalog-heading": "Explore our Catalog:",
216+
"fsd-restructure-note": "If you were previously working through our Certified Full Stack Developer curriculum, don't worry - your progress is saved. We've split it into smaller certifications you can earn along your journey.",
216217
"archive-link": "Looking for older coursework? Check out <0>our archive page</0>.",
217218
"faq": "Frequently asked questions:",
218219
"faqs": [
@@ -1227,6 +1228,18 @@
12271228
"a2-english-for-developers-cert": "A2 English for Developers Certification",
12281229
"b1-english-for-developers": "B1 English for Developers",
12291230
"b1-english-for-developers-cert": "B1 English for Developers Certification",
1231+
"responsive-web-design-v9": "Responsive Web Design",
1232+
"responsive-web-design-v9-cert": "Responsive Web Design Certification",
1233+
"javascript-v9": "JavaScript",
1234+
"javascript-v9-cert": "JavaScript Certification",
1235+
"front-end-development-libraries-v9": "Front End Development Libraries",
1236+
"front-end-development-libraries-v9-cert": "Front End Development Libraries Certification",
1237+
"python-v9": "Python",
1238+
"python-v9-cert": "Python Certification",
1239+
"relational-databases-v9": "Relational Database",
1240+
"relational-databases-v9-cert": "Relational Database Certification",
1241+
"back-end-development-and-apis-v9": "Back End Development and APIs",
1242+
"back-end-development-and-apis-v9-cert": "Back End Development and APIs Certification",
12301243
"full-stack-developer-v9": "Full Stack Developer",
12311244
"full-stack-developer-v9-cert": "Full Stack Developer Certification",
12321245
"a1-professional-spanish": "A1 Professional Spanish",

client/src/components/Map/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ function Map({ forLanding = false }: MapProps) {
113113
<h2 className={forLanding ? 'big-heading' : ''}>
114114
{t(superBlockHeadings[stage])}
115115
</h2>
116+
{stage === SuperBlockStage.Core && (
117+
<p>{t('landing.fsd-restructure-note')}</p>
118+
)}
116119
<ul key={stage}>
117120
{superblocks.map(superblock => (
118121
<MapLi

client/src/templates/Introduction/components/super-block-accordion.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { type Module } from '../../../../../shared-dist/config/modules';
1818
import envData from '../../../../config/env.json';
1919
import Block from './block';
2020
import CheckMark from './check-mark';
21+
import { default as BlockLabelComponent } from './block-label';
2122

2223
import './super-block-accordion.css';
2324

@@ -107,9 +108,12 @@ const Chapter = ({
107108
</span>
108109
<ChapterIcon className='map-icon' chapter={dashedName as FsdChapters} />
109110
{chapterLabel}
111+
{isLinkChapter && examSlug && (
112+
<BlockLabelComponent blockLabel={BlockLabel.exam} />
113+
)}
110114
</div>
111115
<div className='chapter-button-right'>
112-
{!comingSoon && (
116+
{!comingSoon && !isLinkChapter && (
113117
<span className='chapter-steps'>
114118
{t('learn.steps-completed', {
115119
totalSteps,
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
import React, { useMemo } from 'react';
2+
import { useTranslation } from 'react-i18next';
3+
import { Spacer } from '@freecodecamp/ui';
4+
5+
import {
6+
certificationCollectionSuperBlocks,
7+
chapterBasedSuperBlocks,
8+
SuperBlocks
9+
} from '../../../../../shared-dist/config/curriculum';
10+
import type { CertTitle } from '../../../../config/cert-and-project-map';
11+
import type {
12+
ChapterBasedSuperBlockStructure,
13+
ClaimedCertifications,
14+
User
15+
} from '../../../redux/prop-types';
16+
import type {
17+
BlockLabel,
18+
BlockLayouts
19+
} from '../../../../../shared-dist/config/blocks';
20+
import { SuperBlockIcon } from '../../../assets/superblock-icon';
21+
import { Link } from '../../../components/helpers';
22+
import {
23+
certSlugTypeMap,
24+
certificationRequirements,
25+
superBlockToCertMap
26+
} from '../../../../../shared-dist/config/certification-settings';
27+
import CheckMark from './check-mark';
28+
29+
import Block from './block';
30+
import CertChallenge from './cert-challenge';
31+
import { SuperBlockAccordion } from './super-block-accordion';
32+
import './super-block-accordion.css';
33+
34+
type Challenge = {
35+
block: string;
36+
blockLabel: BlockLabel;
37+
blockLayout: BlockLayouts;
38+
challengeType: number;
39+
dashedName: string;
40+
fields: { slug: string };
41+
id: string;
42+
module: string;
43+
order: number;
44+
superBlock: SuperBlocks;
45+
title: string;
46+
};
47+
48+
type SuperBlockMapProps = {
49+
certification: string;
50+
completedChallengeIds: string[];
51+
disabledBlocks: string[];
52+
initialExpandedBlock: string;
53+
showCertification: boolean;
54+
structure?: ChapterBasedSuperBlockStructure;
55+
superBlock: SuperBlocks;
56+
superBlockChallenges: Challenge[];
57+
title: CertTitle;
58+
user: User | null;
59+
};
60+
61+
const BlockList = ({
62+
certification,
63+
disabledBlocks,
64+
showCertification,
65+
superBlock,
66+
superBlockChallenges,
67+
title,
68+
user
69+
}: {
70+
certification: string;
71+
disabledBlocks: string[];
72+
showCertification: boolean;
73+
superBlock: SuperBlocks;
74+
superBlockChallenges: Challenge[];
75+
title: CertTitle;
76+
user: User | null;
77+
}) => {
78+
const visibleBlocks = useMemo(() => {
79+
const uniqueBlocks = Array.from(
80+
new Set(superBlockChallenges.map(({ block }) => block))
81+
);
82+
83+
return uniqueBlocks.filter(block => !disabledBlocks.includes(block));
84+
}, [disabledBlocks, superBlockChallenges]);
85+
86+
return (
87+
<div className='block-ui'>
88+
{visibleBlocks.map(block => {
89+
const blockChallenges = superBlockChallenges.filter(
90+
challenge => challenge.block === block
91+
);
92+
const blockLabel = blockChallenges[0]?.blockLabel ?? null;
93+
94+
if (!blockChallenges.length) return null;
95+
96+
return (
97+
<Block
98+
key={block}
99+
block={block}
100+
blockLabel={blockLabel}
101+
challenges={blockChallenges}
102+
superBlock={superBlock}
103+
/>
104+
);
105+
})}
106+
{showCertification && !!user && (
107+
<CertChallenge
108+
certification={certification}
109+
superBlock={superBlock}
110+
title={title}
111+
user={user}
112+
/>
113+
)}
114+
</div>
115+
);
116+
};
117+
118+
export const SuperBlockMap = ({
119+
certification,
120+
completedChallengeIds,
121+
disabledBlocks,
122+
initialExpandedBlock,
123+
showCertification,
124+
structure,
125+
superBlock,
126+
superBlockChallenges,
127+
title,
128+
user
129+
}: SuperBlockMapProps) => {
130+
const { t } = useTranslation();
131+
if (chapterBasedSuperBlocks.includes(superBlock)) {
132+
if (!structure) return null;
133+
134+
const getRequirementItems = () => {
135+
const certificationForSuperBlock = superBlockToCertMap[superBlock];
136+
const requirementsLookup = certificationRequirements as Partial<
137+
Record<string, SuperBlocks[]>
138+
>;
139+
const requirements: SuperBlocks[] =
140+
(certificationForSuperBlock &&
141+
requirementsLookup[certificationForSuperBlock]) ??
142+
[];
143+
144+
const requirementItems = requirements.map((requirement: SuperBlocks) => {
145+
const requirementTitle = t(`intro:${requirement}.title`);
146+
const requirementLink = `/learn/${requirement}/`;
147+
148+
const certSlug = superBlockToCertMap[requirement];
149+
const certFlagLookup = certSlugTypeMap as Record<
150+
string,
151+
keyof ClaimedCertifications
152+
>;
153+
const certFlagKey = certSlug ? certFlagLookup[certSlug] : undefined;
154+
const isRequirementComplete = Boolean(
155+
certFlagKey && user?.[certFlagKey]
156+
);
157+
158+
return (
159+
<li className='chapter requirement' key={requirement}>
160+
<Link
161+
className='chapter-button'
162+
data-playwright-test-label='requirement-button'
163+
to={requirementLink}
164+
>
165+
<div className='chapter-button-left'>
166+
<span className='checkmark-wrap chapter-checkmark-wrap'>
167+
<CheckMark isCompleted={isRequirementComplete} />
168+
</span>
169+
<SuperBlockIcon className='map-icon' superBlock={requirement} />
170+
{requirementTitle}
171+
</div>
172+
</Link>
173+
</li>
174+
);
175+
});
176+
177+
return requirementItems;
178+
};
179+
180+
return (
181+
<>
182+
{certificationCollectionSuperBlocks.includes(superBlock) && (
183+
<>
184+
<ul className='super-block-accordion requirement-list'>
185+
{getRequirementItems()}
186+
</ul>
187+
<Spacer size='m' />
188+
<h2 className='text-center big-subheading'>
189+
{t(`intro:misc-text.courses`)}
190+
</h2>
191+
<Spacer size='m' />
192+
</>
193+
)}
194+
195+
<SuperBlockAccordion
196+
challenges={superBlockChallenges}
197+
superBlock={superBlock}
198+
structure={structure}
199+
chosenBlock={initialExpandedBlock}
200+
completedChallengeIds={completedChallengeIds}
201+
/>
202+
</>
203+
);
204+
}
205+
206+
return (
207+
<BlockList
208+
certification={certification}
209+
disabledBlocks={disabledBlocks}
210+
showCertification={showCertification}
211+
superBlock={superBlock}
212+
superBlockChallenges={superBlockChallenges}
213+
title={title}
214+
user={user}
215+
/>
216+
);
217+
};
218+
219+
SuperBlockMap.displayName = 'SuperBlockMap';
220+
221+
export default SuperBlockMap;

0 commit comments

Comments
 (0)