From 506b9c937782fdb82f0b8a7af28da94f1cf9946f Mon Sep 17 00:00:00 2001 From: Kristen Fang Date: Mon, 30 Mar 2026 15:30:36 -0400 Subject: [PATCH 1/4] making the actions a hash --- .../lab15/components/PromptStateManager.js | 200 ++++++++++++++++++ .../exercise/lab15/pages/PromptBuilder.js | 66 ------ 2 files changed, 200 insertions(+), 66 deletions(-) create mode 100644 client/src/components/exercise/lab15/components/PromptStateManager.js delete mode 100644 client/src/components/exercise/lab15/pages/PromptBuilder.js diff --git a/client/src/components/exercise/lab15/components/PromptStateManager.js b/client/src/components/exercise/lab15/components/PromptStateManager.js new file mode 100644 index 000000000..288a44008 --- /dev/null +++ b/client/src/components/exercise/lab15/components/PromptStateManager.js @@ -0,0 +1,200 @@ +import { useMemo, useReducer } from "react"; + +// Ordered flow for the prompt builder UI +export const PROMPT_BUILDER_STAGES = [ + "goal", + "context", + "sources", + "expectations", +]; + +// Minimum score to consider the prompt ready +export const DEFAULT_PASSING_SCORE = 6; + +const ACTIONS = { + SELECT_STAGE_OPTION: "SELECT_STAGE_OPTION", + LOCK_CURRENT_STAGE: "LOCK_CURRENT_STAGE", + CLEAR_JUST_LOCKED: "CLEAR_JUST_LOCKED", + MOVE_STAGE: "MOVE_STAGE", + SET_STAGE_INDEX: "SET_STAGE_INDEX", + RESET: "RESET", +}; + +const buildEmptyStageMap = (defaultValue) => + PROMPT_BUILDER_STAGES.reduce((acc, stage) => { + acc[stage] = defaultValue; + return acc; + }, {}); + +const buildInitialState = (passingScore = DEFAULT_PASSING_SCORE) => ({ + currentStageIndex: 0, + passingScore, + selections: buildEmptyStageMap(null), + scores: buildEmptyStageMap(0), + lockedStages: buildEmptyStageMap(false), + justLockedKey: null, +}); + +// Preventing going below and above the available stages +const clampStageIndex = (index) => + Math.max(0, Math.min(index, PROMPT_BUILDER_STAGES.length - 1)); + +const getTotalScore = (scores) => + Object.values(scores).reduce((total, score) => total + score, 0); + +// Helper to determine if a stage has an answer +const hasSelection = (selection) => selection !== null && selection !== ""; + +const hasStageSelection = (state, stage) => + hasSelection(state.selections[stage]); + +const handleSelectStageOption = (state, action) => { + const { stage, value, score = 0 } = action.payload; + + if (!PROMPT_BUILDER_STAGES.includes(stage)) { + return state; + } + + return { + ...state, + selections: { + ...state.selections, + [stage]: value, + }, + scores: { + ...state.scores, + [stage]: score, + }, + }; +}; + +const handleLockCurrentStage = (state) => { + const stage = PROMPT_BUILDER_STAGES[state.currentStageIndex]; + if (!hasStageSelection(state, stage)) { + return state; + } + + return { + ...state, + lockedStages: { + ...state.lockedStages, + [stage]: true, + }, + justLockedKey: stage, + }; +}; + +const handleClearJustLocked = (state) => ({ + ...state, + justLockedKey: null, +}); + +const handleMoveStage = (state, action) => { + const delta = action.payload?.delta ?? 0; + return { + ...state, + currentStageIndex: clampStageIndex(state.currentStageIndex + delta), + justLockedKey: null, + }; +}; + +const handleSetStageIndex = (state, action) => ({ + ...state, + currentStageIndex: clampStageIndex(action.payload.index), + justLockedKey: null, +}); + +const handleReset = (state) => buildInitialState(state.passingScore); + +const ACTION_HANDLERS = { + [ACTIONS.SELECT_STAGE_OPTION]: handleSelectStageOption, + [ACTIONS.LOCK_CURRENT_STAGE]: handleLockCurrentStage, + [ACTIONS.CLEAR_JUST_LOCKED]: handleClearJustLocked, + [ACTIONS.MOVE_STAGE]: handleMoveStage, + [ACTIONS.SET_STAGE_INDEX]: handleSetStageIndex, + [ACTIONS.RESET]: handleReset, +}; + +// With the current state and the next action, determine which stage to go to +export const promptBuilderStageReducer = (state, action) => { + const handler = ACTION_HANDLERS[action.type]; + if (!handler) { + return state; + } + return handler(state, action); +}; + +export const usePromptBuilderStageManager = ({ + passingScore = DEFAULT_PASSING_SCORE, +} = {}) => { + const [state, dispatch] = useReducer( + promptBuilderStageReducer, + passingScore, + buildInitialState, + ); + + const currentStage = PROMPT_BUILDER_STAGES[state.currentStageIndex]; + const totalScore = useMemo(() => getTotalScore(state.scores), [state.scores]); + + const allStagesAnswered = useMemo( + () => Object.values(state.selections).every(hasSelection), + [state.selections], + ); + + const canMoveToNextStage = hasStageSelection(state, currentStage); + const hasMetPassingScore = + allStagesAnswered && totalScore >= state.passingScore; + + const selectStageOption = (stage, value, score = 0) => { + dispatch({ + type: ACTIONS.SELECT_STAGE_OPTION, + payload: { stage, value, score }, + }); + }; + + const lockedKeys = useMemo( + () => PROMPT_BUILDER_STAGES.filter((stage) => state.lockedStages[stage]), + [state.lockedStages], + ); + + return { + ...state, + stages: PROMPT_BUILDER_STAGES, + currentStage, + currentSelection: state.selections[currentStage], + currentScore: state.scores[currentStage], + totalScore, + allStagesAnswered, + canMoveToNextStage, + lockedKeys, + hasMetPassingScore, + isPromptReadyToSubmit: hasMetPassingScore, + + // Selection helpers + selectStageOption, + selectGoal: (value, score = 0) => selectStageOption("goal", value, score), + selectContext: (value, score = 0) => + selectStageOption("context", value, score), + selectSource: (value, score = 0) => + selectStageOption("sources", value, score), + selectSources: (value, score = 0) => + selectStageOption("sources", value, score), + selectExpectation: (value, score = 0) => + selectStageOption("expectations", value, score), + selectExpectations: (value, score = 0) => + selectStageOption("expectations", value, score), + + // Navigation helpers + lockCurrentStage: () => dispatch({ type: ACTIONS.LOCK_CURRENT_STAGE }), + clearJustLockedKey: () => dispatch({ type: ACTIONS.CLEAR_JUST_LOCKED }), + nextStage: () => + dispatch({ type: ACTIONS.MOVE_STAGE, payload: { delta: 1 } }), + previousStage: () => + dispatch({ type: ACTIONS.MOVE_STAGE, payload: { delta: -1 } }), + goToStageIndex: (index) => + dispatch({ type: ACTIONS.SET_STAGE_INDEX, payload: { index } }), + resetPromptBuilder: () => dispatch({ type: ACTIONS.RESET }), + }; +}; + +export default usePromptBuilderStageManager; diff --git a/client/src/components/exercise/lab15/pages/PromptBuilder.js b/client/src/components/exercise/lab15/pages/PromptBuilder.js deleted file mode 100644 index 4e6292d20..000000000 --- a/client/src/components/exercise/lab15/pages/PromptBuilder.js +++ /dev/null @@ -1,66 +0,0 @@ -import { navigate } from "@reach/router"; -import React, { useState } from "react"; -import PromptViewer from "../components/PromptViewer"; -import { GCSE_SECTIONS } from "../../../../constants/lab15"; -import LabButton from "../../../all-components/LabButton"; - -const ModelRepair = () => { - const [sectionValues] = useState({ - values: GCSE_SECTIONS.reduce((acc, section) => { - acc[section.key] = null; - return acc; - }, {}), - activeIndex: 0, - lockedKeys: [], - justLockedKey: null, - }); - - const activeSection = GCSE_SECTIONS[sectionValues.activeIndex]; - const activeKey = activeSection?.key ?? null; - - return ( -
-
-

