Skip to content

Commit 624d8e2

Browse files
committed
fix(StudentGradesPerQuestionTable): add RubricPanel to past answer display for RubricBasedResponse
1 parent a09bb36 commit 624d8e2

File tree

14 files changed

+73
-59
lines changed

14 files changed

+73
-59
lines changed

app/views/course/assessment/answer/forum_post_responses/_forum_post_response.json.jbuilder

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# frozen_string_literal: true
2+
json.questionType answer.question.question_type
3+
24
json.fields do
35
json.questionId answer.question_id
46
json.id answer.acting_as.id

app/views/course/assessment/answer/multiple_responses/_multiple_response.json.jbuilder

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# frozen_string_literal: true
2+
json.questionType answer.question.question_type
3+
24
json.fields do
35
json.questionId answer.question_id
46
json.id answer.acting_as.id

app/views/course/assessment/answer/programming/_programming.json.jbuilder

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ if is_current_answer && !latest_answer.current_answer?
2020
end
2121
end
2222

23+
json.questionType answer.question.question_type
24+
2325
json.fields do
2426
json.questionId answer.question_id
2527
json.id answer.acting_as.id

app/views/course/assessment/answer/rubric_based_responses/_rubric_based_response.json.jbuilder

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# frozen_string_literal: true
2+
json.questionType answer.question.question_type
3+
24
json.fields do
35
json.questionId answer.question_id
46
json.id answer.acting_as.id

app/views/course/assessment/answer/scribing/_scribing.json.jbuilder

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# frozen_string_literal: true
2+
json.questionType answer.question.question_type
3+
24
json.scribing_answer do
35
json.image_url answer.question.actable.attachment_reference.generate_public_url
46
json.user_id current_user.id

app/views/course/assessment/answer/text_responses/_text_response.json.jbuilder

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# frozen_string_literal: true
2+
json.questionType answer.question.question_type
3+
24
json.fields do
35
json.questionId answer.question_id
46
json.id answer.acting_as.id

app/views/course/assessment/answer/voice_responses/_voice_response.json.jbuilder

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# frozen_string_literal: true
2+
json.questionType answer.question.question_type
3+
24
json.fields do
35
json.questionId answer.question_id
46
json.id answer.acting_as.id

