From 383cf7f9782e84de353b2316cf0466681305107c Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Tue, 10 Dec 2024 12:21:30 +0100 Subject: [PATCH] feat(client): move FSD superblock into Next superblock stage (#57349) --- client/i18n/locales/english/translations.json | 1 + client/src/components/Map/index.tsx | 10 +++++++- curriculum/utils.js | 3 ++- shared/config/curriculum.test.ts | 21 +++++++++++++--- shared/config/curriculum.ts | 25 +++++++++++++------ 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/client/i18n/locales/english/translations.json b/client/i18n/locales/english/translations.json index 4b5d867f0b3..9825d391fa4 100644 --- a/client/i18n/locales/english/translations.json +++ b/client/i18n/locales/english/translations.json @@ -166,6 +166,7 @@ "professional-certs-heading": "Earn free professional certifications:", "interview-prep-heading": "Prepare for the developer interview job search:", "legacy-curriculum-heading": "Explore our Legacy Curriculum:", + "next-heading": "Try our beta curriculum:", "upcoming-heading": "Upcoming curriculum:", "faq": "Frequently asked questions:", "faqs": [ diff --git a/client/src/components/Map/index.tsx b/client/src/components/Map/index.tsx index 664559af93c..5addcad77bd 100644 --- a/client/src/components/Map/index.tsx +++ b/client/src/components/Map/index.tsx @@ -3,6 +3,8 @@ import { useTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { Spacer } from '@freecodecamp/ui'; +import { useFeature } from '@growthbook/growthbook-react'; + import { type SuperBlocks, SuperBlockStage, @@ -60,6 +62,7 @@ const superBlockHeadings: { [key in SuperBlockStage]: string } = { [SuperBlockStage.Extra]: 'landing.interview-prep-heading', [SuperBlockStage.Legacy]: 'landing.legacy-curriculum-heading', [SuperBlockStage.New]: '', // TODO: add translation + [SuperBlockStage.Next]: 'landing.next-heading', [SuperBlockStage.Upcoming]: 'landing.upcoming-heading' }; @@ -135,6 +138,7 @@ function Map({ allChallenges }: MapProps): React.ReactElement { const { t } = useTranslation(); + const showNextCurriculum = useFeature('fcc-10').on; const allSuperblockChallengesCompleted = (superblock: SuperBlocks) => { // array of all challenge ID's in the superblock @@ -161,7 +165,11 @@ function Map({ return (
- {getStageOrder({ showNewCurriculum, showUpcomingChanges }).map(stage => ( + {getStageOrder({ + showNewCurriculum, + showUpcomingChanges, + showNextCurriculum + }).map(stage => (

{t(superBlockHeadings[stage])} diff --git a/curriculum/utils.js b/curriculum/utils.js index cd80b423e23..1b6d95347f5 100644 --- a/curriculum/utils.js +++ b/curriculum/utils.js @@ -44,7 +44,8 @@ function createSuperOrder(superBlocks) { const flatSuperBlockMap = generateSuperBlockList({ showNewCurriculum: process.env.SHOW_NEW_CURRICULUM === 'true', - showUpcomingChanges: process.env.SHOW_UPCOMING_CHANGES === 'true' + showUpcomingChanges: process.env.SHOW_UPCOMING_CHANGES === 'true', + showNextCurriculum: true }); const superOrder = createSuperOrder(flatSuperBlockMap); diff --git a/shared/config/curriculum.test.ts b/shared/config/curriculum.test.ts index d79940d63d8..eb3cab9efd1 100644 --- a/shared/config/curriculum.test.ts +++ b/shared/config/curriculum.test.ts @@ -20,10 +20,11 @@ describe('superBlockOrder', () => { }); describe('generateSuperBlockList', () => { - it('should return an array of SuperBlocks object with New and Upcoming when { showNewCurriculum: true, showUpcomingChanges: true }', () => { + it('should return an array of SuperBlocks object with all elements when if all configs are true', () => { const result = generateSuperBlockList({ showNewCurriculum: true, - showUpcomingChanges: true + showUpcomingChanges: true, + showNextCurriculum: true }); expect(result).toHaveLength(Object.values(superBlockStages).flat().length); }); @@ -31,13 +32,27 @@ describe('generateSuperBlockList', () => { it('should return an array of SuperBlocks without New and Upcoming when { showNewCurriculum: false, showUpcomingChanges: false }', () => { const result = generateSuperBlockList({ showNewCurriculum: false, - showUpcomingChanges: false + showUpcomingChanges: false, + showNextCurriculum: true }); const tempSuperBlockMap = { ...superBlockStages }; tempSuperBlockMap[SuperBlockStage.New] = []; tempSuperBlockMap[SuperBlockStage.Upcoming] = []; expect(result).toHaveLength(Object.values(tempSuperBlockMap).flat().length); }); + + it('should exclude the Next SuperBlocks when { showNextCurriculum: false }', () => { + const result = generateSuperBlockList({ + showNewCurriculum: false, + showUpcomingChanges: false, + showNextCurriculum: false + }); + const tempSuperBlockMap = { ...superBlockStages }; + tempSuperBlockMap[SuperBlockStage.New] = []; + tempSuperBlockMap[SuperBlockStage.Upcoming] = []; + tempSuperBlockMap[SuperBlockStage.Next] = []; + expect(result).toHaveLength(Object.values(tempSuperBlockMap).flat().length); + }); }); describe('Immutability of superBlockOrder, notAuditedSuperBlocks, and flatSuperBlockMap', () => { diff --git a/shared/config/curriculum.ts b/shared/config/curriculum.ts index 681f4ca5309..48d21adabf5 100644 --- a/shared/config/curriculum.ts +++ b/shared/config/curriculum.ts @@ -35,6 +35,10 @@ export enum SuperBlocks { * * SuperBlockStages.Upcoming = SHOW_UPCOMING_CHANGES === 'true' * 'Upcoming' is for development -> not shown on stag or prod anywhere + * + * SuperBlockStages.Next = deployed, but only shown if the Growthbook feature + * is enabled. + * */ export enum SuperBlockStage { Core, @@ -43,11 +47,13 @@ export enum SuperBlockStage { Extra, Legacy, New, - Upcoming + Upcoming, + Next } const defaultStageOrder = [ SuperBlockStage.Core, + SuperBlockStage.Next, SuperBlockStage.English, SuperBlockStage.Professional, SuperBlockStage.Extra, @@ -56,9 +62,12 @@ const defaultStageOrder = [ export function getStageOrder({ showNewCurriculum, - showUpcomingChanges + showUpcomingChanges, + showNextCurriculum }: Config): SuperBlockStage[] { - const stageOrder = [...defaultStageOrder]; + const stageOrder = showNextCurriculum + ? [...defaultStageOrder] + : [...defaultStageOrder.filter(stage => stage !== SuperBlockStage.Next)]; if (showNewCurriculum) stageOrder.push(SuperBlockStage.New); if (showUpcomingChanges) stageOrder.push(SuperBlockStage.Upcoming); @@ -85,6 +94,7 @@ export const superBlockStages: StageMap = { SuperBlocks.MachineLearningPy, SuperBlocks.CollegeAlgebraPy ], + [SuperBlockStage.Next]: [SuperBlocks.FullStackDeveloper], [SuperBlockStage.English]: [SuperBlocks.A2English], [SuperBlockStage.Professional]: [SuperBlocks.FoundationalCSharp], [SuperBlockStage.Extra]: [ @@ -99,10 +109,7 @@ export const superBlockStages: StageMap = { SuperBlocks.PythonForEverybody ], [SuperBlockStage.New]: [], - [SuperBlockStage.Upcoming]: [ - SuperBlocks.B1English, - SuperBlocks.FullStackDeveloper - ] + [SuperBlockStage.Upcoming]: [SuperBlocks.B1English] }; Object.freeze(superBlockStages); @@ -246,6 +253,7 @@ Object.freeze(notAuditedSuperBlocks); type Config = { showNewCurriculum: boolean; showUpcomingChanges: boolean; + showNextCurriculum: boolean; }; export function generateSuperBlockList(config: Config): SuperBlocks[] { @@ -266,7 +274,8 @@ export function getAuditedSuperBlocks({ // To find the audited superblocks, we need to start with all superblocks. const flatSuperBlockMap = generateSuperBlockList({ showNewCurriculum: true, - showUpcomingChanges: true + showUpcomingChanges: true, + showNextCurriculum: true }); const auditedSuperBlocks = flatSuperBlockMap.filter( superBlock =>