diff --git a/client/src/components/Map/index.tsx b/client/src/components/Map/index.tsx
index 0dbe5faec2d..6154b86dc18 100644
--- a/client/src/components/Map/index.tsx
+++ b/client/src/components/Map/index.tsx
@@ -4,15 +4,19 @@ import { useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import {
- SuperBlockStages,
- SuperBlocks,
- superBlockOrder
+ type SuperBlocks,
+ SuperBlockStage,
+ getStageOrder,
+ superBlockStages
} from '../../../../shared/config/curriculum';
import { SuperBlockIcon } from '../../assets/icons/superblock-icon';
import LinkButton from '../../assets/icons/link-button';
import { Spacer, ButtonLink } from '../helpers';
import { getSuperBlockTitleForMap } from '../../utils/superblock-map-titles';
-import { showUpcomingChanges } from '../../../config/env.json';
+import {
+ showUpcomingChanges,
+ showNewCurriculum
+} from '../../../config/env.json';
import './map.css';
@@ -49,11 +53,15 @@ const linkSpacingStyle = {
gap: '15px'
};
-const coreCurriculum = [
- ...superBlockOrder[SuperBlockStages.FrontEnd],
- ...superBlockOrder[SuperBlockStages.Backend],
- ...superBlockOrder[SuperBlockStages.Python]
-];
+const superBlockHeadings: { [key in SuperBlockStage]: string } = {
+ [SuperBlockStage.Core]: 'landing.core-certs-heading',
+ [SuperBlockStage.English]: 'landing.learn-english-heading',
+ [SuperBlockStage.Professional]: 'landing.professional-certs-heading',
+ [SuperBlockStage.Extra]: 'landing.interview-prep-heading',
+ [SuperBlockStage.Legacy]: 'landing.legacy-curriculum-heading',
+ [SuperBlockStage.New]: '', // TODO: add translation
+ [SuperBlockStage.Upcoming]: 'landing.upcoming-heading'
+};
const mapStateToProps = createSelector(
isSignedInSelector,
@@ -173,107 +181,28 @@ function Map({
return (
-
- {t('landing.core-certs-heading')}
-
-
- {coreCurriculum.map((superBlock, i) => (
-
- ))}
-
-
-
- {t('landing.learn-english-heading')}
-
-
- {superBlockOrder[SuperBlockStages.English].map((superBlock, i) => (
-
- ))}
-
-
-
- {t('landing.professional-certs-heading')}
-
-
- {superBlockOrder[SuperBlockStages.Professional].map((superBlock, i) => (
-
- ))}
-
-
-
- {t('landing.interview-prep-heading')}
-
-
- {superBlockOrder[SuperBlockStages.Extra].map((superBlock, i) => (
-
- ))}
-
-
-
- {t('landing.legacy-curriculum-heading')}
-
-
- {superBlockOrder[SuperBlockStages.Legacy].map((superBlock, i) => (
-
- ))}
-
- {showUpcomingChanges && (
+ {getStageOrder({ showNewCurriculum, showUpcomingChanges }).map(stage => (
<>
-
- {t('landing.upcoming-heading')}
+ {t(superBlockHeadings[stage])}
-
- {superBlockOrder[SuperBlockStages.Upcoming].map((superBlock, i) => (
+
+ {superBlockStages[stage].map((superblock, i) => (
))}
+
>
- )}
+ ))}
);
}
diff --git a/e2e/map.spec.ts b/e2e/map.spec.ts
index 339f5abad77..5d2d00ef4f5 100644
--- a/e2e/map.spec.ts
+++ b/e2e/map.spec.ts
@@ -2,20 +2,18 @@ import { test, expect } from '@playwright/test';
import translations from '../client/i18n/locales/english/translations.json';
import intro from '../client/i18n/locales/english/intro.json';
-import { SuperBlockStages, superBlockOrder } from '../shared/config/curriculum';
+import { SuperBlockStage, superBlockStages } from '../shared/config/curriculum';
test.beforeEach(async ({ page }) => {
await page.goto('/learn');
});
const superBlocksWithLinks = [
- ...superBlockOrder[SuperBlockStages.FrontEnd],
- ...superBlockOrder[SuperBlockStages.Backend],
- ...superBlockOrder[SuperBlockStages.Python],
- ...superBlockOrder[SuperBlockStages.English],
- ...superBlockOrder[SuperBlockStages.Professional],
- ...superBlockOrder[SuperBlockStages.Extra],
- ...superBlockOrder[SuperBlockStages.Legacy]
+ ...superBlockStages[SuperBlockStage.Core],
+ ...superBlockStages[SuperBlockStage.English],
+ ...superBlockStages[SuperBlockStage.Professional],
+ ...superBlockStages[SuperBlockStage.Extra],
+ ...superBlockStages[SuperBlockStage.Legacy]
];
const superBlockTitleOverride: Record = {
diff --git a/shared/config/curriculum.test.ts b/shared/config/curriculum.test.ts
index c059c6fece6..4c88eae26f5 100644
--- a/shared/config/curriculum.test.ts
+++ b/shared/config/curriculum.test.ts
@@ -1,10 +1,9 @@
import { Languages } from './i18n';
import {
SuperBlocks,
- SuperBlockStages,
- superBlockOrder,
+ SuperBlockStage,
+ superBlockStages,
notAuditedSuperBlocks,
- createSuperBlockMap,
createFlatSuperBlockMap,
getAuditedSuperBlocks
} from './curriculum';
@@ -12,7 +11,7 @@ import {
describe('superBlockOrder', () => {
it('should contain all SuperBlocks', () => {
const allSuperBlocks = Object.values(SuperBlocks);
- const superBlockOrderValues = Object.values(superBlockOrder).flat();
+ const superBlockOrderValues = Object.values(superBlockStages).flat();
expect(superBlockOrderValues).toHaveLength(allSuperBlocks.length);
expect(superBlockOrderValues).toEqual(
expect.arrayContaining(allSuperBlocks)
@@ -20,37 +19,13 @@ describe('superBlockOrder', () => {
});
});
-describe('createSuperBlockMap', () => {
- it('should return an object with New and Upcoming when { showNewCurriculum: true, showUpcomingChanges: true }', () => {
- const result = createSuperBlockMap({
- showNewCurriculum: true,
- showUpcomingChanges: true
- });
- expect(result[SuperBlockStages.New]).toHaveLength(
- superBlockOrder[SuperBlockStages.New].length
- );
- expect(result[SuperBlockStages.Upcoming]).toHaveLength(
- superBlockOrder[SuperBlockStages.Upcoming].length
- );
- });
-
- it('should return an object without New and Upcoming when { showNewCurriculum: false, showUpcomingChanges: false }', () => {
- const result = createSuperBlockMap({
- showNewCurriculum: false,
- showUpcomingChanges: false
- });
- expect(result[SuperBlockStages.New]).toHaveLength(0);
- expect(result[SuperBlockStages.Upcoming]).toHaveLength(0);
- });
-});
-
describe('createFlatSuperBlockMap', () => {
it('should return an array of SuperBlocks object with New and Upcoming when { showNewCurriculum: true, showUpcomingChanges: true }', () => {
const result = createFlatSuperBlockMap({
showNewCurriculum: true,
showUpcomingChanges: true
});
- expect(result).toHaveLength(Object.values(superBlockOrder).flat().length);
+ expect(result).toHaveLength(Object.values(superBlockStages).flat().length);
});
it('should return an array of SuperBlocks without New and Upcoming when { showNewCurriculum: false, showUpcomingChanges: false }', () => {
@@ -58,9 +33,9 @@ describe('createFlatSuperBlockMap', () => {
showNewCurriculum: false,
showUpcomingChanges: false
});
- const tempSuperBlockMap = { ...superBlockOrder };
- tempSuperBlockMap[SuperBlockStages.New] = [];
- tempSuperBlockMap[SuperBlockStages.Upcoming] = [];
+ const tempSuperBlockMap = { ...superBlockStages };
+ tempSuperBlockMap[SuperBlockStage.New] = [];
+ tempSuperBlockMap[SuperBlockStage.Upcoming] = [];
expect(result).toHaveLength(Object.values(tempSuperBlockMap).flat().length);
});
});
@@ -68,7 +43,7 @@ describe('createFlatSuperBlockMap', () => {
describe('Immutability of superBlockOrder, notAuditedSuperBlocks, and flatSuperBlockMap', () => {
it('should not allow modification of superBlockOrder', () => {
expect(() => {
- superBlockOrder[SuperBlockStages.FrontEnd] = [];
+ superBlockStages[SuperBlockStage.Core] = [];
}).toThrowError(TypeError);
});
diff --git a/shared/config/curriculum.ts b/shared/config/curriculum.ts
index 00785150ca0..d7f12098a0e 100644
--- a/shared/config/curriculum.ts
+++ b/shared/config/curriculum.ts
@@ -37,10 +37,8 @@ export enum SuperBlocks {
* SuperBlockStages.Upcoming = SHOW_UPCOMING_CHANGES === 'true'
* 'Upcoming' is for development -> not shown on stag or prod anywhere
*/
-export enum SuperBlockStages {
- FrontEnd,
- Backend,
- Python,
+export enum SuperBlockStage {
+ Core,
English,
Professional,
Extra,
@@ -49,53 +47,67 @@ export enum SuperBlockStages {
Upcoming
}
-export type SuperBlockOrder = {
- [key in SuperBlockStages]: SuperBlocks[];
+const defaultStageOrder = [
+ SuperBlockStage.Core,
+ SuperBlockStage.English,
+ SuperBlockStage.Professional,
+ SuperBlockStage.Extra,
+ SuperBlockStage.Legacy
+];
+
+export function getStageOrder({
+ showNewCurriculum,
+ showUpcomingChanges
+}: Config): SuperBlockStage[] {
+ const stageOrder = [...defaultStageOrder];
+
+ if (showNewCurriculum) stageOrder.push(SuperBlockStage.New);
+ if (showUpcomingChanges) stageOrder.push(SuperBlockStage.Upcoming);
+ return stageOrder;
+}
+
+export type StageMap = {
+ [key in SuperBlockStage]: SuperBlocks[];
};
-// order of buttons on map, this should include all superblocks
-// new and upcoming superblocks are removed below
-export const superBlockOrder: SuperBlockOrder = {
- [SuperBlockStages.FrontEnd]: [
+// Groups of superblocks in learn map. This should include all superblocks.
+export const superBlockStages: StageMap = {
+ [SuperBlockStage.Core]: [
SuperBlocks.RespWebDesignNew,
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.FrontEndDevLibs,
- SuperBlocks.DataVis
- ],
- [SuperBlockStages.Backend]: [
+ SuperBlocks.DataVis,
SuperBlocks.RelationalDb,
SuperBlocks.BackEndDevApis,
- SuperBlocks.QualityAssurance
- ],
- [SuperBlockStages.Python]: [
+ SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy,
SuperBlocks.CollegeAlgebraPy
],
- [SuperBlockStages.English]: [SuperBlocks.A2English],
- [SuperBlockStages.Professional]: [SuperBlocks.FoundationalCSharp],
- [SuperBlockStages.Extra]: [
+ [SuperBlockStage.English]: [SuperBlocks.A2English],
+ [SuperBlockStage.Professional]: [SuperBlocks.FoundationalCSharp],
+ [SuperBlockStage.Extra]: [
SuperBlocks.TheOdinProject,
SuperBlocks.CodingInterviewPrep,
SuperBlocks.ProjectEuler,
SuperBlocks.RosettaCode
],
- [SuperBlockStages.Legacy]: [
+ [SuperBlockStage.Legacy]: [
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.PythonForEverybody
],
- [SuperBlockStages.New]: [],
- [SuperBlockStages.Upcoming]: [
+ [SuperBlockStage.New]: [],
+ [SuperBlockStage.Upcoming]: [
SuperBlocks.B1English,
SuperBlocks.FrontEndDevelopment,
SuperBlocks.UpcomingPython
]
};
-Object.freeze(superBlockOrder);
+Object.freeze(superBlockStages);
type NotAuditedSuperBlocks = {
[key in Languages]: SuperBlocks[];
@@ -277,34 +289,10 @@ type LanguagesConfig = Config & {
language: string;
};
-// removes new and upcoming from superBlockOrder
-// not used yet, will be used when adding progress indicators to map
-export function createSuperBlockMap({
- showNewCurriculum,
- showUpcomingChanges
-}: Config): SuperBlockOrder {
- const superBlockMap = { ...superBlockOrder };
- if (!showNewCurriculum) {
- superBlockMap[SuperBlockStages.New] = [];
- }
- if (!showUpcomingChanges) {
- superBlockMap[SuperBlockStages.Upcoming] = [];
- }
- return superBlockMap;
-}
-
-export function createFlatSuperBlockMap({
- showNewCurriculum,
- showUpcomingChanges
-}: Config): SuperBlocks[] {
- const superBlockMap = { ...superBlockOrder };
- if (!showNewCurriculum) {
- superBlockMap[SuperBlockStages.New] = [];
- }
- if (!showUpcomingChanges) {
- superBlockMap[SuperBlockStages.Upcoming] = [];
- }
- return Object.values(superBlockMap).flat();
+export function createFlatSuperBlockMap(config: Config): SuperBlocks[] {
+ return getStageOrder(config)
+ .map(stage => superBlockStages[stage])
+ .flat();
}
export function getAuditedSuperBlocks({