client/app/bundles/course/assessment/pages/AssessmentStatistics/StudentGradesPerQuestionTable.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ const StudentGradesPerQuestionTable: FC<Props> = (props) => {
4343
const { t } = useTranslation();
4444
const { courseId, assessmentId } = useParams();
4545
const { includePhantom } = props;
46-
4746
const statistics = useAppSelector(getAssessmentStatistics);
4847
const [openAnswer, setOpenAnswer] = useState(false);
4948
const [answerDisplayInfo, setAnswerDisplayInfo] = useState<AnswerInfoState>({

client/app/bundles/course/assessment/submission/components/AnswerDetails/RubricBasedResponseDetails.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
import { Typography } from '@mui/material';
22
import { QuestionType } from 'types/course/assessment/question';
33

4+
import RubricPanel from '../../containers/RubricPanel';
45
import { AnswerDetailsProps } from '../../types';
56

6-
import AttachmentDetails from './AttachmentDetails';
7-
87
const RubricBasedResponseDetails = (
98
props: AnswerDetailsProps<QuestionType.RubricBasedResponse>,
109
): JSX.Element => {
1110
const { question, answer } = props;
12-
1311
return (
14-
<Typography
15-
dangerouslySetInnerHTML={{ __html: answer.fields.answer_text }}
16-
variant="body2"
17-
/>
12+
<>
13+
<Typography
14+
dangerouslySetInnerHTML={{ __html: answer.fields.answer_text }}
15+
variant="body2"
16+
/>
17+
<RubricPanel
18+
answerCategoryGrades={answer.categoryGrades}
19+
answerId={answer.id}
20+
question={question}
21+
setIsFirstRendering={() => {}} // Placeholder function since RubricPanel is not editable here
22+
/>
23+
</>
1824
);
1925
};
2026

client/app/bundles/course/assessment/submission/containers/QuestionGrade.tsx

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { FC, useState } from 'react';
22
import { Chip, Paper, TextField, Tooltip, Typography } from '@mui/material';
33
import { QuestionType } from 'types/course/assessment/question';
4-
import { SubmissionQuestionBaseData } from 'types/course/assessment/submission/question/types';
4+
import {
5+
SubmissionQuestionBaseData,
6+
SubmissionQuestionData,
7+
} from 'types/course/assessment/submission/question/types';
58

69
import { FIELD_LONG_DEBOUNCE_DELAY_MS } from 'lib/constants/sharedConstants';
710
import { getSubmissionId } from 'lib/helpers/url-helpers';
@@ -13,6 +16,7 @@ import { saveGrade, updateGrade } from '../actions/answers';
1316
import { workflowStates } from '../constants';
1417
import { computeExp } from '../reducers/grading';
1518
import { QuestionGradeData } from '../reducers/grading/types';
19+
import { getRubricCategoryGradesForAnswerId } from '../selectors/answers';
1620
import { getAssessment } from '../selectors/assessments';
1721
import {
1822
getBasePoints,
@@ -23,6 +27,7 @@ import {
2327
import { getQuestions } from '../selectors/questions';
2428
import { getSubmission } from '../selectors/submissions';
2529
import translations from '../translations';
30+
import { AnswerDetailsMap } from '../types';
2631

2732
import RubricPanel from './RubricPanel';
2833

@@ -55,7 +60,6 @@ const QuestionGrade: FC<QuestionGradeProps> = (props) => {
5560
const submission = useAppSelector(getSubmission);
5661
const questions = useAppSelector(getQuestions);
5762
const questionWithGrades = useAppSelector(getQuestionWithGrades);
58-
5963
const submissionId = getSubmissionId();
6064

6165
const { submittedAt, bonusEndAt, graderView, bonusPoints, workflowState } =
@@ -69,21 +73,24 @@ const QuestionGrade: FC<QuestionGradeProps> = (props) => {
6973
const basePoints = useAppSelector(getBasePoints);
7074
const expMultiplier = useAppSelector(getExpMultiplier);
7175
const maximumGrade = useAppSelector(getMaximumGrade);
76+
const answerCategoryGradesFromStore = useAppSelector((state) =>
77+
grading ? getRubricCategoryGradesForAnswerId(state, grading.id) : [],
78+
);
7279

7380
const attempting = workflowState === workflowStates.Attempting;
7481
const published = workflowState === workflowStates.Published;
7582

76-
const isRubricBasedResponse =
77-
question.type === QuestionType.RubricBasedResponse;
78-
7983
const editable = !attempting && graderView;
8084

8185
const isNotGradedAndNotPublished =
8286
workflowState !== workflowStates.Graded &&
8387
workflowState !== workflowStates.Published;
8488

89+
const isRubricBasedResponse =
90+
question.type === QuestionType.RubricBasedResponse;
8591
const isRubricVisible =
86-
!submission.isStudent || assessment.showRubricToStudents;
92+
isRubricBasedResponse &&
93+
(!submission.isStudent || assessment.showRubricToStudents);
8794

8895
const handleSaveGrade = (
8996
newGrade: string | number | null,
@@ -278,12 +285,18 @@ const QuestionGrade: FC<QuestionGradeProps> = (props) => {
278285
</Typography>
279286
);
280287

288+
const answerCategoryGrades = (
289+
isRubricVisible && grading ? answerCategoryGradesFromStore : undefined
290+
) as AnswerDetailsMap['RubricBasedResponse']['categoryGrades'] | undefined;
291+
281292
return (
282293
(editable || published) && (
283294
<>
284-
{isRubricBasedResponse && isRubricVisible && (
295+
{isRubricVisible && answerCategoryGrades && (
285296
<RubricPanel
286-
questionId={questionId}
297+
answerCategoryGrades={answerCategoryGrades!}
298+
answerId={grading.id}
299+
question={question as SubmissionQuestionData<'RubricBasedResponse'>}
287300
setIsFirstRendering={setIsFirstRendering}
288301
/>
289302
)}

client/app/bundles/course/assessment/submission/containers/RubricPanel.tsx

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,27 @@ import {
99
} from '@mui/material';
1010
import { SubmissionQuestionData } from 'types/course/assessment/submission/question/types';
1111

12-
import { useAppSelector } from 'lib/hooks/store';
1312
import useTranslation from 'lib/hooks/useTranslation';
1413

15-
import { getRubricCategoryGradesForAnswerId } from '../selectors/answers';
16-
import { getQuestionWithGrades } from '../selectors/grading';
17-
import { getQuestions } from '../selectors/questions';
1814
import translations from '../translations';
15+
import { AnswerDetailsMap } from '../types';
1916

2017
import RubricPanelRow from './RubricPanelRow';
2118

2219
interface RubricPanelProps {
20+
answerId: number;
21+
answerCategoryGrades: AnswerDetailsMap['RubricBasedResponse']['categoryGrades'];
22+
question: SubmissionQuestionData<'RubricBasedResponse'>;
2323
setIsFirstRendering: (isFirstRendering: boolean) => void;
24-
questionId: number;
2524
}
2625

2726
const RubricPanel: FC<RubricPanelProps> = (props) => {
28-
const { setIsFirstRendering, questionId } = props;
29-
3027
const { t } = useTranslation();
31-
const questions = useAppSelector(getQuestions);
32-
33-
const question = questions[
34-
questionId
35-
] as SubmissionQuestionData<'RubricBasedResponse'>;
36-
const questionWithGrades = useAppSelector(getQuestionWithGrades);
37-
38-
const answerId = questionWithGrades[questionId].id;
39-
40-
const categoryGrade = useAppSelector((state) =>
41-
getRubricCategoryGradesForAnswerId(state, answerId),
42-
);
28+
const { answerId, answerCategoryGrades, question, setIsFirstRendering } =
29+
props;
4330

4431
const categoryGrades = useMemo(() => {
45-
const categoryGradeHash = categoryGrade.reduce(
32+
const categoryGradeHash = answerCategoryGrades.reduce(
4633
(obj, category) => ({
4734
...obj,
4835
[category.categoryId]: {
@@ -68,7 +55,7 @@ const RubricPanel: FC<RubricPanelProps> = (props) => {
6855
}),
6956
{},
7057
);
71-
}, [categoryGrade, question.categories]);
58+
}, [answerCategoryGrades, question.categories]);
7259

7360
return (
7461
<div className="w-full p-2">
@@ -91,13 +78,13 @@ const RubricPanel: FC<RubricPanelProps> = (props) => {
9178
</TableHead>
9279

9380
<TableBody>
94-
{question.categories.map((category) => (
81+
{question?.categories.map((category) => (
9582
<RubricPanelRow
9683
key={category.id}
9784
answerId={answerId}
9885
category={category}
9986
categoryGrades={categoryGrades}
100-
questionId={questionId}
87+
question={question}
10188
setIsFirstRendering={setIsFirstRendering}
10289
/>
10390
))}

client/app/bundles/course/assessment/submission/containers/RubricPanelRow.tsx

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
getExpMultiplier,
2020
getMaximumGrade,
2121
} from '../selectors/grading';
22-
import { getQuestions } from '../selectors/questions';
2322
import { getSubmission } from '../selectors/submissions';
2423
import { GradeWithPrefilledStatus } from '../types';
2524

@@ -28,25 +27,20 @@ import RubricGrade from './RubricGrade';
2827

2928
interface RubricPanelRowProps {
3029
answerId: number;
31-
questionId: number;
30+
question: SubmissionQuestionData<'RubricBasedResponse'>;
3231
category: RubricBasedResponseCategoryQuestionData;
3332
categoryGrades: Record<number, AnswerRubricGradeData>;
3433
setIsFirstRendering: (isFirstRendering: boolean) => void;
3534
}
3635

3736
const RubricPanelRow: FC<RubricPanelRowProps> = (props) => {
38-
const { answerId, questionId, category, categoryGrades } = props;
37+
const { answerId, question, category, categoryGrades } = props;
3938

39+
// For editable rubric grades
4040
const dispatch = useAppDispatch();
41-
4241
const submission = useAppSelector(getSubmission);
43-
const questions = useAppSelector(getQuestions);
44-
45-
const { graderView, workflowState } = submission;
46-
const question = questions[
47-
questionId
48-
] as SubmissionQuestionData<'RubricBasedResponse'>;
49-
42+
const { graderView, workflowState, submittedAt, bonusEndAt, bonusPoints } =
43+
submission;
5044
const submissionId = getSubmissionId();
5145

5246
const maximumGrade = useAppSelector(getMaximumGrade);
@@ -57,11 +51,10 @@ const RubricPanelRow: FC<RubricPanelRowProps> = (props) => {
5751
const published = workflowState === workflowStates.Published;
5852
const editable = !attempting && graderView;
5953

60-
const { submittedAt, bonusEndAt, bonusPoints } = submission;
61-
6254
const bonusAwarded =
6355
new Date(submittedAt) < new Date(bonusEndAt) ? bonusPoints : 0;
6456

57+
const categoryIds = question.categories.map((cat) => cat.id);
6558
const categoryGradeExplanationMap = question.categories.reduce(
6659
(acc, cat) => ({
6760
...acc,
@@ -76,8 +69,6 @@ const RubricPanelRow: FC<RubricPanelRowProps> = (props) => {
7669
{},
7770
);
7871

79-
const categoryIds = question.categories.map((cat) => cat.id);
80-
8172
const handleSaveRubricAndGrade = (
8273
catGrades: Record<number, AnswerRubricGradeData>,
8374
qId: number,
@@ -108,12 +99,12 @@ const RubricPanelRow: FC<RubricPanelRowProps> = (props) => {
10899
saveRubricAndGrade(
109100
submissionId,
110101
answerId,
111-
questionId,
102+
question.id,
112103
categoryIds,
113104
newExpPoints,
114105
published,
115106
catGrades,
116-
question.maximumGrade,
107+
question?.maximumGrade,
117108
),
118109
);
119110
};
@@ -131,6 +122,7 @@ const RubricPanelRow: FC<RubricPanelRowProps> = (props) => {
131122
{editable ? (
132123
<RubricExplanation
133124
key={category.id}
125+
questionId={question.id}
134126
updateGrade={debouncedUpdateRubricGrade}
135127
{...props}
136128
/>
@@ -150,6 +142,7 @@ const RubricPanelRow: FC<RubricPanelRowProps> = (props) => {
150142
{editable ? (
151143
<RubricGrade
152144
key={category.id}
145+
questionId={question.id}
153146
updateGrade={debouncedUpdateRubricGrade}
154147
{...props}
155148
/>

client/app/types/course/assessment/submission/answer/rubricBasedResponse.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ export interface RubricBasedResponseAnswerData extends AnswerBaseData {
2525
path?: string;
2626
};
2727
latestAnswer?: RubricBasedResponseAnswerData;
28-
categoryScores: {
29-
canReadRubric: boolean;
28+
categoryGrades: {
3029
id: number | null | undefined;
3130
categoryId: number;
32-
score: number;
31+
grade: number;
32+
gradeId: number;
33+
explanation: string | null;
3334
}[];
3435
}
3536

client/app/types/course/assessment/submission/question/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export interface SubmissionQuestionBaseData extends QuestionData {
9999
questionTitle: string;
100100
submissionQuestionId: number;
101101
topicId: number;
102+
type: QuestionType;
102103
answerId?: number;
103104
isCodaveri?: boolean;
104105
// Derived within redux reducer

0 commit comments

Comments
 (0)