feat: add user flags for all certifications (#64338)

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>
This commit is contained in:
Oliver Eyton-Williams
2025-12-12 14:51:05 +01:00
committed by GitHub
parent 4558096cee
commit 44f5cd6cfc
23 changed files with 219 additions and 130 deletions

View File

@@ -134,6 +134,13 @@ model user {
is2018DataVisCert Boolean? // Undefined
is2018FullStackCert Boolean? // Undefined
isCollegeAlgebraPyCertV8 Boolean? // Undefined
isFrontEndLibsCertV9 Boolean? // Undefined
isBackEndDevApisCertV9 Boolean? // Undefined
isFullStackDeveloperCertV9 Boolean? // Undefined
isB1EnglishCert Boolean? // Undefined
isA2SpanishCert Boolean? // Undefined
isA2ChineseCert Boolean? // Undefined
isA1ChineseCert Boolean? // Undefined
// isUpcomingPythonCertV8 Boolean? // Undefined. It is in the db but has never been used.
keyboardShortcuts Boolean? // Undefined
linkedin String? // Null | Undefined

View File

@@ -56,6 +56,13 @@ export const newUser = (email: string) => ({
isRespWebDesignCert: false,
isRespWebDesignCertV9: false,
isSciCompPyCertV7: false,
isFrontEndLibsCertV9: false,
isBackEndDevApisCertV9: false,
isFullStackDeveloperCertV9: false,
isB1EnglishCert: false,
isA2SpanishCert: false,
isA2ChineseCert: false,
isA1ChineseCert: false,
keyboardShortcuts: false,
linkedin: null,
location: '',

View File

@@ -21,9 +21,7 @@ const fullStackCertificateIds = [
* @param certSlug - The certification slug to check.
* @returns True if the certification slug is known, otherwise false.
*/
export function isKnownCertSlug(
certSlug: string
): certSlug is keyof typeof certSlugTypeMap {
export function isKnownCertSlug(certSlug: string): certSlug is Certification {
return certSlug in certSlugTypeMap;
}

View File

@@ -34,6 +34,13 @@ const nullableFlags = [
'isRespWebDesignCertV9',
'isSciCompPyCertV7',
'isDataAnalysisPyCertV7',
'isFrontEndLibsCertV9',
'isBackEndDevApisCertV9',
'isFullStackDeveloperCertV9',
'isB1EnglishCert',
'isA2SpanishCert',
'isA2ChineseCert',
'isA1ChineseCert',
// isUpcomingPythonCertV8 exists in the db, but is not returned by the api-server
// TODO(Post-MVP): delete it from the db?
'keyboardShortcuts'

View File

@@ -13,6 +13,7 @@ import {
defaultUserEmail,
defaultUserId,
devLogin,
resetDefaultUser,
setupServer,
superRequest
} from '../../../vitest.utils.js';
@@ -35,30 +36,13 @@ describe('certificate routes', () => {
describe('PUT /certificate/verify', () => {
beforeEach(async () => {
await resetDefaultUser();
await fastifyTestInstance.prisma.user.updateMany({
where: { email: defaultUserEmail },
data: {
completedChallenges: [],
is2018DataVisCert: false,
isA2EnglishCert: false,
isApisMicroservicesCert: false,
isCollegeAlgebraPyCertV8: false,
isDataAnalysisPyCertV7: false,
isFoundationalCSharpCertV8: false,
isFrontEndLibsCert: false,
isInfosecCertV7: false,
isJsAlgoDataStructCert: false,
isJavascriptCertV9: false,
isMachineLearningPyCertV7: false,
isPythonCertV9: false,
isQaCertV7: false,
isRelationalDatabaseCertV8: false,
isRelationalDatabaseCertV9: false,
isRespWebDesignCert: false,
isRespWebDesignCertV9: false,
isSciCompPyCertV7: false,
name: 'fcc',
username: 'fcc'
username: 'fcc',
completedChallenges: []
}
});
});
@@ -174,7 +158,6 @@ describe('certificate routes', () => {
await fastifyTestInstance.prisma.user.updateMany({
where: { email: defaultUserEmail },
data: {
completedChallenges: [],
isRespWebDesignCert: true
}
});
@@ -309,29 +292,37 @@ describe('certificate routes', () => {
}
},
isCertMap: {
is2018DataVisCert: false,
isA1ChineseCert: false,
isA2ChineseCert: false,
isA2EnglishCert: false,
isRespWebDesignCert: true,
isRespWebDesignCertV9: false,
isA2SpanishCert: false,
isApisMicroservicesCert: false,
isB1EnglishCert: false,
isBackEndCert: false,
isBackEndDevApisCertV9: false,
isCollegeAlgebraPyCertV8: false,
isDataAnalysisPyCertV7: false,
isDataVisCert: false,
isFoundationalCSharpCertV8: false,
isFrontEndCert: false,
isFrontEndLibsCert: false,
isFrontEndLibsCertV9: false,
isFullStackCert: false,
isFullStackDeveloperCertV9: false,
isInfosecCertV7: false,
isInfosecQaCert: false,
isJavascriptCertV9: false,
isJsAlgoDataStructCert: false,
isFrontEndLibsCert: false,
is2018DataVisCert: false,
isApisMicroservicesCert: false,
isInfosecQaCert: false,
isQaCertV7: false,
isInfosecCertV7: false,
isFrontEndCert: false,
isBackEndCert: false,
isDataVisCert: false,
isFullStackCert: false,
isSciCompPyCertV7: false,
isDataAnalysisPyCertV7: false,
isJsAlgoDataStructCertV8: false,
isMachineLearningPyCertV7: false,
isRelationalDatabaseCertV8: false,
isCollegeAlgebraPyCertV8: false,
isFoundationalCSharpCertV8: false,
isPythonCertV9: false,
isRelationalDatabaseCertV9: false
isQaCertV7: false,
isRelationalDatabaseCertV8: false,
isRelationalDatabaseCertV9: false,
isRespWebDesignCert: true,
isRespWebDesignCertV9: false,
isSciCompPyCertV7: false
},
completedChallenges: [
{

View File

@@ -5,6 +5,7 @@ import type { FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebo
import { challenges, getChallenges } from '../../utils/get-challenges.js';
import {
Certification,
type CertificationFlags,
certSlugTypeMap,
certToIdMap,
certToTitleMap,
@@ -121,45 +122,26 @@ export function createCertLookup(
return certLookup;
}
interface CertI {
isA2EnglishCert?: boolean;
isApisMicroservicesCert?: boolean;
isBackEndCert?: boolean;
isCollegeAlgebraPyCertV8?: boolean;
isDataAnalysisPyCertV7?: boolean;
isDataVisCert?: boolean;
isFrontEndCert?: boolean;
isFrontEndLibsCert?: boolean;
isFoundationalCSharpCertV8?: boolean;
isFullStackCert?: boolean;
isInfosecCertV7?: boolean;
isInfosecQaCert?: boolean;
isJavascriptCertV9?: boolean;
isJsAlgoDataStructCert?: boolean;
isJsAlgoDataStructCertV8?: boolean;
isMachineLearningPyCertV7?: boolean;
isPythonCertV9?: boolean;
isQaCertV7?: boolean;
isRelationalDatabaseCertV8?: boolean;
isRelationalDatabaseCertV9?: boolean;
isRespWebDesignCert?: boolean;
isRespWebDesignCertV9?: boolean;
isSciCompPyCertV7?: boolean;
is2018DataVisCert?: boolean;
}
function getUserIsCertMap(user: CertI) {
function getUserIsCertMap(user: Partial<CertificationFlags>) {
const {
is2018DataVisCert = false,
isA1ChineseCert = false,
isA2ChineseCert = false,
isA2EnglishCert = false,
isA2SpanishCert = false,
isApisMicroservicesCert = false,
isB1EnglishCert = false,
isBackEndCert = false,
isBackEndDevApisCertV9 = false,
isCollegeAlgebraPyCertV8 = false,
isDataAnalysisPyCertV7 = false,
isDataVisCert = false,
isFoundationalCSharpCertV8 = false,
isFrontEndCert = false,
isFrontEndLibsCert = false,
isFoundationalCSharpCertV8 = false,
isFrontEndLibsCertV9 = false,
isFullStackCert = false,
isFullStackDeveloperCertV9 = false,
isInfosecCertV7 = false,
isInfosecQaCert = false,
isJavascriptCertV9 = false,
@@ -172,21 +154,28 @@ function getUserIsCertMap(user: CertI) {
isRelationalDatabaseCertV9 = false,
isRespWebDesignCert = false,
isRespWebDesignCertV9 = false,
isSciCompPyCertV7 = false,
is2018DataVisCert = false
isSciCompPyCertV7 = false
} = user;
return {
is2018DataVisCert,
isA1ChineseCert,
isA2ChineseCert,
isA2EnglishCert,
isA2SpanishCert,
isApisMicroservicesCert,
isB1EnglishCert,
isBackEndCert,
isBackEndDevApisCertV9,
isCollegeAlgebraPyCertV8,
isDataAnalysisPyCertV7,
isDataVisCert,
isFoundationalCSharpCertV8,
isFrontEndCert,
isFrontEndLibsCert,
isFoundationalCSharpCertV8,
isFrontEndLibsCertV9,
isFullStackCert,
isFullStackDeveloperCertV9,
isInfosecCertV7,
isInfosecQaCert,
isJavascriptCertV9,
@@ -199,8 +188,7 @@ function getUserIsCertMap(user: CertI) {
isRelationalDatabaseCertV9,
isRespWebDesignCert,
isRespWebDesignCertV9,
isSciCompPyCertV7,
is2018DataVisCert
isSciCompPyCertV7
};
}
@@ -346,16 +334,23 @@ export const protectedCertificateRoutes: FastifyPluginCallbackTypebox = (
username: true,
is2018DataVisCert: true,
is2018FullStackCert: true,
isA1ChineseCert: true,
isA2ChineseCert: true,
isA2EnglishCert: true,
isA2SpanishCert: true,
isApisMicroservicesCert: true,
isB1EnglishCert: true,
isBackEndCert: true,
isBackEndDevApisCertV9: true,
isCollegeAlgebraPyCertV8: true,
isDataAnalysisPyCertV7: true,
isDataVisCert: true,
isFoundationalCSharpCertV8: true,
isFrontEndCert: true,
isFrontEndLibsCert: true,
isFrontEndLibsCertV9: true,
isFullStackCert: true,
isFullStackDeveloperCertV9: true,
isInfosecCertV7: true,
isInfosecQaCert: true,
isJavascriptCertV9: true,

View File

@@ -300,6 +300,13 @@ const publicUserData = {
isRespWebDesignCert: testUserData.isRespWebDesignCert,
isRespWebDesignCertV9: testUserData.isRespWebDesignCertV9,
isSciCompPyCertV7: testUserData.isSciCompPyCertV7,
isFrontEndLibsCertV9: testUserData.isFrontEndLibsCertV9,
isBackEndDevApisCertV9: testUserData.isBackEndDevApisCertV9,
isFullStackDeveloperCertV9: testUserData.isFullStackDeveloperCertV9,
isB1EnglishCert: testUserData.isB1EnglishCert,
isA2SpanishCert: testUserData.isA2SpanishCert,
isA2ChineseCert: testUserData.isA2ChineseCert,
isA1ChineseCert: testUserData.isA1ChineseCert,
linkedin: testUserData.linkedin,
location: testUserData.location,
name: testUserData.name,
@@ -1029,6 +1036,13 @@ describe('userRoutes', () => {
isRespWebDesignCert: false,
isRespWebDesignCertV9: false,
isSciCompPyCertV7: false,
isFrontEndLibsCertV9: false,
isBackEndDevApisCertV9: false,
isFullStackDeveloperCertV9: false,
isB1EnglishCert: false,
isA2SpanishCert: false,
isA2ChineseCert: false,
isA1ChineseCert: false,
keyboardShortcuts: false,
location: '',
name: '',

View File

@@ -708,6 +708,13 @@ export const userGetRoutes: FastifyPluginCallbackTypebox = (
isRespWebDesignCert: true,
isRespWebDesignCertV9: true,
isSciCompPyCertV7: true,
isFrontEndLibsCertV9: true,
isBackEndDevApisCertV9: true,
isFullStackDeveloperCertV9: true,
isB1EnglishCert: true,
isA2SpanishCert: true,
isA2ChineseCert: true,
isA1ChineseCert: true,
keyboardShortcuts: true,
linkedin: true,
location: true,

View File

@@ -84,6 +84,13 @@ export const unprotectedCertificateRoutes: FastifyPluginCallbackTypebox = (
isRelationalDatabaseCertV9: true,
isCollegeAlgebraPyCertV8: true,
isFoundationalCSharpCertV8: true,
isFrontEndLibsCertV9: true,
isBackEndDevApisCertV9: true,
isFullStackDeveloperCertV9: true,
isB1EnglishCert: true,
isA2SpanishCert: true,
isA2ChineseCert: true,
isA1ChineseCert: true,
isHonest: true,
username: true,
name: true,

View File

@@ -28,7 +28,15 @@ export const isCertMap = Type.Object({
isRelationalDatabaseCertV8: Type.Boolean(),
isRelationalDatabaseCertV9: Type.Boolean(),
isCollegeAlgebraPyCertV8: Type.Boolean(),
isFoundationalCSharpCertV8: Type.Boolean()
isFoundationalCSharpCertV8: Type.Boolean(),
isJsAlgoDataStructCertV8: Type.Boolean(),
isA1ChineseCert: Type.Boolean(),
isA2ChineseCert: Type.Boolean(),
isA2SpanishCert: Type.Boolean(),
isB1EnglishCert: Type.Boolean(),
isBackEndDevApisCertV9: Type.Boolean(),
isFullStackDeveloperCertV9: Type.Boolean(),
isFrontEndLibsCertV9: Type.Boolean()
});
export const file = Type.Object({

View File

@@ -93,6 +93,13 @@ export const getSessionUser = {
isRespWebDesignCert: Type.Boolean(),
isRespWebDesignCertV9: Type.Boolean(),
isSciCompPyCertV7: Type.Boolean(),
isFrontEndLibsCertV9: Type.Boolean(),
isBackEndDevApisCertV9: Type.Boolean(),
isFullStackDeveloperCertV9: Type.Boolean(),
isB1EnglishCert: Type.Boolean(),
isA2SpanishCert: Type.Boolean(),
isA2ChineseCert: Type.Boolean(),
isA1ChineseCert: Type.Boolean(),
keyboardShortcuts: Type.Boolean(),
linkedin: Type.Optional(Type.String()),
location: Type.String(),

View File

@@ -39,6 +39,13 @@ export const createResetProperties = () => ({
isRespWebDesignCert: false,
isRespWebDesignCertV9: false,
isSciCompPyCertV7: false,
isFrontEndLibsCertV9: false,
isBackEndDevApisCertV9: false,
isFullStackDeveloperCertV9: false,
isB1EnglishCert: false,
isA2SpanishCert: false,
isA2ChineseCert: false,
isA1ChineseCert: false,
needsModeration: false,
partiallyCompletedChallenges: [], // TODO(Post-MVP): Omit this from the document? (prisma will always return [])
progressTimestamps: [Date.now()], // TODO(Post-MVP): This may need normalising before we can omit it. Also, does it need to start with a timestamp?

View File

@@ -163,6 +163,13 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element {
isCollegeAlgebraPyCertV8,
isFoundationalCSharpCertV8,
isJsAlgoDataStructCertV8,
isFrontEndLibsCertV9,
isBackEndDevApisCertV9,
isFullStackDeveloperCertV9,
isB1EnglishCert,
isA2SpanishCert,
isA2ChineseCert,
isA1ChineseCert,
isEmailVerified,
isHonest,
sendQuincyEmail,
@@ -251,9 +258,15 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element {
isRespWebDesignCertV9={isRespWebDesignCertV9}
isSciCompPyCertV7={isSciCompPyCertV7}
isJsAlgoDataStructCertV8={isJsAlgoDataStructCertV8}
isFrontEndLibsCertV9={isFrontEndLibsCertV9}
isBackEndDevApisCertV9={isBackEndDevApisCertV9}
isFullStackDeveloperCertV9={isFullStackDeveloperCertV9}
isB1EnglishCert={isB1EnglishCert}
isA2SpanishCert={isA2SpanishCert}
isA2ChineseCert={isA2ChineseCert}
isA1ChineseCert={isA1ChineseCert}
username={username}
verifyCert={verifyCert}
isEmailVerified={isEmailVerified}
/>
<Spacer size='m' />
</ScrollElement>

View File

@@ -286,6 +286,13 @@ const defaultTestProps = {
isRelationalDatabaseCertV9: false,
isCollegeAlgebraPyCertV8: false,
isFoundationalCSharpCertV8: false,
isFrontEndLibsCertV9: false,
isBackEndDevApisCertV9: false,
isFullStackDeveloperCertV9: false,
isB1EnglishCert: false,
isA2SpanishCert: false,
isA2ChineseCert: false,
isA1ChineseCert: false,
username: 'developmentuser',
verifyCert: verifyCert,
isEmailVerified: false

View File

@@ -19,13 +19,13 @@ import {
Certification,
currentCertifications,
legacyCertifications,
upcomingCertifications
upcomingCertifications,
type CertificationFlags
} from '../../../../shared-dist/config/certification-settings';
import env from '../../../config/env.json';
import type {
ChallengeData,
ClaimedCertifications,
CompletedChallenge,
GeneratedExamResults,
User
@@ -66,7 +66,7 @@ const createCertifiedMap = ({
isCollegeAlgebraPyCertV8,
isFoundationalCSharpCertV8,
isJsAlgoDataStructCertV8
}: ClaimedCertifications): Record<
}: CertificationFlags): Record<
Exclude<Certification, Certification.LegacyFullStack>,
boolean
> => ({
@@ -115,7 +115,7 @@ type CertificationSettingsProps = {
t: TFunction;
verifyCert: typeof verifyCert;
openModal: typeof openModal;
} & ClaimedCertifications &
} & CertificationFlags &
Pick<User, 'completedChallenges' | 'isHonest' | 'username'>;
const LegacyFullStack = (props: CertificationSettingsProps) => {

View File

@@ -1,8 +1,9 @@
import { HandlerProps } from 'react-reflex';
import {
import type {
ChallengeLang,
SuperBlocks
} from '../../../shared-dist/config/curriculum';
import type { CertificationFlags } from '../../../shared-dist/config/certification-settings';
import type { Chapter } from '../../../shared-dist/config/chapters';
import { BlockLayouts, BlockLabel } from '../../../shared-dist/config/blocks';
import type { ChallengeFile, Ext } from '../../../shared-dist/utils/polyvinyl';
@@ -424,6 +425,7 @@ export type User = {
email: string;
emailVerified: boolean;
githubProfile: string;
isEmailVerified: boolean;
isBanned: boolean;
isCheater: boolean;
isDonating: boolean;
@@ -447,7 +449,7 @@ export type User = {
username: string;
website: string;
yearsTopContributor: string[];
} & ClaimedCertifications;
} & CertificationFlags;
export type ProfileUI = {
isLocked: boolean;
@@ -462,34 +464,6 @@ export type ProfileUI = {
showTimeLine: boolean;
};
export type ClaimedCertifications = {
is2018DataVisCert: boolean;
isA2EnglishCert: boolean;
isApisMicroservicesCert: boolean;
isBackEndCert: boolean;
isDataVisCert: boolean;
isEmailVerified: boolean;
isCollegeAlgebraPyCertV8: boolean;
isFoundationalCSharpCertV8: boolean;
isFrontEndCert: boolean;
isFrontEndLibsCert: boolean;
isFullStackCert: boolean;
isInfosecQaCert: boolean;
isJavascriptCertV9: boolean;
isPythonCertV9: boolean;
isQaCertV7: boolean;
isInfosecCertV7: boolean;
isJsAlgoDataStructCert: boolean;
isRelationalDatabaseCertV8: boolean;
isRelationalDatabaseCertV9: boolean;
isRespWebDesignCert: boolean;
isRespWebDesignCertV9: boolean;
isSciCompPyCertV7: boolean;
isDataAnalysisPyCertV7: boolean;
isMachineLearningPyCertV7: boolean;
isJsAlgoDataStructCertV8: boolean;
};
type SavedChallenges = SavedChallenge[];
export type SavedChallenge = {

View File

@@ -10,7 +10,6 @@ import {
import type { CertTitle } from '../../../../config/cert-and-project-map';
import type {
ChapterBasedSuperBlockStructure,
ClaimedCertifications,
User
} from '../../../redux/prop-types';
import type {
@@ -146,11 +145,7 @@ export const SuperBlockMap = ({
const requirementLink = `/learn/${requirement}/`;
const certSlug = superBlockToCertMap[requirement];
const certFlagLookup = certSlugTypeMap as Record<
string,
keyof ClaimedCertifications
>;
const certFlagKey = certSlug ? certFlagLookup[certSlug] : undefined;
const certFlagKey = certSlug ? certSlugTypeMap[certSlug] : undefined;
const isRequirementComplete = Boolean(
certFlagKey && user?.[certFlagKey]
);

View File

@@ -1,7 +1,7 @@
---
id: 68f1268149f045a650d4229e
title: A1 Professional Chinese Certification
certification: a1-professional-chinese-v8
certification: a1-professional-chinese
challengeType: 7
tests:
- id: 688f1daf0133dbe2a36b140b

View File

@@ -1,7 +1,7 @@
---
id: 682c3153086dd7cabe7f48bc
title: A2 Professional Chinese Certification
certification: a2-professional-chinese-v8
certification: a2-professional-chinese
challengeType: 7
tests:
- id: 682c2753317b88f1ecdad894

View File

@@ -1,7 +1,7 @@
---
id: 681a6b22e5a782fe3459984a
title: A2 Professional Spanish Certification
certification: a2-professional-spanish-v8
certification: a2-professional-spanish
challengeType: 7
tests:
- id: 681a8796e5a782fe3459984b

View File

@@ -1,7 +1,7 @@
---
id: 66607e53317411dd5e8aae21
title: B1 English for Developers Certification
certification: b1-english-for-developers-v8
certification: b1-english-for-developers
challengeType: 7
tests:
- id: 66607e5b317411dd5e8aae22

View File

@@ -35,7 +35,7 @@ describe('certToIdMap', () => {
});
describe('certSlugTypeMap', () => {
it.todo('should contain a value for all certifications', () => {
it('should contain a value for all certifications', () => {
const allCertifications = Object.values(Certification).sort();
const certSlugTypeMapKeys = Object.keys(certSlugTypeMap).sort();

View File

@@ -34,10 +34,10 @@ export enum Certification {
BackEndDevApisV9 = 'back-end-development-and-apis-v9',
A2English = 'a2-english-for-developers',
FullStackDeveloperV9 = 'full-stack-developer-v9',
B1English = 'b1-english-for-developers-v8',
A2Spanish = 'a2-professional-spanish-v8',
A2Chinese = 'a2-professional-chinese-v8',
A1Chinese = 'a1-professional-chinese-v8',
B1English = 'b1-english-for-developers',
A2Spanish = 'a2-professional-spanish',
A2Chinese = 'a2-professional-chinese',
A1Chinese = 'a1-professional-chinese',
// Legacy certifications
LegacyFrontEnd = 'legacy-front-end',
JsAlgoDataStruct = 'javascript-algorithms-and-data-structures',
@@ -175,7 +175,40 @@ export const completionHours: Record<Certification, number> = {
[Certification.A1Chinese]: 300
};
export const certSlugTypeMap = {
type UserCertFlag =
| 'isFrontEndCert'
| 'isJsAlgoDataStructCert'
| 'isBackEndCert'
| 'isDataVisCert'
| 'isInfosecQaCert'
| 'isFullStackCert'
| 'isRespWebDesignCert'
| 'isJsAlgoDataStructCertV8'
| 'isFrontEndLibsCert'
| 'is2018DataVisCert'
| 'isApisMicroservicesCert'
| 'isQaCertV7'
| 'isInfosecCertV7'
| 'isSciCompPyCertV7'
| 'isDataAnalysisPyCertV7'
| 'isMachineLearningPyCertV7'
| 'isRelationalDatabaseCertV8'
| 'isCollegeAlgebraPyCertV8'
| 'isFoundationalCSharpCertV8'
| 'isA2EnglishCert'
| 'isRespWebDesignCertV9'
| 'isJavascriptCertV9'
| 'isFrontEndLibsCertV9'
| 'isPythonCertV9'
| 'isRelationalDatabaseCertV9'
| 'isBackEndDevApisCertV9'
| 'isFullStackDeveloperCertV9'
| 'isB1EnglishCert'
| 'isA2SpanishCert'
| 'isA2ChineseCert'
| 'isA1ChineseCert';
export const certSlugTypeMap: Record<Certification, UserCertFlag> = {
// legacy
[Certification.LegacyFrontEnd]: 'isFrontEndCert',
[Certification.JsAlgoDataStruct]: 'isJsAlgoDataStructCert',
@@ -202,9 +235,21 @@ export const certSlugTypeMap = {
[Certification.PythonV9]: 'isPythonCertV9',
[Certification.RelationalDbV9]: 'isRelationalDatabaseCertV9',
[Certification.RespWebDesignV9]: 'isRespWebDesignCertV9',
[Certification.JsV9]: 'isJavascriptCertV9'
[Certification.JsV9]: 'isJavascriptCertV9',
// upcoming
} as const;
[Certification.FrontEndDevLibsV9]: 'isFrontEndLibsCertV9',
[Certification.BackEndDevApisV9]: 'isBackEndDevApisCertV9',
[Certification.FullStackDeveloperV9]: 'isFullStackDeveloperCertV9',
[Certification.B1English]: 'isB1EnglishCert',
[Certification.A2Spanish]: 'isA2SpanishCert',
[Certification.A2Chinese]: 'isA2ChineseCert',
[Certification.A1Chinese]: 'isA1ChineseCert'
};
export type CertificationFlags = {
[key in UserCertFlag]: boolean;
};
// TODO: use i18n keys instead of hardcoded titles
export const certToTitleMap: Record<Certification, string> = {