Skip to content

Commit

Permalink
feat(client, curriculum): add support for blockLayout property (freeC…
Browse files Browse the repository at this point in the history
…odeCamp#56101)

Co-authored-by: Tom <[email protected]>
  • Loading branch information
huyenltnguyen and moT01 authored Oct 15, 2024
1 parent b3d4241 commit 815f029
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 10 deletions.
2 changes: 2 additions & 0 deletions client/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ exports.createPages = async function createPages({
challenge {
block
blockType
blockLayout
certification
challengeType
dashedName
Expand Down Expand Up @@ -260,6 +261,7 @@ exports.createSchemaCustomization = ({ actions }) => {
}
type Challenge {
blockType: String
blockLayout: String
challengeFiles: [FileContents]
explanation: String
notes: String
Expand Down
3 changes: 2 additions & 1 deletion client/src/redux/prop-types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HandlerProps } from 'react-reflex';
import { SuperBlocks } from '../../../shared/config/curriculum';
import { BlockTypes } from '../../../shared/config/blocks';
import { BlockLayouts, BlockTypes } from '../../../shared/config/blocks';
import { Themes } from '../components/settings/theme';
import { type CertTitle } from '../../config/cert-and-project-map';

Expand Down Expand Up @@ -167,6 +167,7 @@ export type ChallengeNode = {
challenge: {
block: string;
blockType: BlockTypes;
blockLayout: BlockLayouts;
certification: string;
challengeOrder: number;
challengeType: number;
Expand Down
48 changes: 39 additions & 9 deletions client/src/templates/Introduction/components/block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { ChallengeNode, CompletedChallenge } from '../../../redux/prop-types';
import { playTone } from '../../../utils/tone';
import { makeExpandedBlockSelector, toggleBlock } from '../redux';
import { isGridBased, isProjectBased } from '../../../utils/curriculum-layout';
import { BlockTypes } from '../../../../../shared/config/blocks';
import { BlockLayouts, BlockTypes } from '../../../../../shared/config/blocks';
import Challenges from './challenges';
import BlockLabel from './block-label';

Expand Down Expand Up @@ -151,7 +151,12 @@ class Block extends Component<BlockProps> {
</div>
);

const Block = (
/**
* ChallengeListBlock displays challenges in a list.
* This layout is used in backend blocks, The Odin Project blocks, and blocks in legacy certification.
* Example: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#basic-javascript
*/
const ChallengeListBlock = (
<>
{' '}
<ScrollableAnchor id={block}>
Expand Down Expand Up @@ -209,7 +214,12 @@ class Block extends Component<BlockProps> {
</>
);

const ProjectBlock = (
/**
* ProjectListBlock displays a list of certification projects.
* This layout is used in legacy certifications.
* Example: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#javascript-algorithms-and-data-structures-projects
*/
const ProjectListBlock = (
<>
<ScrollableAnchor id={block}>
<div className='block'>
Expand Down Expand Up @@ -247,7 +257,12 @@ class Block extends Component<BlockProps> {
return `${percentageCompleted}% ${t('learn.completed')}`;
};

const GridBlock = (
/**
* ChallengeGridBlock displays challenges in a grid.
* This layout is used for step-based blocks.
* Example: https://www.freecodecamp.org/learn/2022/responsive-web-design/#learn-html-by-building-a-cat-photo-app
*/
const ChallengeGridBlock = (
<>
{' '}
<ScrollableAnchor id={block}>
Expand Down Expand Up @@ -304,7 +319,12 @@ class Block extends Component<BlockProps> {
</>
);

const GridProjectBlock = (
/**
* LinkBlock displays the block as a single link.
* This layout is used if the block has a single challenge.
* Example: https://www.freecodecamp.org/learn/2022/responsive-web-design/#build-a-survey-form-project
*/
const LinkBlock = (
<ScrollableAnchor id={block}>
<div className='block block-grid grid-project-block'>
<div className='tags-wrapper'>
Expand Down Expand Up @@ -346,14 +366,24 @@ class Block extends Component<BlockProps> {
</ScrollableAnchor>
);

const blockrenderer = () => {
if (isProjectBlock) return isGridBlock ? GridProjectBlock : ProjectBlock;
return isGridBlock ? GridBlock : Block;
const blockRenderer = () => {
const blockLayout = challenges[0].blockLayout;

// `blockLayout` property isn't available in all challenges
if (!blockLayout) {
if (isProjectBlock) return isGridBlock ? LinkBlock : ProjectListBlock;
return isGridBlock ? ChallengeGridBlock : ChallengeListBlock;
}

if (blockLayout === BlockLayouts.ChallengeGrid) return ChallengeGridBlock;
if (blockLayout === BlockLayouts.ChallengeList) return ChallengeListBlock;
if (blockLayout === BlockLayouts.Link) return LinkBlock;
if (blockLayout === BlockLayouts.ProjectList) return ProjectListBlock;
};

return (
<>
{blockrenderer()}
{blockRenderer()}
{isGridBlock && !isProjectBlock ? null : <Spacer size='medium' />}
</>
);
Expand Down
1 change: 1 addition & 0 deletions client/src/templates/Introduction/super-block-intro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ export const query = graphql`
order
superBlock
dashedName
blockLayout
}
}
}
Expand Down
1 change: 1 addition & 0 deletions curriculum/get-challenges.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ function generateChallengeCreator(lang, englishPath, i18nPath) {

challenge.block = meta.dashedName;
challenge.blockType = meta.blockType;
challenge.blockLayout = meta.blockLayout;
challenge.hasEditableBoundaries = !!meta.hasEditableBoundaries;
challenge.order = meta.order;
// const superOrder = getSuperOrder(meta.superBlock);
Expand Down
9 changes: 9 additions & 0 deletions curriculum/schema/__snapshots__/challenge-schema.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@ const schema = Joi.object()
).required(),
otherwise: Joi.valid(null)
}),
blockLayout: Joi.when('superBlock', {
is: [SuperBlocks.FrontEndDevelopment],
then: Joi.valid(
'challenge-list',
'challenge-grid',
'link',
'project-list'
)
}),
challengeOrder: Joi.number(),
certification: Joi.string().regex(slugWithSlashRE),
challengeType: Joi.number().min(0).max(23).required(),
Expand Down
9 changes: 9 additions & 0 deletions curriculum/schema/challenge-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ const schema = Joi.object()
).required(),
otherwise: Joi.valid(null)
}),
blockLayout: Joi.when('superBlock', {
is: [SuperBlocks.FrontEndDevelopment],
then: Joi.valid(
'challenge-list',
'challenge-grid',
'link',
'project-list'
)
}),
challengeOrder: Joi.number(),
certification: Joi.string().regex(slugWithSlashRE),
challengeType: Joi.number().min(0).max(23).required(),
Expand Down
6 changes: 6 additions & 0 deletions curriculum/schema/meta-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ const schema = Joi.object()
.keys({
name: Joi.string().required(),
blockType: Joi.valid('workshop', 'lab', 'lecture', 'quiz', 'exam'),
blockLayout: Joi.valid(
'challenge-list',
'challenge-grid',
'link',
'project-list'
),
isUpcomingChange: Joi.boolean().required(),
dashedName: Joi.string().regex(slugRE).required(),
superBlock: Joi.string().regex(slugWithSlashRE).required(),
Expand Down
30 changes: 30 additions & 0 deletions shared/config/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,33 @@ export enum BlockTypes {
quiz = 'quiz',
exam = 'exam'
}

export enum BlockLayouts {
/**
* ChallengeList displays challenges in a list.
* This layout is used in backend blocks, The Odin Project blocks, and blocks in legacy certification.
* Example: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#basic-javascript
*/
ChallengeList = 'challenge-list',

/**
* ChallengeGrid displays challenges in a grid.
* This layout is used for step-based blocks.
* Example: https://www.freecodecamp.org/learn/2022/responsive-web-design/#learn-html-by-building-a-cat-photo-app
*/
ChallengeGrid = 'challenge-grid',

/**
* Link displays the block as a single link.
* This layout is used if the block has a single challenge.
* Example: https://www.freecodecamp.org/learn/2022/responsive-web-design/#build-a-survey-form-project
*/
Link = 'link',

/**
* ProjectList displays a list of certification projects.
* This layout is used in legacy certifications.
* Example: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#javascript-algorithms-and-data-structures-projects
*/
ProjectList = 'project-list'
}

0 comments on commit 815f029

Please sign in to comment.