Skip to content

Commit b4706ee

Browse files
committed
feat: add scale question type to quiz functionality
- Introduced a new question type 'scale' that allows instructors to set a target value on a scale for quiz questions. - Updated relevant components to support the scale question type, including the addition of FormScale for handling scale configurations and answers. - Enhanced the QuestionList and QuestionConditions components to include the scale option with appropriate labels and icons. - Ensured proper integration with existing quiz handling logic and validation processes.
1 parent e28f93e commit b4706ee

8 files changed

Lines changed: 456 additions & 0 deletions

File tree

assets/src/js/v3/entries/course-builder/components/curriculum/Question.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const questionTypeIconMap: Record<Exclude<QuizQuestionType, 'single_choice' | 'i
4242
draw_image: 'quizImageAnswer',
4343
pin_image: 'quizImageAnswer',
4444
coordinates: 'quizImageAnswer',
45+
scale: 'quizImageAnswer',
4546
h5p: 'quizH5p',
4647
};
4748

assets/src/js/v3/entries/course-builder/components/curriculum/QuestionConditions.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ const questionTypes = {
6262
label: __('Coordinates', 'tutor'),
6363
icon: 'quizImageAnswer',
6464
},
65+
scale: {
66+
label: __('Scale', 'tutor'),
67+
icon: 'quizImageAnswer',
68+
},
6569
h5p: {
6670
label: __('H5P', 'tutor'),
6771
icon: 'quizTrueFalse',

assets/src/js/v3/entries/course-builder/components/curriculum/QuestionForm.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import TrueFalse from '@CourseBuilderComponents/curriculum/question-types/TrueFa
1818
import DrawImage from '@CourseBuilderComponents/curriculum/question-types/DrawImage';
1919
import PinImage from '@CourseBuilderComponents/curriculum/question-types/PinImage';
2020
import Coordinates from '@CourseBuilderComponents/curriculum/question-types/Coordinates';
21+
import Scale from '@CourseBuilderComponents/curriculum/question-types/Scale';
2122
import { useQuizModalContext } from '@CourseBuilderContexts/QuizModalContext';
2223

2324
import { tutorConfig } from '@TutorShared/config/config';
@@ -60,6 +61,7 @@ const QuestionForm = () => {
6061
draw_image: <DrawImage key={activeQuestionId} />,
6162
pin_image: <PinImage key={activeQuestionId} />,
6263
coordinates: <Coordinates key={activeQuestionId} />,
64+
scale: <Scale key={activeQuestionId} />,
6365
} as const;
6466

6567
useEffect(() => {

assets/src/js/v3/entries/course-builder/components/curriculum/QuestionList.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ const questionTypeOptions: {
122122
icon: 'quizImageAnswer',
123123
isPro: true,
124124
},
125+
{
126+
label: __('Scale', 'tutor'),
127+
value: 'scale',
128+
icon: 'quizImageAnswer',
129+
isPro: true,
130+
},
125131
];
126132

127133
const isTutorPro = !!tutorConfig.tutor_pro_url;
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { css } from '@emotion/react';
2+
import { useEffect } from 'react';
3+
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
4+
5+
import { useQuizModalContext } from '@CourseBuilderContexts/QuizModalContext';
6+
import type { QuizForm } from '@CourseBuilderServices/quiz';
7+
import FormScale from '@TutorShared/components/fields/quiz/questions/FormScale';
8+
import { spacing } from '@TutorShared/config/styles';
9+
import { styleUtils } from '@TutorShared/utils/style-utils';
10+
import { QuizDataStatus, type QuizQuestionOption } from '@TutorShared/utils/types';
11+
import { nanoid } from '@TutorShared/utils/util';
12+
13+
const Scale = () => {
14+
const form = useFormContext<QuizForm>();
15+
const { activeQuestionId, activeQuestionIndex, validationError, setValidationError } = useQuizModalContext();
16+
17+
const answersPath = `questions.${activeQuestionIndex}.question_answers` as 'questions.0.question_answers';
18+
19+
const { fields: optionsFields } = useFieldArray({
20+
control: form.control,
21+
name: answersPath,
22+
});
23+
24+
useEffect(() => {
25+
if (!activeQuestionId) {
26+
return;
27+
}
28+
if (optionsFields.length > 0) {
29+
return;
30+
}
31+
const baseAnswer: QuizQuestionOption = {
32+
_data_status: QuizDataStatus.NEW,
33+
is_saved: false,
34+
answer_id: nanoid(),
35+
belongs_question_id: activeQuestionId,
36+
belongs_question_type: 'scale' as QuizQuestionOption['belongs_question_type'],
37+
answer_title: '',
38+
is_correct: '1',
39+
image_id: undefined,
40+
image_url: '',
41+
answer_two_gap_match: JSON.stringify({
42+
value: 50,
43+
config: {
44+
min: 0,
45+
max: 100,
46+
step: 1,
47+
defaultValue: 50,
48+
pxPerUnit: 10,
49+
labelEvery: 10,
50+
minorTickEvery: 5,
51+
precision: 0,
52+
},
53+
}),
54+
answer_view_format: 'scale',
55+
answer_order: 0,
56+
};
57+
form.setValue(answersPath, [baseAnswer]);
58+
}, [activeQuestionId, optionsFields.length, answersPath, form]);
59+
60+
if (optionsFields.length === 0) {
61+
return null;
62+
}
63+
64+
return (
65+
<div css={styles.optionWrapper}>
66+
<Controller
67+
key={JSON.stringify(optionsFields[0])}
68+
control={form.control}
69+
name={`questions.${activeQuestionIndex}.question_answers.0` as 'questions.0.question_answers.0'}
70+
render={(controllerProps) => (
71+
<FormScale
72+
{...controllerProps}
73+
questionId={activeQuestionId}
74+
validationError={validationError}
75+
setValidationError={setValidationError}
76+
/>
77+
)}
78+
/>
79+
</div>
80+
);
81+
};
82+
83+
export default Scale;
84+
85+
const styles = {
86+
optionWrapper: css`
87+
${styleUtils.display.flex('column')};
88+
padding-left: ${spacing[40]};
89+
`,
90+
};

0 commit comments

Comments
 (0)