Exercise Start

-

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad - minim veniam. -

-
-
- {/* Left Panel */} -
-
- {/* QUIZ COMPONENT TO BE ADDED */} -
-
- - {/* Divider */} - -
- navigate("/Lab15/Exercise/model-repair")} - /> -
-
- ); -}; - -export default ModelRepair; From 70e426945ebdb5ba2afd868b2b05d359061c5261 Mon Sep 17 00:00:00 2001 From: Kristen Fang Date: Mon, 30 Mar 2026 15:32:41 -0400 Subject: [PATCH 2/4] Revert "making the actions a hash" This reverts commit 506b9c937782fdb82f0b8a7af28da94f1cf9946f. --- .../lab15/components/PromptStateManager.js | 200 ------------------ .../exercise/lab15/pages/PromptBuilder.js | 66 ++++++ 2 files changed, 66 insertions(+), 200 deletions(-) delete mode 100644 client/src/components/exercise/lab15/components/PromptStateManager.js create mode 100644 client/src/components/exercise/lab15/pages/PromptBuilder.js diff --git a/client/src/components/exercise/lab15/components/PromptStateManager.js b/client/src/components/exercise/lab15/components/PromptStateManager.js deleted file mode 100644 index 288a44008..000000000 --- a/client/src/components/exercise/lab15/components/PromptStateManager.js +++ /dev/null @@ -1,200 +0,0 @@ -import { useMemo, useReducer } from "react"; - -// Ordered flow for the prompt builder UI -export const PROMPT_BUILDER_STAGES = [ - "goal", - "context", - "sources", - "expectations", -]; - -// Minimum score to consider the prompt ready -export const DEFAULT_PASSING_SCORE = 6; - -const ACTIONS = { - SELECT_STAGE_OPTION: "SELECT_STAGE_OPTION", - LOCK_CURRENT_STAGE: "LOCK_CURRENT_STAGE", - CLEAR_JUST_LOCKED: "CLEAR_JUST_LOCKED", - MOVE_STAGE: "MOVE_STAGE", - SET_STAGE_INDEX: "SET_STAGE_INDEX", - RESET: "RESET", -}; - -const buildEmptyStageMap = (defaultValue) => - PROMPT_BUILDER_STAGES.reduce((acc, stage) => { - acc[stage] = defaultValue; - return acc; - }, {}); - -const buildInitialState = (passingScore = DEFAULT_PASSING_SCORE) => ({ - currentStageIndex: 0, - passingScore, - selections: buildEmptyStageMap(null), - scores: buildEmptyStageMap(0), - lockedStages: buildEmptyStageMap(false), - justLockedKey: null, -}); - -// Preventing going below and above the available stages -const clampStageIndex = (index) => - Math.max(0, Math.min(index, PROMPT_BUILDER_STAGES.length - 1)); - -const getTotalScore = (scores) => - Object.values(scores).reduce((total, score) => total + score, 0); - -// Helper to determine if a stage has an answer -const hasSelection = (selection) => selection !== null && selection !== ""; - -const hasStageSelection = (state, stage) => - hasSelection(state.selections[stage]); - -const handleSelectStageOption = (state, action) => { - const { stage, value, score = 0 } = action.payload; - - if (!PROMPT_BUILDER_STAGES.includes(stage)) { - return state; - } - - return { - ...state, - selections: { - ...state.selections, - [stage]: value, - }, - scores: { - ...state.scores, - [stage]: score, - }, - }; -}; - -const handleLockCurrentStage = (state) => { - const stage = PROMPT_BUILDER_STAGES[state.currentStageIndex]; - if (!hasStageSelection(state, stage)) { - return state; - } - - return { - ...state, - lockedStages: { - ...state.lockedStages, - [stage]: true, - }, - justLockedKey: stage, - }; -}; - -const handleClearJustLocked = (state) => ({ - ...state, - justLockedKey: null, -}); - -const handleMoveStage = (state, action) => { - const delta = action.payload?.delta ?? 0; - return { - ...state, - currentStageIndex: clampStageIndex(state.currentStageIndex + delta), - justLockedKey: null, - }; -}; - -const handleSetStageIndex = (state, action) => ({ - ...state, - currentStageIndex: clampStageIndex(action.payload.index), - justLockedKey: null, -}); - -const handleReset = (state) => buildInitialState(state.passingScore); - -const ACTION_HANDLERS = { - [ACTIONS.SELECT_STAGE_OPTION]: handleSelectStageOption, - [ACTIONS.LOCK_CURRENT_STAGE]: handleLockCurrentStage, - [ACTIONS.CLEAR_JUST_LOCKED]: handleClearJustLocked, - [ACTIONS.MOVE_STAGE]: handleMoveStage, - [ACTIONS.SET_STAGE_INDEX]: handleSetStageIndex, - [ACTIONS.RESET]: handleReset, -}; - -// With the current state and the next action, determine which stage to go to -export const promptBuilderStageReducer = (state, action) => { - const handler = ACTION_HANDLERS[action.type]; - if (!handler) { - return state; - } - return handler(state, action); -}; - -export const usePromptBuilderStageManager = ({ - passingScore = DEFAULT_PASSING_SCORE, -} = {}) => { - const [state, dispatch] = useReducer( - promptBuilderStageReducer, - passingScore, - buildInitialState, - ); - - const currentStage = PROMPT_BUILDER_STAGES[state.currentStageIndex]; - const totalScore = useMemo(() => getTotalScore(state.scores), [state.scores]); - - const allStagesAnswered = useMemo( - () => Object.values(state.selections).every(hasSelection), - [state.selections], - ); - - const canMoveToNextStage = hasStageSelection(state, currentStage); - const hasMetPassingScore = - allStagesAnswered && totalScore >= state.passingScore; - - const selectStageOption = (stage, value, score = 0) => { - dispatch({ - type: ACTIONS.SELECT_STAGE_OPTION, - payload: { stage, value, score }, - }); - }; - - const lockedKeys = useMemo( - () => PROMPT_BUILDER_STAGES.filter((stage) => state.lockedStages[stage]), - [state.lockedStages], - ); - - return { - ...state, - stages: PROMPT_BUILDER_STAGES, - currentStage, - currentSelection: state.selections[currentStage], - currentScore: state.scores[currentStage], - totalScore, - allStagesAnswered, - canMoveToNextStage, - lockedKeys, - hasMetPassingScore, - isPromptReadyToSubmit: hasMetPassingScore, - - // Selection helpers - selectStageOption, - selectGoal: (value, score = 0) => selectStageOption("goal", value, score), - selectContext: (value, score = 0) => - selectStageOption("context", value, score), - selectSource: (value, score = 0) => - selectStageOption("sources", value, score), - selectSources: (value, score = 0) => - selectStageOption("sources", value, score), - selectExpectation: (value, score = 0) => - selectStageOption("expectations", value, score), - selectExpectations: (value, score = 0) => - selectStageOption("expectations", value, score), - - // Navigation helpers - lockCurrentStage: () => dispatch({ type: ACTIONS.LOCK_CURRENT_STAGE }), - clearJustLockedKey: () => dispatch({ type: ACTIONS.CLEAR_JUST_LOCKED }), - nextStage: () => - dispatch({ type: ACTIONS.MOVE_STAGE, payload: { delta: 1 } }), - previousStage: () => - dispatch({ type: ACTIONS.MOVE_STAGE, payload: { delta: -1 } }), - goToStageIndex: (index) => - dispatch({ type: ACTIONS.SET_STAGE_INDEX, payload: { index } }), - resetPromptBuilder: () => dispatch({ type: ACTIONS.RESET }), - }; -}; - -export default usePromptBuilderStageManager; diff --git a/client/src/components/exercise/lab15/pages/PromptBuilder.js b/client/src/components/exercise/lab15/pages/PromptBuilder.js new file mode 100644 index 000000000..4e6292d20 --- /dev/null +++ b/client/src/components/exercise/lab15/pages/PromptBuilder.js @@ -0,0 +1,66 @@ +import { navigate } from "@reach/router"; +import React, { useState } from "react"; +import PromptViewer from "../components/PromptViewer"; +import { GCSE_SECTIONS } from "../../../../constants/lab15"; +import LabButton from "../../../all-components/LabButton"; + +const ModelRepair = () => { + const [sectionValues] = useState({ + values: GCSE_SECTIONS.reduce((acc, section) => { + acc[section.key] = null; + return acc; + }, {}), + activeIndex: 0, + lockedKeys: [], + justLockedKey: null, + }); + + const activeSection = GCSE_SECTIONS[sectionValues.activeIndex]; + const activeKey = activeSection?.key ?? null; + + return ( +
+
+

