-
Notifications
You must be signed in to change notification settings - Fork 2
1210 story prompt builder #1451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development/lab15
Are you sure you want to change the base?
Changes from all commits
506b9c9
70e4269
22a9a7f
8d41f5a
e4692c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,48 +1,142 @@ | ||
| 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 { | ||
| 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 { 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 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 ( | ||
| <div className="tw-flex tw-flex-col tw-w-full tw-h-full tw-min-h-0 tw-overflow-hidden"> | ||
| <div className="tw-px-6 tw-pt-6 tw-pb-4 tw-shrink-0 md:tw-px-0 md:tw-pt-0 md:tw-pb-0"> | ||
| <h1 className="tw-title tw-text-left">Exercise Start</h1> | ||
| <h1 className="tw-title tw-text-left">{PROMPT_BUILDER_HEADING}</h1> | ||
| <p className="tw-body-text tw-text-left tw-py-6"> | ||
| Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do | ||
| eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad | ||
| minim veniam. | ||
| {PROMPT_BUILDER_DESCRIPTION} | ||
| </p> | ||
| </div> | ||
|
|
||
| <div className="tw-flex tw-flex-col md:tw-flex-row tw-flex-1 tw-min-h-0 tw-overflow-hidden"> | ||
| {/* Left Panel */} | ||
| <div className="tw-flex-1 tw-overflow-y-auto tw-p-6"> | ||
| <div className="tw-border-solid tw-border-b-labGray tw-p-4"> | ||
| {/* QUIZ COMPONENT TO BE ADDED */} | ||
| <div className="tw-flex tw-items-center tw-justify-between tw-mb-4 tw-gap-3"> | ||
| <h2 className="tw-text-xl tw-font-bold tw-text-darkGray tw-capitalize"> | ||
| {currentStage} | ||
| </h2> | ||
| <div className="tw-text-sm tw-font-semibold tw-text-darkGray"> | ||
| Score: {totalScore}/{passingScore} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should Score: "n/6" be visible during selection? It may lead to students selecting choices for score rather than choosing the best answer. It'd be best to hide it until they click complete, allowing them to see the completion message popup under the quiz. |
||
| </div> | ||
| </div> | ||
|
|
||
| <Quiz | ||
| isFinalQuiz | ||
| answer={""} | ||
| answerOptions={quizAnswerOptions} | ||
| disable={!canMoveToNextStage} | ||
| multiChoice={false} | ||
| multiSelectedEntry={() => {}} | ||
| nextQuestion={handleNext} | ||
| lastQuestion={handleBack} | ||
| onAnswerSelected={handleAnswerSelected} | ||
| onComplete={() => { | ||
| clearJustLockedKey(); | ||
| requestAnimationFrame(() => { | ||
| lockCurrentStage(); | ||
| }); | ||
| }} | ||
| questionId={currentStageIndex + 1} | ||
| question={PROMPT_QUESTION_TEMPLATE.replace( | ||
| "{label}", | ||
| questionLabel, | ||
| )} | ||
| questionTotal={stages.length} | ||
| /> | ||
|
|
||
| {allStagesAnswered && ( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. allStagesAnswered is currently based on selections so the second user clicks an option on phase 4, it completes before the user clicks the complete button., removing the point of the complete button. You can use lockedStages instead so completion happens only after all stages are locked (complete button is clicked/all sentence sections are green) |
||
| <div className="tw-mt-6 tw-p-4 tw-rounded-lg tw-border tw-border-darkLine tw-bg-secondary-gray/60"> | ||
| <div className="tw-font-semibold tw-text-darkGray"> | ||
| {hasMetPassingScore | ||
| ? PROMPT_COMPLETE_PASSED_MESSAGE | ||
| : PROMPT_COMPLETE_FAILED_MESSAGE} | ||
| </div> | ||
| </div> | ||
| )} | ||
| </div> | ||
|
|
||
| {/* Divider */} | ||
| <div | ||
| aria-hidden="true" | ||
| className="tw-h-px md:tw-h-auto md:tw-w-px tw-w-full tw-bg-bgdark tw-shrink-0" | ||
| /> | ||
|
|
||
| {/* Right Panel */} | ||
| <div className="tw-flex-1 tw-overflow-y-auto tw-p-6 tw-bg-white"> | ||
| <PromptViewer | ||
| sections={GCSE_SECTIONS} | ||
|
|
@@ -53,14 +147,15 @@ const ModelRepair = () => { | |
| /> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div className="tw-mt-5"> | ||
| <LabButton | ||
| label="Next" | ||
| onClick={() => navigate("/Lab15/Exercise/model-repair")} | ||
| onClick={() => navigate("/Lab15/Exercise/model-with-grades")} | ||
| /> | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default ModelRepair; | ||
| export default PromptBuilder; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is what's causing the non-green state when the sentence section locks.
the nextStage func and lockCurrentStage are happening almost simultaneously, then justLockedKey is cleared immediately.
Call lockCurrentStage first, then delay nextStage and clearJustLockedKey so the pop animation finishes before moving onto the next stage