Skip to content

Commit

Permalink
feat(client/curriclum): make C# live (#51354)
Browse files Browse the repository at this point in the history
  • Loading branch information
moT01 committed Aug 27, 2023
1 parent f1ccccf commit 4ed9597
Show file tree
Hide file tree
Showing 35 changed files with 158 additions and 106 deletions.
12 changes: 7 additions & 5 deletions api-server/src/server/boot/certificate.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const {
machineLearningPyV7Id,
relationalDatabaseV8Id,
collegeAlgebraPyV8Id,
foundationalCSharpId
foundationalCSharpV8Id
} = certIds;

const log = debug('fcc:certification');
Expand Down Expand Up @@ -134,8 +134,8 @@ function createCertTypeIds(allChallenges) {
collegeAlgebraPyV8Id,
allChallenges
),
[certTypes.foundationalCSharp]: getCertById(
foundationalCSharpId,
[certTypes.foundationalCSharpV8]: getCertById(
foundationalCSharpV8Id,
allChallenges
)
};
Expand Down Expand Up @@ -174,7 +174,8 @@ function sendCertifiedEmail(
isDataAnalysisPyCertV7,
isMachineLearningPyCertV7,
isRelationalDatabaseCertV8,
isCollegeAlgebraPyCertV8
isCollegeAlgebraPyCertV8,
isFoundationalCSharpCertV8
},
send$
) {
Expand All @@ -191,7 +192,8 @@ function sendCertifiedEmail(
!isDataAnalysisPyCertV7 ||
!isMachineLearningPyCertV7 ||
!isRelationalDatabaseCertV8 ||
!isCollegeAlgebraPyCertV8
!isCollegeAlgebraPyCertV8 ||
!isFoundationalCSharpCertV8
) {
return Observable.just(false);
}
Expand Down
1 change: 1 addition & 0 deletions api-server/src/server/boot/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ function postResetProgress(req, res, next) {
isMachineLearningPyCertV7: false,
isRelationalDatabaseCertV8: false,
isCollegeAlgebraPyCertV8: false,
isFoundationalCSharpCertV8: false,
completedChallenges: [],
completedExams: [],
savedChallenges: [],
Expand Down
3 changes: 2 additions & 1 deletion api-server/src/server/utils/certTypes.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
"machineLearningPyV7": "isMachineLearningPyCertV7",
"fullStack": "isFullStackCert",
"relationalDatabaseV8": "isRelationalDatabaseV8",
"collegeAlgebraPyV8": "isCollegeAlgebraPyCertV8"
"collegeAlgebraPyV8": "isCollegeAlgebraPyCertV8",
"foundationalCSharpV8": "isFoundationalCSharpCertV8"
}
2 changes: 1 addition & 1 deletion client/config/cert-and-project-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,6 @@ const allStandardCerts = [
}
]
},
// Upcoming Certifications
{
id: '647e3159823e0ef219c7359b',
title: 'Foundational C# with Microsoft',
Expand All @@ -761,6 +760,7 @@ const allStandardCerts = [
}
]
},
// Upcoming Certifications
{
id: '64514fda6c245de4d11eb7bb',
title: 'Example Certification',
Expand Down
2 changes: 1 addition & 1 deletion client/i18n/locales/english/intro.json
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,7 @@
}
},
"foundational-c-sharp-with-microsoft": {
"title": "Foundational C# with Microsoft",
"title": "(New) Foundational C# with Microsoft",
"intro": [
"This course offers a comprehensive introduction to C# programming, covering its core concepts, syntax, and practical application in software development.",
"Through hands-on exercises and projects, you will learn the fundamentals of C#, including variables, data types, control structures, and object-oriented programming principles.",
Expand Down
3 changes: 3 additions & 0 deletions client/i18n/locales/english/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@
}
},
"certification-heading": "Earn free verified certifications in:",
"core-certs-heading": "Earn free verified certifications with freeCodeCamp's core curriculum:",
"professional-certs-heading": "Earn free professional certifications:",
"interview-prep-heading": "Prepare for the developer interview job search:",
"faq": "Frequently asked questions:",
"faqs": [
{
Expand Down
2 changes: 1 addition & 1 deletion client/src/client-only-routes/show-certification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ const ShowCertification = (props: ShowCertificationProps): JSX.Element => {
);

const isMicrosoftCert =
certTitle === certTypeTitleMap[certTypes.foundationalCSharp];
certTitle === certTypeTitleMap[certTypes.foundationalCSharpV8];

return (
<Container className='certificate-outer-wrapper'>
Expand Down
2 changes: 1 addition & 1 deletion client/src/client-only-routes/show-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element {
isDataAnalysisPyCertV7={isDataAnalysisPyCertV7}
isDataVisCert={isDataVisCert}
isCollegeAlgebraPyCertV8={isCollegeAlgebraPyCertV8}
isFoundationalCSharpCertV8={isFoundationalCSharpCertV8}
isFrontEndCert={isFrontEndCert}
isFrontEndLibsCert={isFrontEndLibsCert}
isFullStackCert={isFullStackCert}
Expand All @@ -225,7 +226,6 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element {
isRelationalDatabaseCertV8={isRelationalDatabaseCertV8}
isRespWebDesignCert={isRespWebDesignCert}
isSciCompPyCertV7={isSciCompPyCertV7}
isFoundationalCSharpCertV8={isFoundationalCSharpCertV8}
username={username}
verifyCert={verifyCert}
/>
Expand Down
41 changes: 34 additions & 7 deletions client/src/components/Map/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import i18next from 'i18next';
import React from 'react';
import { useTranslation } from 'react-i18next';

import {
SuperBlockStages,
SuperBlocks,
createFlatSuperBlockMap,
getFirstNotAuditedSuperBlock
getFirstNotAuditedSuperBlock,
superBlockOrder
} from '../../../../config/superblocks';
import { generateIconComponent } from '../../assets/icons';
import LinkButton from '../../assets/icons/link-button';
Expand All @@ -29,16 +31,18 @@ const linkSpacingStyle = {
gap: '15px'
};

const flatSuperBlockMap = createFlatSuperBlockMap({
showNewCurriculum,
showUpcomingChanges
});
const firstNotAuditedSuperBlock = getFirstNotAuditedSuperBlock({
language: curriculumLocale,
showNewCurriculum,
showUpcomingChanges
});

const coreCurriculum = [
...superBlockOrder[SuperBlockStages.FrontEnd],
...superBlockOrder[SuperBlockStages.Backend],
...superBlockOrder[SuperBlockStages.Python]
];

function MapLi({
superBlock,
landing = false
Expand Down Expand Up @@ -81,10 +85,33 @@ function MapLi({
}

function Map({ forLanding = false }: MapProps): React.ReactElement {
const { t } = useTranslation();

return (
<div className='map-ui' data-test-label='curriculum-map'>
<h1 className={forLanding ? 'big-heading' : ''}>
{t('landing.core-certs-heading')}
</h1>
<ul>
{coreCurriculum.map((superBlock, i) => (
<MapLi key={i} superBlock={superBlock} landing={forLanding} />
))}
</ul>
<Spacer size='medium' />
<h1 className={forLanding ? 'big-heading' : ''}>
{t('landing.professional-certs-heading')}
</h1>
<ul>
{superBlockOrder[SuperBlockStages.Professional].map((superBlock, i) => (
<MapLi key={i} superBlock={superBlock} landing={forLanding} />
))}
</ul>
<Spacer size='medium' />
<h1 className={forLanding ? 'big-heading' : ''}>
{t('landing.interview-prep-heading')}
</h1>
<ul>
{flatSuperBlockMap.map((superBlock, i) => (
{superBlockOrder[SuperBlockStages.Extra].map((superBlock, i) => (
<MapLi key={i} superBlock={superBlock} landing={forLanding} />
))}
</ul>
Expand Down
4 changes: 0 additions & 4 deletions client/src/components/landing/components/certifications.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { Col } from '@freecodecamp/react-bootstrap';
import React from 'react';
import { useTranslation } from 'react-i18next';
import Map from '../../Map/index';
import { Spacer } from '../../helpers';
import BigCallToAction from './big-call-to-action';

const Certifications = (): JSX.Element => {
const { t } = useTranslation();

return (
<Col
className='certification-section'
Expand All @@ -17,7 +14,6 @@ const Certifications = (): JSX.Element => {
smOffset={1}
xs={12}
>
<h1 className='big-heading'>{t('landing.certification-heading')}</h1>
<Map forLanding={true} />
<Spacer size='medium' />
<BigCallToAction />
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/profile/profile.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ const userProps = {
isDataAnalysisPyCertV7: true,
isMachineLearningPyCertV7: true,
isRelationalDatabaseCertV8: true,
isCollegeAlgebraPyCertV8: true
isCollegeAlgebraPyCertV8: true,
isFoundationalCSharpVertV8: true
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
navigate: () => {}
Expand Down
1 change: 1 addition & 0 deletions client/src/components/settings/certification.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ const defaultTestProps = {
isMachineLearningPyCertV7: false,
isRelationalDatabaseCertV8: false,
isCollegeAlgebraPyCertV8: false,
isFoundationalCSharpCertV8: false,
username: 'developmentuser',
verifyCert: verifyCert,
isEmailVerified: false
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/settings/certification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ const isCertMapSelector = createSelector(
'Machine Learning with Python': isMachineLearningPyCertV7,
'Relational Database': isRelationalDatabaseCertV8,
'College Algebra with Python': isCollegeAlgebraPyCertV8,
'Foundational C# with Microsoft': isFoundationalCSharpCertV8,
'Legacy Front End': isFrontEndCert,
'Legacy Data Visualization': isDataVisCert,
'Legacy Back End': isBackEndCert,
'Legacy Information Security and Quality Assurance': isInfosecQaCert,
'Foundational C# with Microsoft': isFoundationalCSharpCertV8,
// TODO: remove Example Certification? Also, include Upcoming Python
// Certification.
'Example Certification': false,
Expand Down
5 changes: 3 additions & 2 deletions client/src/pages/certification.css
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,15 @@

.certification-namespace .dual-logo svg {
max-width: 70%;
height: auto;
}

.certification-namespace .fcc-logo svg {
max-width: 350px;
width: 350px;
}

.certification-namespace .ms-logo svg {
max-width: 300px;
width: 300px;
}

.certification-namespace .information {
Expand Down
50 changes: 31 additions & 19 deletions client/src/redux/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,26 +317,38 @@ export const reducer = handleActions(
submittedchallenges = submittedChallenge.challArray;
}
const { appUsername } = state;
return {
...state,
completionCount: state.completionCount + 1,
user: {
...state.user,
[appUsername]: {
...state.user[appUsername],
completedChallenges: uniqBy(
[
...submittedchallenges,
...state.user[appUsername].completedChallenges
],
'id'
),
savedChallenges:
savedChallenges ?? savedChallengesSelector(state[MainApp]),
examResults

return examResults && !examResults.passed
? {
...state,
user: {
...state.user,
[appUsername]: {
...state.user[appUsername],
examResults
}
}
}
}
};
: {
...state,
completionCount: state.completionCount + 1,
user: {
...state.user,
[appUsername]: {
...state.user[appUsername],
completedChallenges: uniqBy(
[
...submittedchallenges,
...state.user[appUsername].completedChallenges
],
'id'
),
savedChallenges:
savedChallenges ?? savedChallengesSelector(state[MainApp]),
examResults
}
}
};
},
[actionTypes.setMsUsername]: (state, { payload }) => {
const { appUsername } = state;
Expand Down
2 changes: 1 addition & 1 deletion client/src/redux/prop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ export type ClaimedCertifications = {
isDataVisCert: boolean;
isEmailVerified: boolean;
isCollegeAlgebraPyCertV8: boolean;
isFoundationalCSharpCertV8: boolean;
isFrontEndCert: boolean;
isFrontEndLibsCert: boolean;
isFullStackCert: boolean;
Expand All @@ -265,7 +266,6 @@ export type ClaimedCertifications = {
isSciCompPyCertV7: boolean;
isDataAnalysisPyCertV7: boolean;
isMachineLearningPyCertV7: boolean;
isFoundationalCSharpCertV8: boolean;
};

type SavedChallenges = SavedChallenge[];
Expand Down
11 changes: 9 additions & 2 deletions client/src/redux/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ export const certificatesByNameSelector = username => state => {
isDataAnalysisPyCertV7,
isMachineLearningPyCertV7,
isRelationalDatabaseCertV8,
isCollegeAlgebraPyCertV8
isCollegeAlgebraPyCertV8,
isFoundationalCSharpCertV8
} = userByNameSelector(username)(state);
return {
hasModernCert:
Expand All @@ -140,7 +141,8 @@ export const certificatesByNameSelector = username => state => {
isDataAnalysisPyCertV7 ||
isMachineLearningPyCertV7 ||
isRelationalDatabaseCertV8 ||
isCollegeAlgebraPyCertV8,
isCollegeAlgebraPyCertV8 ||
isFoundationalCSharpCertV8,
hasLegacyCert:
isFrontEndCert || isBackEndCert || isDataVisCert || isInfosecQaCert,
isFullStackCert,
Expand Down Expand Up @@ -204,6 +206,11 @@ export const certificatesByNameSelector = username => state => {
show: isCollegeAlgebraPyCertV8,
title: 'College Algebra with Python Certification',
certSlug: Certification.CollegeAlgebraPy
},
{
show: isFoundationalCSharpCertV8,
title: 'Foundational C# with Microsoft Certification',
certSlug: Certification.FoundationalCSharp
}
],
legacyCerts: [
Expand Down
Loading

0 comments on commit 4ed9597

Please sign in to comment.