Exercise Start

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam. +

+
+
+ {/* Left Panel */} +
+
+ {/* QUIZ COMPONENT TO BE ADDED */} +
+
+ + {/* Divider */} + +
+ navigate("/Lab15/Exercise/model-repair")} + /> +
+
+ ); +}; + +export default ModelRepair; From 8d41f5ae238bda97eb6d56c66a9f03b450e46f1f Mon Sep 17 00:00:00 2001 From: Kristen Fang Date: Wed, 1 Apr 2026 15:14:27 -0400 Subject: [PATCH 3/4] rerouted the prompt builder to be after the ide fix --- client/src/components/exercise/lab15/Main.js | 2 +- .../exercise/lab15/pages/ModelRepair.js | 2 +- .../exercise/lab15/pages/PromptBuilder.js | 190 +++++++++++++++--- 3 files changed, 165 insertions(+), 29 deletions(-) diff --git a/client/src/components/exercise/lab15/Main.js b/client/src/components/exercise/lab15/Main.js index c2c39f533..81f0af49c 100644 --- a/client/src/components/exercise/lab15/Main.js +++ b/client/src/components/exercise/lab15/Main.js @@ -32,8 +32,8 @@ const Main = () => { - + diff --git a/client/src/components/exercise/lab15/pages/ModelRepair.js b/client/src/components/exercise/lab15/pages/ModelRepair.js index 6065e4923..66ed0a8e4 100644 --- a/client/src/components/exercise/lab15/pages/ModelRepair.js +++ b/client/src/components/exercise/lab15/pages/ModelRepair.js @@ -34,7 +34,7 @@ const ModelRepair = () => { }, ]} navigateNext={() => { - navigate(`${EXERCISE_PATH}/model-with-grades`); + navigate(`${EXERCISE_PATH}/prompt-builder`); }} repairComplete /> diff --git a/client/src/components/exercise/lab15/pages/PromptBuilder.js b/client/src/components/exercise/lab15/pages/PromptBuilder.js index 4e6292d20..c95e9b688 100644 --- a/client/src/components/exercise/lab15/pages/PromptBuilder.js +++ b/client/src/components/exercise/lab15/pages/PromptBuilder.js @@ -1,48 +1,183 @@ import { navigate } from "@reach/router"; -import React, { useState } from "react"; + +import LabButton from "src/components/all-components/LabButton"; +import Quiz from "src/components/quiz/components/Quiz"; +import { GCSE_SECTIONS } from "src/constants/lab15"; import PromptViewer from "../components/PromptViewer"; -import { GCSE_SECTIONS } from "../../../../constants/lab15"; -import LabButton from "../../../all-components/LabButton"; - -const ModelRepair = () => { - const [sectionValues] = useState({ - values: GCSE_SECTIONS.reduce((acc, section) => { - acc[section.key] = null; - return acc; - }, {}), - activeIndex: 0, - lockedKeys: [], - justLockedKey: null, - }); - - const activeSection = GCSE_SECTIONS[sectionValues.activeIndex]; - const activeKey = activeSection?.key ?? null; +import usePromptBuilderStageManager from "../components/PromptStateManager"; + +const STAGE_OPTIONS = { + goal: [ + { + id: "goal-1", + text: "Help me with science.", + score: 1, + }, + { + id: "goal-2", + text: "Explain Newton's First Law in simple terms for a middle school student.", + score: 3, + }, + ], + context: [ + { + id: "context-1", + text: "I need this quickly.", + score: 1, + }, + { + id: "context-2", + text: "This is for a class recap and I struggled with motion and forces this week.", + score: 3, + }, + ], + sources: [ + { + id: "sources-1", + text: "Use anything online.", + score: 1, + }, + { + id: "sources-2", + text: "Use our textbook chapter on Forces and cite one trustworthy educational source.", + score: 3, + }, + ], + expectations: [ + { + id: "expectations-1", + text: "Make it short.", + score: 1, + }, + { + id: "expectations-2", + text: "Answer in 4 bullet points and include one real-world example.", + score: 3, + }, + ], +}; + +const PromptBuilder = () => { + const { + stages, + currentStage, + currentStageIndex, + selections, + lockedKeys, + justLockedKey, + totalScore, + passingScore, + canMoveToNextStage, + allStagesAnswered, + hasMetPassingScore, + selectStageOption, + lockCurrentStage, + clearJustLockedKey, + nextStage, + previousStage, + } = usePromptBuilderStageManager(); + + const activeOptions = STAGE_OPTIONS[currentStage] || []; + const isFinalStage = currentStageIndex === stages.length - 1; + + const handleNext = () => { + if (!canMoveToNextStage) return; + clearJustLockedKey(); + requestAnimationFrame(() => { + lockCurrentStage(); + }); + + if (!isFinalStage) { + nextStage(); + } + }; + + const handleBack = () => { + if (currentStageIndex === 0) return; + previousStage(); + }; + + const handleAnswerSelected = (event) => { + const optionIndex = Number(event.target.value); + const selectedOption = activeOptions[optionIndex]; + if (!selectedOption) return; + + selectStageOption(currentStage, selectedOption.text, selectedOption.score); + }; + + const quizAnswerOptions = activeOptions.map((option, index) => ({ + type: String(index), + content: option.text, + })); + + const questionLabel = + GCSE_SECTIONS[currentStageIndex]?.label || GCSE_SECTIONS[0].label; + + const sectionValues = { + values: selections, + lockedKeys, + justLockedKey, + }; + const activeKey = currentStage; return (

Exercise Start

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad - minim veniam. + Build your prompt section by section using GCSE. Choose the strongest + option in each category to improve your score.

+
- {/* Left Panel */}
-
- {/* QUIZ COMPONENT TO BE ADDED */} +
+

+ {currentStage} +

+
+ Score: {totalScore}/{passingScore} +
+ + {}} + nextQuestion={handleNext} + lastQuestion={handleBack} + onAnswerSelected={handleAnswerSelected} + onComplete={() => { + clearJustLockedKey(); + requestAnimationFrame(() => { + lockCurrentStage(); + }); + }} + questionId={currentStageIndex + 1} + question={`Choose the best ${questionLabel} statement for your prompt.`} + questionTotal={stages.length} + /> + + {allStagesAnswered && ( +
+
+ {hasMetPassingScore + ? "Prompt complete. You passed the quality threshold." + : "Prompt complete, but score is below passing. Improve your choices."} +
+
+ )}
- {/* Divider */} +
navigate("/Lab15/Exercise/model-repair")} + onClick={() => navigate("/Lab15/Exercise/model-with-grades")} />
); }; -export default ModelRepair; +export default PromptBuilder; From e4692c8f9f7f38b6f5cdd44c57674ed97b240333 Mon Sep 17 00:00:00 2001 From: Kristen Fang Date: Wed, 1 Apr 2026 15:20:09 -0400 Subject: [PATCH 4/4] putting the constants in the constants folder --- .../exercise/lab15/pages/PromptBuilder.js | 73 ++++--------------- .../constants/lab15/PromptBuilderConfig.js | 60 +++++++++++++++ 2 files changed, 76 insertions(+), 57 deletions(-) create mode 100644 client/src/constants/lab15/PromptBuilderConfig.js diff --git a/client/src/components/exercise/lab15/pages/PromptBuilder.js b/client/src/components/exercise/lab15/pages/PromptBuilder.js index c95e9b688..45f820de8 100644 --- a/client/src/components/exercise/lab15/pages/PromptBuilder.js +++ b/client/src/components/exercise/lab15/pages/PromptBuilder.js @@ -3,60 +3,17 @@ import { navigate } from "@reach/router"; import LabButton from "src/components/all-components/LabButton"; import Quiz from "src/components/quiz/components/Quiz"; import { GCSE_SECTIONS } from "src/constants/lab15"; +import { + PROMPT_BUILDER_DESCRIPTION, + PROMPT_BUILDER_HEADING, + PROMPT_COMPLETE_FAILED_MESSAGE, + PROMPT_COMPLETE_PASSED_MESSAGE, + PROMPT_QUESTION_TEMPLATE, + STAGE_OPTIONS, +} from "src/constants/lab15/PromptBuilderConfig"; import PromptViewer from "../components/PromptViewer"; import usePromptBuilderStageManager from "../components/PromptStateManager"; -const STAGE_OPTIONS = { - goal: [ - { - id: "goal-1", - text: "Help me with science.", - score: 1, - }, - { - id: "goal-2", - text: "Explain Newton's First Law in simple terms for a middle school student.", - score: 3, - }, - ], - context: [ - { - id: "context-1", - text: "I need this quickly.", - score: 1, - }, - { - id: "context-2", - text: "This is for a class recap and I struggled with motion and forces this week.", - score: 3, - }, - ], - sources: [ - { - id: "sources-1", - text: "Use anything online.", - score: 1, - }, - { - id: "sources-2", - text: "Use our textbook chapter on Forces and cite one trustworthy educational source.", - score: 3, - }, - ], - expectations: [ - { - id: "expectations-1", - text: "Make it short.", - score: 1, - }, - { - id: "expectations-2", - text: "Answer in 4 bullet points and include one real-world example.", - score: 3, - }, - ], -}; - const PromptBuilder = () => { const { stages, @@ -123,10 +80,9 @@ const PromptBuilder = () => { return (
-

Exercise Start

+

{PROMPT_BUILDER_HEADING}

- Build your prompt section by section using GCSE. Choose the strongest - option in each category to improve your score. + {PROMPT_BUILDER_DESCRIPTION}

@@ -158,7 +114,10 @@ const PromptBuilder = () => { }); }} questionId={currentStageIndex + 1} - question={`Choose the best ${questionLabel} statement for your prompt.`} + question={PROMPT_QUESTION_TEMPLATE.replace( + "{label}", + questionLabel, + )} questionTotal={stages.length} /> @@ -166,8 +125,8 @@ const PromptBuilder = () => {
{hasMetPassingScore - ? "Prompt complete. You passed the quality threshold." - : "Prompt complete, but score is below passing. Improve your choices."} + ? PROMPT_COMPLETE_PASSED_MESSAGE + : PROMPT_COMPLETE_FAILED_MESSAGE}
)} diff --git a/client/src/constants/lab15/PromptBuilderConfig.js b/client/src/constants/lab15/PromptBuilderConfig.js new file mode 100644 index 000000000..00a02906c --- /dev/null +++ b/client/src/constants/lab15/PromptBuilderConfig.js @@ -0,0 +1,60 @@ +export const STAGE_OPTIONS = { + goal: [ + { + id: "goal-1", + text: "Help me with science.", + score: 1, + }, + { + id: "goal-2", + text: "Explain Newton's First Law in simple terms for a middle school student.", + score: 3, + }, + ], + context: [ + { + id: "context-1", + text: "I need this quickly.", + score: 1, + }, + { + id: "context-2", + text: "This is for a class recap and I struggled with motion and forces this week.", + score: 3, + }, + ], + sources: [ + { + id: "sources-1", + text: "Use anything online.", + score: 1, + }, + { + id: "sources-2", + text: "Use our textbook chapter on Forces and cite one trustworthy educational source.", + score: 3, + }, + ], + expectations: [ + { + id: "expectations-1", + text: "Make it short.", + score: 1, + }, + { + id: "expectations-2", + text: "Answer in 4 bullet points and include one real-world example.", + score: 3, + }, + ], +}; + +export const PROMPT_BUILDER_HEADING = "Exercise Start"; +export const PROMPT_BUILDER_DESCRIPTION = + "Build your prompt section by section using GCSE. Choose the strongest option in each category to improve your score."; +export const PROMPT_COMPLETE_PASSED_MESSAGE = + "Prompt complete. You passed the quality threshold."; +export const PROMPT_COMPLETE_FAILED_MESSAGE = + "Prompt complete, but score is below passing. Improve your choices."; +export const PROMPT_QUESTION_TEMPLATE = + "Choose the best {label} statement for your prompt.";