From 32713ed842fb4e123c0b93c218ffa3a0e9b409e0 Mon Sep 17 00:00:00 2001 From: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com> Date: Thu, 28 May 2026 06:58:12 +0700 Subject: [PATCH] fix(client,curriculum): mark inputType as required for Chinese FITB challenges (#67221) --- client/schema.gql | 1 - client/src/redux/prop-types.ts | 4 +++- .../Challenges/components/fill-in-the-blanks.tsx | 9 +++++++-- .../templates/Challenges/fill-in-the-blank/show.tsx | 8 +++++--- .../__snapshots__/challenge-schema.test.mjs.snap | 13 +------------ curriculum/schema/challenge-schema.js | 5 ++--- .../parser/plugins/add-fill-in-the-blank.js | 2 +- .../parser/plugins/add-fill-in-the-blank.test.js | 2 +- 8 files changed, 20 insertions(+), 24 deletions(-) diff --git a/client/schema.gql b/client/schema.gql index 725dc5415bb..7e76feade0a 100644 --- a/client/schema.gql +++ b/client/schema.gql @@ -540,7 +540,6 @@ type ChallengeNodeChallengeSceneCommandsPosition { type ChallengeNodeChallengeFillInTheBlank @derivedTypes { sentence: String blanks: [ChallengeNodeChallengeFillInTheBlankBlanks] - inputType: String } type ChallengeNodeChallengeFillInTheBlankBlanks { diff --git a/client/src/redux/prop-types.ts b/client/src/redux/prop-types.ts index 9f3ae2891c7..fe7e19795df 100644 --- a/client/src/redux/prop-types.ts +++ b/client/src/redux/prop-types.ts @@ -43,9 +43,10 @@ export type Question = { export type FillInTheBlank = { sentence: string; blanks: MultipleChoiceAnswer[]; - inputType?: 'pinyin-tone' | 'pinyin-to-hanzi'; }; +export type FillInTheBlankInputType = 'pinyin-tone' | 'pinyin-to-hanzi'; + export type Fields = { slug: string; blockHashSlug: string; @@ -216,6 +217,7 @@ export type ChallengeNode = { helpCategory: string; hooks?: Hooks; id: string; + inputType?: FillInTheBlankInputType; lang?: ChallengeLang; instructions: string; internal?: { diff --git a/client/src/templates/Challenges/components/fill-in-the-blanks.tsx b/client/src/templates/Challenges/components/fill-in-the-blanks.tsx index ee315d9dd31..1100d43f543 100644 --- a/client/src/templates/Challenges/components/fill-in-the-blanks.tsx +++ b/client/src/templates/Challenges/components/fill-in-the-blanks.tsx @@ -4,13 +4,17 @@ import { Spacer } from '@freecodecamp/ui'; import { parseBlanks, parseAnswer } from '../fill-in-the-blank/parse-blanks'; import PrismFormatted from '../components/prism-formatted'; -import { FillInTheBlank } from '../../../redux/prop-types'; +import { + FillInTheBlankInputType, + FillInTheBlank +} from '../../../redux/prop-types'; import ChallengeHeading from './challenge-heading'; import PinyinToHanziInput from './pinyin-to-hanzi-input'; import PinyinToneInput from './pinyin-tone-input'; type FillInTheBlankProps = { fillInTheBlank: FillInTheBlank; + inputType?: FillInTheBlankInputType; answersCorrect: (boolean | null)[]; showFeedback: boolean; feedback: string | null; @@ -103,7 +107,8 @@ const BlankInput = ({ }; function FillInTheBlanks({ - fillInTheBlank: { sentence, blanks, inputType }, + fillInTheBlank: { sentence, blanks }, + inputType, answersCorrect, showFeedback, feedback, diff --git a/client/src/templates/Challenges/fill-in-the-blank/show.tsx b/client/src/templates/Challenges/fill-in-the-blank/show.tsx index e9594669fd2..7cd7882ac1b 100644 --- a/client/src/templates/Challenges/fill-in-the-blank/show.tsx +++ b/client/src/templates/Challenges/fill-in-the-blank/show.tsx @@ -92,6 +92,7 @@ const ShowFillInTheBlank = ({ translationPending, challengeType, fillInTheBlank, + inputType, helpCategory, scene, tests, @@ -181,7 +182,7 @@ const ShowFillInTheBlank = ({ const answer = blankAnswers[i]; const normalizedUserAnswer = userAnswer.trim().toLowerCase(); - if (fillInTheBlank.inputType === 'pinyin-to-hanzi') { + if (inputType === 'pinyin-to-hanzi') { const pairs = parseHanziPinyinPairs(answer); if (pairs.length === 1) { const hanziPinyin = pairs[0]; @@ -191,7 +192,7 @@ const ShowFillInTheBlank = ({ hanzi.replace(/\s+/g, '') ); } - } else if (fillInTheBlank.inputType === 'pinyin-tone') { + } else if (inputType === 'pinyin-tone') { // Ignore spaces to allow both syllable formats: // spaced (e.g., 'nǐ hǎo') and unspaced (e.g., 'nǐhǎo'). return ( @@ -302,6 +303,7 @@ const ShowFillInTheBlank = ({ should not be changed without informing the mobile t ], "type": "array", }, - "inputType": { - "allow": [ - "pinyin-tone", - "pinyin-to-hanzi", - ], - "flags": { - "only": true, - "presence": "optional", - }, - "type": "string", - }, "sentence": { "flags": { "presence": "required", @@ -629,7 +618,7 @@ exports[`challenge schema > should not be changed without informing the mobile t ], "flags": { "only": true, - "presence": "optional", + "presence": "required", }, "type": "string", }, diff --git a/curriculum/schema/challenge-schema.js b/curriculum/schema/challenge-schema.js index 59a1e7fc79e..144c21b2ab5 100644 --- a/curriculum/schema/challenge-schema.js +++ b/curriculum/schema/challenge-schema.js @@ -248,8 +248,7 @@ export const schema = Joi.object().keys({ feedback: Joi.string().allow(null) }) ) - .required(), - inputType: Joi.string().valid('pinyin-tone', 'pinyin-to-hanzi').optional() + .required() }), forumTopicId: Joi.number(), id: Joi.objectId().required(), @@ -262,7 +261,7 @@ export const schema = Joi.object().keys({ is: challengeTypes.fillInTheBlank, then: Joi.when('superBlock', { is: Joi.valid(SuperBlocks.A1Chinese, SuperBlocks.A2Chinese), - then: Joi.string().valid('pinyin-tone', 'pinyin-to-hanzi').optional(), + then: Joi.string().valid('pinyin-tone', 'pinyin-to-hanzi').required(), otherwise: Joi.forbidden() }), otherwise: Joi.forbidden() diff --git a/tools/challenge-parser/parser/plugins/add-fill-in-the-blank.js b/tools/challenge-parser/parser/plugins/add-fill-in-the-blank.js index ce35d6204db..37f0c2b6e2a 100644 --- a/tools/challenge-parser/parser/plugins/add-fill-in-the-blank.js +++ b/tools/challenge-parser/parser/plugins/add-fill-in-the-blank.js @@ -107,7 +107,7 @@ function plugin() { } } - return { sentence, blanks, ...(inputType && { inputType }) }; + return { sentence, blanks }; } function getBlanks(blanksNodes) { diff --git a/tools/challenge-parser/parser/plugins/add-fill-in-the-blank.test.js b/tools/challenge-parser/parser/plugins/add-fill-in-the-blank.test.js index f3332f10caf..ca5549735f6 100644 --- a/tools/challenge-parser/parser/plugins/add-fill-in-the-blank.test.js +++ b/tools/challenge-parser/parser/plugins/add-fill-in-the-blank.test.js @@ -198,7 +198,7 @@ Example of good formatting: plugin(mockChineseFillInTheBlankAST, file); const testObject = file.data.fillInTheBlank; - expect(testObject.inputType).toBe('pinyin-to-hanzi'); + expect(file.data.inputType).toBe('pinyin-to-hanzi'); expect(testObject.sentence).toBe( '

BLANK BLANK,BLANK 是王华(shì Wang Hua)请问你(qǐng wèn nǐ) BLANK 什么名字(shén me míng zi)

'