From ca02bcb7ee8761cb8bf9a8d61e097134766bbf9d Mon Sep 17 00:00:00 2001 From: Shaun Hamilton Date: Wed, 15 Oct 2025 18:06:42 +0200 Subject: [PATCH] feat(api,client): add rwd and js v9 certs (#62458) --- api/prisma/schema.prisma | 6 ++++-- api/src/plugins/__fixtures__/user.ts | 2 ++ api/src/routes/helpers/user-utils.ts | 2 ++ api/src/routes/protected/certificate.test.ts | 5 +++++ api/src/routes/protected/certificate.ts | 20 +++++++++++++++---- api/src/routes/protected/user.test.ts | 6 ++++++ api/src/routes/protected/user.ts | 2 ++ api/src/routes/public/certificate.ts | 2 ++ api/src/routes/public/user.test.ts | 2 ++ api/src/schemas/types.ts | 2 ++ api/src/schemas/user/get-session-user.ts | 2 ++ api/src/schemas/users/get-public-profile.ts | 2 ++ api/src/utils/create-user.ts | 2 ++ client/config/cert-and-project-map.ts | 4 ++-- client/i18n/locales/english/translations.json | 1 + .../src/client-only-routes/show-settings.tsx | 4 ++++ .../profile/components/utils/certification.ts | 14 +++++++++++++ .../src/components/profile/profile.test.tsx | 2 ++ .../settings/certification.test.tsx | 2 ++ .../src/components/settings/certification.tsx | 6 ++++-- .../solution-display-widget/index.tsx | 10 ++++++++-- client/src/redux/prop-types.ts | 2 ++ client/src/utils/solution-display-type.ts | 5 ++++- .../68db37350b398ecddd1f5dac.md | 2 +- shared/config/certification-settings.ts | 20 ++++++++++++++----- tools/scripts/seed/user-data.js | 2 ++ 26 files changed, 110 insertions(+), 19 deletions(-) diff --git a/api/prisma/schema.prisma b/api/prisma/schema.prisma index 19365d98c78..dde5727582e 100644 --- a/api/prisma/schema.prisma +++ b/api/prisma/schema.prisma @@ -119,12 +119,14 @@ model user { isHonest Boolean? isInfosecCertV7 Boolean? // Undefined isInfosecQaCert Boolean? // Undefined + isJavascriptCertV9 Boolean? // Undefined isJsAlgoDataStructCert Boolean? // Undefined isJsAlgoDataStructCertV8 Boolean? // Undefined isMachineLearningPyCertV7 Boolean? // Undefined isQaCertV7 Boolean? // Undefined isRelationalDatabaseCertV8 Boolean? // Undefined isRespWebDesignCert Boolean? // Undefined + isRespWebDesignCertV9 Boolean? // Undefined isSciCompPyCertV7 Boolean? // Undefined is2018DataVisCert Boolean? // Undefined is2018FullStackCert Boolean? // Undefined @@ -166,8 +168,8 @@ model user { isClassroomAccount Boolean? // Undefined // Relations - examAttempts ExamEnvironmentExamAttempt[] - examEnvironmentAuthorizationToken ExamEnvironmentAuthorizationToken? + examAttempts ExamEnvironmentExamAttempt[] + examEnvironmentAuthorizationToken ExamEnvironmentAuthorizationToken? } // ----------------------------------- diff --git a/api/src/plugins/__fixtures__/user.ts b/api/src/plugins/__fixtures__/user.ts index 18164ea4085..b37c81da212 100644 --- a/api/src/plugins/__fixtures__/user.ts +++ b/api/src/plugins/__fixtures__/user.ts @@ -43,6 +43,7 @@ export const newUser = (email: string) => ({ isHonest: false, isInfosecCertV7: false, isInfosecQaCert: false, + isJavascriptCertV9: false, isJsAlgoDataStructCert: false, isJsAlgoDataStructCertV8: false, isMachineLearningPyCertV7: false, @@ -50,6 +51,7 @@ export const newUser = (email: string) => ({ isRelationalDatabaseCertV8: false, isCollegeAlgebraPyCertV8: false, isRespWebDesignCert: false, + isRespWebDesignCertV9: false, isSciCompPyCertV7: false, keyboardShortcuts: false, linkedin: null, diff --git a/api/src/routes/helpers/user-utils.ts b/api/src/routes/helpers/user-utils.ts index 3d5ee9d8d60..8c6c2c13857 100644 --- a/api/src/routes/helpers/user-utils.ts +++ b/api/src/routes/helpers/user-utils.ts @@ -18,6 +18,7 @@ const nullableFlags = [ 'isFrontEndCert', 'isFullStackCert', 'isFrontEndLibsCert', + 'isJavascriptCertV9', 'isHonest', 'isInfosecCertV7', 'isInfosecQaCert', @@ -27,6 +28,7 @@ const nullableFlags = [ 'isQaCertV7', 'isRelationalDatabaseCertV8', 'isRespWebDesignCert', + 'isRespWebDesignCertV9', 'isSciCompPyCertV7', 'isDataAnalysisPyCertV7', // isUpcomingPythonCertV8 exists in the db, but is not returned by the api-server diff --git a/api/src/routes/protected/certificate.test.ts b/api/src/routes/protected/certificate.test.ts index a959088c91f..d0d0c007fa0 100644 --- a/api/src/routes/protected/certificate.test.ts +++ b/api/src/routes/protected/certificate.test.ts @@ -293,6 +293,8 @@ describe('certificate routes', () => { }, isCertMap: { isRespWebDesignCert: true, + isRespWebDesignCertV9: false, + isJavascriptCertV9: false, isJsAlgoDataStructCert: false, isFrontEndLibsCert: false, is2018DataVisCert: false, @@ -354,6 +356,9 @@ describe('certificate routes', () => { test('should return 400 if certSlug is not allowed', async () => { const claimableCerts = [ Certification.RespWebDesign, + // TODO: Enable, once these are no longer "upcoming". + // Certification.RespWebDesignV9, + // Certification.JsV9, Certification.JsAlgoDataStruct, Certification.FrontEndDevLibs, Certification.DataVis, diff --git a/api/src/routes/protected/certificate.ts b/api/src/routes/protected/certificate.ts index bd9514da38e..95b1dad59cd 100644 --- a/api/src/routes/protected/certificate.ts +++ b/api/src/routes/protected/certificate.ts @@ -28,6 +28,7 @@ const { legacyFullStackId, respWebDesignId, frontEndDevLibsId, + javascriptV9Id, jsAlgoDataStructId, jsAlgoDataStructV8Id, dataVis2018Id, @@ -38,6 +39,7 @@ const { dataAnalysisPyV7Id, machineLearningPyV7Id, relationalDatabaseV8Id, + respWebDesignV9Id, collegeAlgebraPyV8Id, foundationalCSharpV8Id } = certIds; @@ -156,7 +158,9 @@ function createCertTypeIds(challenges: ReturnType) { [certTypes.foundationalCSharpV8]: getCertById( foundationalCSharpV8Id, challenges - ) + ), + [certTypes.javascriptV9]: getCertById(javascriptV9Id, challenges), + [certTypes.respWebDesignV9]: getCertById(respWebDesignV9Id, challenges) // upcoming }; @@ -182,6 +186,8 @@ interface CertI { isRelationalDatabaseCertV8?: boolean; isCollegeAlgebraPyCertV8?: boolean; isFoundationalCSharpCertV8?: boolean; + isJavascriptCertV9?: boolean; + isRespWebDesignCertV9?: boolean; } function getUserIsCertMap(user: CertI) { @@ -204,7 +210,9 @@ function getUserIsCertMap(user: CertI) { isMachineLearningPyCertV7 = false, isRelationalDatabaseCertV8 = false, isCollegeAlgebraPyCertV8 = false, - isFoundationalCSharpCertV8 = false + isFoundationalCSharpCertV8 = false, + isJavascriptCertV9 = false, + isRespWebDesignCertV9 = false } = user; return { @@ -226,7 +234,9 @@ function getUserIsCertMap(user: CertI) { isMachineLearningPyCertV7, isRelationalDatabaseCertV8, isCollegeAlgebraPyCertV8, - isFoundationalCSharpCertV8 + isFoundationalCSharpCertV8, + isJavascriptCertV9, + isRespWebDesignCertV9 }; } @@ -390,7 +400,9 @@ export const protectedCertificateRoutes: FastifyPluginCallbackTypebox = ( isQaCertV7: true, isRelationalDatabaseCertV8: true, isRespWebDesignCert: true, - isSciCompPyCertV7: true + isSciCompPyCertV7: true, + isJavascriptCertV9: true, + isRespWebDesignCertV9: true } }); diff --git a/api/src/routes/protected/user.test.ts b/api/src/routes/protected/user.test.ts index 7f98c0f4bdc..71d1e21ba46 100644 --- a/api/src/routes/protected/user.test.ts +++ b/api/src/routes/protected/user.test.ts @@ -288,12 +288,14 @@ const publicUserData = { isHonest: testUserData.isHonest, isInfosecCertV7: testUserData.isInfosecCertV7, isInfosecQaCert: testUserData.isInfosecQaCert, + isJavascriptCertV9: testUserData.isJavascriptCertV9, isJsAlgoDataStructCert: testUserData.isJsAlgoDataStructCert, isJsAlgoDataStructCertV8: testUserData.isJsAlgoDataStructCertV8, isMachineLearningPyCertV7: testUserData.isMachineLearningPyCertV7, isQaCertV7: testUserData.isQaCertV7, isRelationalDatabaseCertV8: testUserData.isRelationalDatabaseCertV8, isRespWebDesignCert: testUserData.isRespWebDesignCert, + isRespWebDesignCertV9: testUserData.isRespWebDesignCertV9, isSciCompPyCertV7: testUserData.isSciCompPyCertV7, linkedin: testUserData.linkedin, location: testUserData.location, @@ -337,10 +339,12 @@ const baseProgressData = { isBackEndCert: false, isDataVisCert: false, isFullStackCert: false, + isJavascriptCertV9: false, isSciCompPyCertV7: false, isDataAnalysisPyCertV7: false, isMachineLearningPyCertV7: false, isRelationalDatabaseCertV8: false, + isRespWebDesignCertV9: false, isCollegeAlgebraPyCertV8: false, completedChallenges: [], completedDailyCodingChallenges: [], @@ -1004,6 +1008,7 @@ describe('userRoutes', () => { isFrontEndCert: false, isFrontEndLibsCert: false, isFullStackCert: false, + isJavascriptCertV9: false, isHonest: false, isInfosecCertV7: false, isInfosecQaCert: false, @@ -1013,6 +1018,7 @@ describe('userRoutes', () => { isQaCertV7: false, isRelationalDatabaseCertV8: false, isRespWebDesignCert: false, + isRespWebDesignCertV9: false, isSciCompPyCertV7: false, keyboardShortcuts: false, location: '', diff --git a/api/src/routes/protected/user.ts b/api/src/routes/protected/user.ts index 253980f2268..de2c6cfc4c6 100644 --- a/api/src/routes/protected/user.ts +++ b/api/src/routes/protected/user.ts @@ -681,12 +681,14 @@ export const userGetRoutes: FastifyPluginCallbackTypebox = ( isHonest: true, isInfosecCertV7: true, isInfosecQaCert: true, + isJavascriptCertV9: true, isJsAlgoDataStructCert: true, isJsAlgoDataStructCertV8: true, isMachineLearningPyCertV7: true, isQaCertV7: true, isRelationalDatabaseCertV8: true, isRespWebDesignCert: true, + isRespWebDesignCertV9: true, isSciCompPyCertV7: true, keyboardShortcuts: true, linkedin: true, diff --git a/api/src/routes/public/certificate.ts b/api/src/routes/public/certificate.ts index 64923c6e715..51d5f74acc5 100644 --- a/api/src/routes/public/certificate.ts +++ b/api/src/routes/public/certificate.ts @@ -64,7 +64,9 @@ export const unprotectedCertificateRoutes: FastifyPluginCallbackTypebox = ( isBackEndCert: true, isFullStackCert: true, isRespWebDesignCert: true, + isRespWebDesignCertV9: true, isFrontEndLibsCert: true, + isJavascriptCertV9: true, isJsAlgoDataStructCert: true, isJsAlgoDataStructCertV8: true, isDataVisCert: true, diff --git a/api/src/routes/public/user.test.ts b/api/src/routes/public/user.test.ts index fd7bc420b00..5182200e207 100644 --- a/api/src/routes/public/user.test.ts +++ b/api/src/routes/public/user.test.ts @@ -198,6 +198,7 @@ const publicUserData = { isFrontEndCert: testUserData.isFrontEndCert, isFrontEndLibsCert: testUserData.isFrontEndLibsCert, isFullStackCert: testUserData.isFullStackCert, + isJavascriptCertV9: testUserData.isJavascriptCertV9, isHonest: testUserData.isHonest, isInfosecCertV7: testUserData.isInfosecCertV7, isInfosecQaCert: testUserData.isInfosecQaCert, @@ -207,6 +208,7 @@ const publicUserData = { isQaCertV7: testUserData.isQaCertV7, isRelationalDatabaseCertV8: testUserData.isRelationalDatabaseCertV8, isRespWebDesignCert: testUserData.isRespWebDesignCert, + isRespWebDesignCertV9: testUserData.isRespWebDesignCertV9, isSciCompPyCertV7: testUserData.isSciCompPyCertV7, linkedin: testUserData.linkedin, location: testUserData.location, diff --git a/api/src/schemas/types.ts b/api/src/schemas/types.ts index 94e90db0ff7..4f73088adc3 100644 --- a/api/src/schemas/types.ts +++ b/api/src/schemas/types.ts @@ -7,6 +7,8 @@ export const genericError = Type.Object({ export const isCertMap = Type.Object({ isRespWebDesignCert: Type.Boolean(), + isRespWebDesignCertV9: Type.Boolean(), + isJavascriptCertV9: Type.Boolean(), isJsAlgoDataStructCert: Type.Boolean(), isFrontEndLibsCert: Type.Boolean(), is2018DataVisCert: Type.Boolean(), diff --git a/api/src/schemas/user/get-session-user.ts b/api/src/schemas/user/get-session-user.ts index 8bfcb5d3ce2..dc665286633 100644 --- a/api/src/schemas/user/get-session-user.ts +++ b/api/src/schemas/user/get-session-user.ts @@ -79,6 +79,7 @@ export const getSessionUser = { isFrontEndCert: Type.Boolean(), isFrontEndLibsCert: Type.Boolean(), isFullStackCert: Type.Boolean(), + isJavascriptCertV9: Type.Boolean(), isHonest: Type.Boolean(), isInfosecCertV7: Type.Boolean(), isInfosecQaCert: Type.Boolean(), @@ -88,6 +89,7 @@ export const getSessionUser = { isQaCertV7: Type.Boolean(), isRelationalDatabaseCertV8: Type.Boolean(), isRespWebDesignCert: Type.Boolean(), + isRespWebDesignCertV9: Type.Boolean(), isSciCompPyCertV7: Type.Boolean(), keyboardShortcuts: Type.Boolean(), linkedin: Type.Optional(Type.String()), diff --git a/api/src/schemas/users/get-public-profile.ts b/api/src/schemas/users/get-public-profile.ts index 96e6039a2a2..e8f8856836a 100644 --- a/api/src/schemas/users/get-public-profile.ts +++ b/api/src/schemas/users/get-public-profile.ts @@ -64,6 +64,7 @@ export const getPublicProfile = { isFrontEndCert: Type.Boolean(), isFrontEndLibsCert: Type.Boolean(), isFullStackCert: Type.Boolean(), + isJavascriptCertV9: Type.Boolean(), isHonest: Type.Boolean(), isInfosecCertV7: Type.Boolean(), isInfosecQaCert: Type.Boolean(), @@ -73,6 +74,7 @@ export const getPublicProfile = { isQaCertV7: Type.Boolean(), isRelationalDatabaseCertV8: Type.Boolean(), isRespWebDesignCert: Type.Boolean(), + isRespWebDesignCertV9: Type.Boolean(), isSciCompPyCertV7: Type.Boolean(), linkedin: Type.Optional(Type.String()), location: Type.String(), diff --git a/api/src/utils/create-user.ts b/api/src/utils/create-user.ts index 52c08e3d58e..07b0124417d 100644 --- a/api/src/utils/create-user.ts +++ b/api/src/utils/create-user.ts @@ -27,12 +27,14 @@ export const createResetProperties = () => ({ isFullStackCert: false, isInfosecCertV7: false, isInfosecQaCert: false, + isJavascriptCertV9: false, isJsAlgoDataStructCert: false, isJsAlgoDataStructCertV8: false, isMachineLearningPyCertV7: false, isQaCertV7: false, isRelationalDatabaseCertV8: false, isRespWebDesignCert: false, + isRespWebDesignCertV9: false, isSciCompPyCertV7: false, needsModeration: false, partiallyCompletedChallenges: [], // TODO(Post-MVP): Omit this from the document? (prisma will always return []) diff --git a/client/config/cert-and-project-map.ts b/client/config/cert-and-project-map.ts index 8191072a90e..8ef9f35548a 100644 --- a/client/config/cert-and-project-map.ts +++ b/client/config/cert-and-project-map.ts @@ -827,7 +827,7 @@ const allStandardCerts = [ { id: '68db37350b398ecddd1f5dac', title: 'Responsive Web Design Certification Exam', - link: `${respWebV9Base}/responsive-web-design-certification-exam/exam-responsive-web-design-certification`, + link: `${respWebV9Base}/exam-responsive-web-design-certification/exam-responsive-web-design-certification`, certSlug: Certification.RespWebDesignV9 } ] @@ -838,7 +838,7 @@ const allStandardCerts = [ certSlug: Certification.JsV9, projects: [ { - id: '645147516c245de4d11eb7ba', + id: '68c462d7dc707f3ca82f8e6d', title: 'JavaScript Certification Exam', link: `${jsV9Base}/exam-javascript-certification/exam-javascript-certification`, certSlug: Certification.JsV9 diff --git a/client/i18n/locales/english/translations.json b/client/i18n/locales/english/translations.json index a06bef8f4a9..94d4350c6fe 100644 --- a/client/i18n/locales/english/translations.json +++ b/client/i18n/locales/english/translations.json @@ -1103,6 +1103,7 @@ "heading": "As part of this certification, {{user}} built the following projects and got all automated test suites to pass:", "solution": "Solution", "no-solution": "error displaying solution, email support@freeCodeCamp.org to get help.", + "no-solution-to-display": "No solution to display", "source": "Source", "footnote": "If you suspect that any of these projects violate the <2>academic honesty policy, please <5>report this to our team.", "title": { diff --git a/client/src/client-only-routes/show-settings.tsx b/client/src/client-only-routes/show-settings.tsx index 92919a5364f..7fec556bced 100644 --- a/client/src/client-only-routes/show-settings.tsx +++ b/client/src/client-only-routes/show-settings.tsx @@ -123,6 +123,7 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element { email, is2018DataVisCert, isApisMicroservicesCert, + isJavascriptCertV9, isJsAlgoDataStructCert, isBackEndCert, isDataVisCert, @@ -133,6 +134,7 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element { isFrontEndLibsCert, isFullStackCert, isRespWebDesignCert, + isRespWebDesignCertV9, isSciCompPyCertV7, isDataAnalysisPyCertV7, isMachineLearningPyCertV7, @@ -197,6 +199,7 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element { isFrontEndCert={isFrontEndCert} isFrontEndLibsCert={isFrontEndLibsCert} isFullStackCert={isFullStackCert} + isJavascriptCertV9={isJavascriptCertV9} isHonest={isHonest} isInfosecCertV7={isInfosecCertV7} isInfosecQaCert={isInfosecQaCert} @@ -205,6 +208,7 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element { isQaCertV7={isQaCertV7} isRelationalDatabaseCertV8={isRelationalDatabaseCertV8} isRespWebDesignCert={isRespWebDesignCert} + isRespWebDesignCertV9={isRespWebDesignCertV9} isSciCompPyCertV7={isSciCompPyCertV7} isJsAlgoDataStructCertV8={isJsAlgoDataStructCertV8} username={username} diff --git a/client/src/components/profile/components/utils/certification.ts b/client/src/components/profile/components/utils/certification.ts index a41ed424b6f..b371d549699 100644 --- a/client/src/components/profile/components/utils/certification.ts +++ b/client/src/components/profile/components/utils/certification.ts @@ -4,8 +4,10 @@ import { User } from '../../../../redux/prop-types'; export const getCertifications = (user: User) => { const { isRespWebDesignCert, + isRespWebDesignCertV9, is2018DataVisCert, isFrontEndLibsCert, + isJavascriptCertV9, isJsAlgoDataStructCert, isApisMicroservicesCert, isInfosecQaCert, @@ -27,6 +29,7 @@ export const getCertifications = (user: User) => { return { hasModernCert: isRespWebDesignCert || + isRespWebDesignCertV9 || is2018DataVisCert || isFrontEndLibsCert || isApisMicroservicesCert || @@ -39,6 +42,7 @@ export const getCertifications = (user: User) => { isRelationalDatabaseCertV8 || isCollegeAlgebraPyCertV8 || isFoundationalCSharpCertV8 || + isJavascriptCertV9 || isJsAlgoDataStructCertV8, hasLegacyCert: isFrontEndCert || @@ -53,6 +57,16 @@ export const getCertifications = (user: User) => { title: 'Responsive Web Design Certification', certSlug: Certification.RespWebDesign }, + { + show: isRespWebDesignCertV9, + title: 'Responsive Web Design Certification', + certSlug: Certification.RespWebDesignV9 + }, + { + show: isJavascriptCertV9, + title: 'JavaScript Certification', + certSlug: Certification.JsV9 + }, { show: isJsAlgoDataStructCertV8, title: 'JavaScript Algorithms and Data Structures Certification', diff --git a/client/src/components/profile/profile.test.tsx b/client/src/components/profile/profile.test.tsx index da53c976cbd..cbdd4da2fee 100644 --- a/client/src/components/profile/profile.test.tsx +++ b/client/src/components/profile/profile.test.tsx @@ -64,8 +64,10 @@ const userProps = { isInfosecQaCert: true, isQaCertV7: true, isInfosecCertV7: true, + isJavascriptCertV9: true, isJsAlgoDataStructCert: true, isRespWebDesignCert: true, + isRespWebDesignCertV9: true, isSciCompPyCertV7: true, isDataAnalysisPyCertV7: true, isMachineLearningPyCertV7: true, diff --git a/client/src/components/settings/certification.test.tsx b/client/src/components/settings/certification.test.tsx index 8531949fa5f..b655f8eafd3 100644 --- a/client/src/components/settings/certification.test.tsx +++ b/client/src/components/settings/certification.test.tsx @@ -272,9 +272,11 @@ const defaultTestProps = { isInfosecQaCert: false, isQaCertV7: false, isInfosecCertV7: false, + isJavascriptCertV9: false, isJsAlgoDataStructCert: false, isJsAlgoDataStructCertV8: false, isRespWebDesignCert: false, + isRespWebDesignCertV9: false, isSciCompPyCertV7: false, isDataAnalysisPyCertV7: false, isMachineLearningPyCertV7: false, diff --git a/client/src/components/settings/certification.tsx b/client/src/components/settings/certification.tsx index 06b8a791dec..12c91d9e7c7 100644 --- a/client/src/components/settings/certification.tsx +++ b/client/src/components/settings/certification.tsx @@ -48,12 +48,14 @@ const mapDispatchToProps = { const createCertifiedMap = ({ is2018DataVisCert, isApisMicroservicesCert, + isJavascriptCertV9, isJsAlgoDataStructCert, isInfosecQaCert, isQaCertV7, isInfosecCertV7, isFrontEndLibsCert, isRespWebDesignCert, + isRespWebDesignCertV9, isDataVisCert, isFrontEndCert, isBackEndCert, @@ -89,8 +91,8 @@ const createCertifiedMap = ({ // be rendered. The new FullStackDeveloper certification is a normal // certification with projects. [Certification.FullStackDeveloper]: false, - [Certification.RespWebDesignV9]: false, - [Certification.JsV9]: false, + [Certification.RespWebDesignV9]: isRespWebDesignCertV9, + [Certification.JsV9]: isJavascriptCertV9, [Certification.FrontEndDevLibsV9]: false, [Certification.PythonV9]: false, [Certification.RelationalDbV9]: false, diff --git a/client/src/components/solution-display-widget/index.tsx b/client/src/components/solution-display-widget/index.tsx index 6efad209c5b..1fac7909bb4 100644 --- a/client/src/components/solution-display-widget/index.tsx +++ b/client/src/components/solution-display-widget/index.tsx @@ -194,6 +194,10 @@ export function SolutionDisplayWidget({ <>{t('certification.project.no-solution')} ) : null; + const NoSolutionToDisplay = ( + <> {t('certification.project.no-solution-to-display')} + ); + const displayComponents = displayContext === 'certification' ? { @@ -202,7 +206,8 @@ export function SolutionDisplayWidget({ showProjectAndGithubLinks: ShowProjectAndGithubLinkForCertification, showProjectLink: ShowProjectLinkForCertification, showExamResults: ShowExamResults, - none: MissingSolutionComponentForCertification + none: MissingSolutionComponentForCertification, + noSolutionToDisplay: NoSolutionToDisplay } : { showUserCode: ShowUserCode, @@ -210,7 +215,8 @@ export function SolutionDisplayWidget({ showProjectAndGithubLinks: ShowProjectAndGithubLinks, showProjectLink: ShowProjectLink, showExamResults: ShowExamResults, - none: MissingSolutionComponent + none: MissingSolutionComponent, + noSolutionToDisplay: NoSolutionToDisplay }; return displayComponents[getSolutionDisplayType(completedChallenge)]; diff --git a/client/src/redux/prop-types.ts b/client/src/redux/prop-types.ts index f83ef4c80ec..217710814b5 100644 --- a/client/src/redux/prop-types.ts +++ b/client/src/redux/prop-types.ts @@ -442,11 +442,13 @@ export type ClaimedCertifications = { isFrontEndLibsCert: boolean; isFullStackCert: boolean; isInfosecQaCert: boolean; + isJavascriptCertV9: boolean; isQaCertV7: boolean; isInfosecCertV7: boolean; isJsAlgoDataStructCert: boolean; isRelationalDatabaseCertV8: boolean; isRespWebDesignCert: boolean; + isRespWebDesignCertV9: boolean; isSciCompPyCertV7: boolean; isDataAnalysisPyCertV7: boolean; isMachineLearningPyCertV7: boolean; diff --git a/client/src/utils/solution-display-type.ts b/client/src/utils/solution-display-type.ts index a5086f51144..7ec92065c2a 100644 --- a/client/src/utils/solution-display-type.ts +++ b/client/src/utils/solution-display-type.ts @@ -8,7 +8,8 @@ type DisplayType = | 'showUserCode' | 'showProjectAndGithubLinks' | 'showProjectLink' - | 'showExamResults'; + | 'showExamResults' + | 'noSolutionToDisplay'; export const getSolutionDisplayType = ({ solution, @@ -17,6 +18,8 @@ export const getSolutionDisplayType = ({ challengeType, examResults }: CompletedChallenge): DisplayType => { + if (challengeType === challengeTypes.examDownload) + return 'noSolutionToDisplay'; if (examResults) return 'showExamResults'; if (challengeFiles?.length) return challengeType === challengeTypes.multifileCertProject diff --git a/curriculum/challenges/english/blocks/exam-responsive-web-design-certification/68db37350b398ecddd1f5dac.md b/curriculum/challenges/english/blocks/exam-responsive-web-design-certification/68db37350b398ecddd1f5dac.md index 71ad25d8e34..78157b567bc 100644 --- a/curriculum/challenges/english/blocks/exam-responsive-web-design-certification/68db37350b398ecddd1f5dac.md +++ b/curriculum/challenges/english/blocks/exam-responsive-web-design-certification/68db37350b398ecddd1f5dac.md @@ -2,7 +2,7 @@ id: 68db37350b398ecddd1f5dac title: Responsive Web Design Certification Exam challengeType: 30 -dashedName: exam-javascript-certification +dashedName: exam-responsive-web-design-certification --- # --description-- diff --git a/shared/config/certification-settings.ts b/shared/config/certification-settings.ts index 1f934ab02b7..dc0105aa637 100644 --- a/shared/config/certification-settings.ts +++ b/shared/config/certification-settings.ts @@ -103,6 +103,7 @@ export const certTypes = { backEnd: 'isBackEndCert', dataVis: 'isDataVisCert', respWebDesign: 'isRespWebDesignCert', + respWebDesignV9: 'isRespWebDesignCertV9', frontEndDevLibs: 'isFrontEndLibsCert', dataVis2018: 'is2018DataVisCert', jsAlgoDataStruct: 'isJsAlgoDataStructCert', @@ -117,7 +118,8 @@ export const certTypes = { relationalDatabaseV8: 'isRelationalDatabaseCertV8', collegeAlgebraPyV8: 'isCollegeAlgebraPyCertV8', foundationalCSharpV8: 'isFoundationalCSharpCertV8', - jsAlgoDataStructV8: 'isJsAlgoDataStructCertV8' + jsAlgoDataStructV8: 'isJsAlgoDataStructCertV8', + javascriptV9: 'isJavascriptCertV9' } as const; export const certIds = { @@ -155,6 +157,7 @@ export const completionHours = { [certTypes.infosecQa]: 300, [certTypes.fullStack]: 1800, [certTypes.respWebDesign]: 300, + [certTypes.respWebDesignV9]: 300, [certTypes.frontEndDevLibs]: 300, [certTypes.jsAlgoDataStruct]: 300, [certTypes.dataVis2018]: 300, @@ -167,7 +170,8 @@ export const completionHours = { [certTypes.relationalDatabaseV8]: 300, [certTypes.collegeAlgebraPyV8]: 300, [certTypes.foundationalCSharpV8]: 300, - [certTypes.jsAlgoDataStructV8]: 300 + [certTypes.jsAlgoDataStructV8]: 300, + [certTypes.javascriptV9]: 300 }; export const certSlugTypeMap = { @@ -192,9 +196,11 @@ export const certSlugTypeMap = { [Certification.MachineLearningPy]: certTypes.machineLearningPyV7, [Certification.RelationalDb]: certTypes.relationalDatabaseV8, [Certification.CollegeAlgebraPy]: certTypes.collegeAlgebraPyV8, - [Certification.FoundationalCSharp]: certTypes.foundationalCSharpV8 + [Certification.FoundationalCSharp]: certTypes.foundationalCSharpV8, // upcoming + [Certification.RespWebDesignV9]: certTypes.respWebDesignV9, + [Certification.JsV9]: certTypes.javascriptV9 }; export const superBlockCertTypeMap = { @@ -235,6 +241,7 @@ export const certTypeIdMap = { [certTypes.infosecQa]: certIds.legacyInfosecQaId, [certTypes.fullStack]: certIds.legacyFullStackId, [certTypes.respWebDesign]: certIds.respWebDesignId, + [certTypes.respWebDesignV9]: certIds.respWebDesignV9Id, [certTypes.frontEndDevLibs]: certIds.frontEndDevLibsId, [certTypes.jsAlgoDataStruct]: certIds.jsAlgoDataStructId, [certTypes.dataVis2018]: certIds.dataVis2018Id, @@ -247,7 +254,8 @@ export const certTypeIdMap = { [certTypes.relationalDatabaseV8]: certIds.relationalDatabaseV8Id, [certTypes.collegeAlgebraPyV8]: certIds.collegeAlgebraPyV8Id, [certTypes.foundationalCSharpV8]: certIds.foundationalCSharpV8Id, - [certTypes.jsAlgoDataStructV8]: certIds.jsAlgoDataStructV8Id + [certTypes.jsAlgoDataStructV8]: certIds.jsAlgoDataStructV8Id, + [certTypes.javascriptV9]: certIds.javascriptV9Id }; export const certTypeTitleMap = { @@ -257,6 +265,7 @@ export const certTypeTitleMap = { [certTypes.infosecQa]: 'Legacy Information Security and Quality Assurance', [certTypes.fullStack]: 'Legacy Full Stack', [certTypes.respWebDesign]: 'Responsive Web Design', + [certTypes.respWebDesignV9]: 'Responsive Web Design', [certTypes.frontEndDevLibs]: 'Front End Development Libraries', [certTypes.jsAlgoDataStruct]: 'Legacy JavaScript Algorithms and Data Structures', @@ -270,7 +279,8 @@ export const certTypeTitleMap = { [certTypes.relationalDatabaseV8]: 'Relational Database', [certTypes.collegeAlgebraPyV8]: 'College Algebra with Python', [certTypes.foundationalCSharpV8]: 'Foundational C# with Microsoft', - [certTypes.jsAlgoDataStructV8]: 'JavaScript Algorithms and Data Structures' + [certTypes.jsAlgoDataStructV8]: 'JavaScript Algorithms and Data Structures', + [certTypes.javascriptV9]: 'JavaScript' }; export const superBlockToCertMap: { diff --git a/tools/scripts/seed/user-data.js b/tools/scripts/seed/user-data.js index 7e9490b7fb8..317351651db 100644 --- a/tools/scripts/seed/user-data.js +++ b/tools/scripts/seed/user-data.js @@ -225,8 +225,10 @@ module.exports.fullyCertifiedUser = { isBackEndCert: true, isFullStackCert: true, isRespWebDesignCert: true, + isRespWebDesignCertV9: true, is2018DataVisCert: true, isFrontEndLibsCert: true, + isJavascriptCertV9: true, isJsAlgoDataStructCert: true, isJsAlgoDataStructCertV8: true, isApisMicroservicesCert: true,