Skip to content

Commit 4f6e3b0

Browse files
committed
fix choices issue
1 parent bd0a9c9 commit 4f6e3b0

File tree

9 files changed

+69
-10
lines changed

9 files changed

+69
-10
lines changed

apps/api/src/api/assignment/attempt/attempt.service.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,8 +2511,8 @@ export class AttemptServiceV1 {
25112511
return { responseDto, learnerResponse };
25122512
}
25132513

2514-
private normalizeText(text: string): string {
2515-
return text
2514+
private normalizeText(text: string | number): string {
2515+
return String(text)
25162516
.trim()
25172517
.toLowerCase()
25182518

@@ -2953,6 +2953,26 @@ export class AttemptServiceV1 {
29532953
}),
29542954
);
29552955

2956+
// Parse learner response for multiple choice questions
2957+
let learnerChoices: string[] | undefined;
2958+
if (
2959+
(question.type === "SINGLE_CORRECT" ||
2960+
question.type === "MULTIPLE_CORRECT") &&
2961+
correspondingResponses.length > 0
2962+
) {
2963+
const learnerResponse = correspondingResponses[0]?.learnerResponse;
2964+
if (learnerResponse && typeof learnerResponse === "string") {
2965+
try {
2966+
const parsed: unknown = JSON.parse(learnerResponse);
2967+
if (Array.isArray(parsed)) {
2968+
learnerChoices = parsed as string[];
2969+
}
2970+
} catch {
2971+
// If parsing fails, learnerChoices remains undefined
2972+
}
2973+
}
2974+
}
2975+
29562976
return {
29572977
id: question.id,
29582978
variantId: extendedQuestion.variantId,
@@ -2972,6 +2992,7 @@ export class AttemptServiceV1 {
29722992
?.showRubricsToLearner
29732993
? question.scoring
29742994
: undefined,
2995+
learnerChoices,
29752996
};
29762997
});
29772998
}

apps/api/src/api/assignment/attempt/dto/assignment-attempt/get.assignment.attempt.response.dto.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,16 @@ export class AssignmentAttemptQuestions {
211211
})
212212
@Optional()
213213
variantId?: number;
214+
215+
@ApiPropertyOptional({
216+
description:
217+
"The learner's selected choices for multiple choice questions (array of choice indices as strings).",
218+
type: [String],
219+
required: false,
220+
})
221+
@Optional()
222+
learnerChoices?: string[];
223+
214224
@Optional()
215225
_permutation?: boolean;
216226
}

apps/api/src/api/assignment/dto/update.questions.request.dto.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
12
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
23
import {
34
AssignmentQuestionDisplayOrder,
@@ -6,7 +7,7 @@ import {
67
QuestionType,
78
ResponseType,
89
} from "@prisma/client";
9-
import { Type } from "class-transformer";
10+
import { Transform, Type } from "class-transformer";
1011
import {
1112
ArrayNotEmpty,
1213
IsArray,
@@ -31,6 +32,9 @@ export enum VariantType {
3132
export class Choice {
3233
@IsNotEmpty()
3334
@IsString()
35+
@Transform(({ value }) =>
36+
typeof value === "number" ? String(value) : (value as string),
37+
)
3438
choice: string;
3539

3640
@IsNotEmpty()

apps/api/src/api/assignment/question/dto/create.update.question.request.dto.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
22
import { QuestionType } from "@prisma/client";
3-
import { Type } from "class-transformer";
3+
import { Transform, Type } from "class-transformer";
44
import {
55
ArrayNotEmpty,
66
IsArray,
@@ -45,6 +45,9 @@ export interface LLMResponseQuestion {
4545
export class Choice {
4646
@IsNotEmpty()
4747
@IsString()
48+
@Transform(({ value }) =>
49+
typeof value === "number" ? String(value) : (value as string),
50+
)
4851
choice: string;
4952
@IsNotEmpty()
5053
@IsBoolean()

apps/api/src/api/attempt/common/utils/attempt-questions-mapper.util.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,13 @@ export class AttemptQuestionsMapper {
391391
if (!choices || typeof choices === "string") return [];
392392

393393
return choices
394-
.filter((c): c is Choice => !!c && typeof c.choice === "string")
394+
.filter(
395+
(c): c is Choice =>
396+
!!c && (typeof c.choice === "string" || typeof c.choice === "number"),
397+
)
395398
.map((c) => ({
396399
id: c.id === undefined ? null : c.id,
397-
choice: c.choice,
400+
choice: typeof c.choice === "number" ? String(c.choice) : c.choice,
398401
}));
399402
}
400403

apps/api/src/api/llm/llm-facade.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export class LlmFacadeService {
227227
rubrics?: RubricDto[];
228228
};
229229
choices?: {
230-
choice: string;
230+
choice: string | number;
231231
isCorrect: boolean;
232232
points: number;
233233
feedback: string;

apps/web/app/learner/(components)/Question/MultipleChoiceQuestion.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ function MultipleChoiceQuestion({
4040
<div className="flex flex-col gap-y-2 w-full">
4141
{choices.map((choice, index) => {
4242
const isSelected = learnerChoices?.includes(String(index));
43+
const choiceText =
44+
typeof choice === "string"
45+
? choice
46+
: typeof choice === "number"
47+
? String(choice)
48+
: choice?.choice;
4349

4450
return (
4551
<button
@@ -76,7 +82,7 @@ function MultipleChoiceQuestion({
7682
) : null}
7783
</span>
7884
<div className="whitespace-pre-wrap break-words hyphens-auto text-left overflow-hidden w-full">
79-
{choice.choice}
85+
{choiceText}
8086
</div>
8187
</div>
8288
</button>

apps/web/app/learner/[assignmentId]/successPage/Question.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ const Question: FC<Props> = ({
576576
<ul className="list-none text-gray-800 w-full flex flex-col justify-start gap-y-2">
577577
{choices.map((choiceObj, idx) => {
578578
const isSelected = Array.isArray(learnerResponse)
579-
? (learnerResponse as string[]).includes(choiceObj.choice)
579+
? (learnerResponse as string[]).includes(String(idx))
580580
: false;
581581

582582
const isCorrect = choiceObj.isCorrect;

apps/web/stores/learner.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,19 @@ export const useLearnerStore = createWithEqualityFn<
840840
const prevDataForQuestion = state.questions.find(
841841
(q2) => q2.id === q.id,
842842
);
843-
return prevDataForQuestion ? { ...prevDataForQuestion, ...q } : q;
843+
const questionData = prevDataForQuestion
844+
? { ...prevDataForQuestion, ...q }
845+
: q;
846+
847+
if (
848+
(!questionData.choices || questionData.choices.length === 0) &&
849+
(questionData as any).randomizedChoices &&
850+
Array.isArray((questionData as any).randomizedChoices)
851+
) {
852+
questionData.choices = (questionData as any).randomizedChoices;
853+
}
854+
855+
return questionData;
844856
});
845857
return { questions: updatedQuestions as QuestionStore[] };
846858
}),

0 commit comments

Comments
 (0)