Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/IsaacApiTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ export interface AssignmentStatusDTO {

export interface AssignmentProgressDTO {
user?: UserSummaryDTO;
correctPartResults?: number[];
incorrectPartResults?: number[];
correctMarkResults?: number[][];
incorrectMarkResults?: number[][];
markTotals?: number[][];
questionResults?: CompletionState[];
questionPartResults?: QuestionPartState[][];
}
Expand Down
12 changes: 8 additions & 4 deletions src/IsaacAppTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ export interface ActiveModalWithoutState {
bodyContainerClassName?: string;
}

export type ProgressSortOrder = number | "name" | "totalPartPercentage" | "totalAttemptedPartPercentage" | "totalQuestionPercentage" | "totalAttemptedQuestionPercentage";
export type ProgressSortOrder = number | "name" | "totalMarkPercentage" | "totalAttemptedMarkPercentage" | "totalQuestionPercentage" | "totalAttemptedQuestionPercentage";

export enum QuizzesBoardOrder {
"title" = "title",
Expand Down Expand Up @@ -438,6 +438,8 @@ export interface AssignmentProgressPageSettings {
setFormatAsPercentage: (formatAsPercentage: boolean) => void;
attemptedOrCorrect: "ATTEMPTED" | "CORRECT";
setAttemptedOrCorrect: (attemptedOrCorrect: "ATTEMPTED" | "CORRECT") => void;
displayIndividualMarks: boolean;
setDisplayIndividualMarks: (displayIndividualMarks: boolean) => void;
assignmentOrder: AssignmentOrderSpec;
setAssignmentOrder: (assignmentOrder: AssignmentOrderSpec) => void;
groupSortOrder: GroupSortOrder;
Expand Down Expand Up @@ -497,14 +499,14 @@ export const AssignmentScheduleContext = React.createContext<{
collapsed: boolean;
setCollapsed: (b: boolean) => void;
viewBy: "startDate" | "dueDate";
}>({boardsById: {}, groupsById: {}, groupFilter: {}, boardIdsByGroupId: {}, groups: [], gameboards: [], openAssignmentModal: () => {}, collapsed: false, setCollapsed: () => {}, viewBy: "startDate"});
}>({boardsById: {}, groupsById: {}, groupFilter: {}, boardIdsByGroupId: {}, groups: [], gameboards: [], openAssignmentModal: () => {}, collapsed: false, setCollapsed: () => {}, viewBy: "startDate"});
export const ContentSidebarContext = React.createContext<{ toggle: () => void; close: () => void; } | undefined>(undefined);

export interface AuthorisedAssignmentProgress extends ApiTypes.AssignmentProgressDTO {
completed?: boolean;
correctQuestionPagesCount: number;
correctQuestionPartsCount: number;
incorrectQuestionPartsCount: number;
correctQuestionMarksCount: number;
incorrectQuestionMarksCount: number;
notAttemptedPartResults: number[];
}

Expand Down Expand Up @@ -741,6 +743,8 @@ export interface PageSettings {
assignmentOrder?: AssignmentOrderSpec;
attemptedOrCorrect?: "ATTEMPTED" | "CORRECT";
setAttemptedOrCorrect?: (newValue: "ATTEMPTED" | "CORRECT") => void;
displayIndividualMarks: boolean;
setDisplayIndividualMarks: (displayIndividualMarks: boolean) => void;
}

export interface GameboardBuilderQuestions {
Expand Down
171 changes: 96 additions & 75 deletions src/app/components/elements/quiz/QuizProgressCommon.tsx

Large diffs are not rendered by default.

36 changes: 23 additions & 13 deletions src/app/components/pages/AssignmentProgressIndividual.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Link } from "react-router-dom";
import { AssignmentProgressDTO, GameboardItem, CompletionState } from "../../../IsaacApiTypes";
import { EnhancedAssignmentWithProgress, AssignmentProgressPageSettingsContext, AuthorisedAssignmentProgress } from "../../../IsaacAppTypes";
import { getAssignmentProgressCSVDownloadLink, isAda, isAuthorisedFullAccess, isPhy, PATHS, siteSpecific } from "../../services";
import { ICON, passMark, ResultsTable, ResultsTablePartBreakdown } from "../elements/quiz/QuizProgressCommon";
import { ICON, markResultsToPartResults, passMark, ResultsTable, ResultsTablePartBreakdown } from "../elements/quiz/QuizProgressCommon";
import { Badge, Button, Card, CardBody } from "reactstrap";
import { formatDate } from "../elements/DateString";
import { StyledCheckbox } from "../elements/inputs/StyledCheckbox";
Expand Down Expand Up @@ -47,6 +47,15 @@ export const AssignmentProgressSettings = () => {
onChange={(e) => assignmentProgressContext?.setAttemptedOrCorrect?.(e.currentTarget.checked ? "CORRECT" : "ATTEMPTED")}
/>
</div>}

{isPhy && <div className="d-flex flex-row flex-md-column flex-grow-1 align-items-center py-2 py-md-0">
<span>Marks display mode</span>
<Spacer />
<StyledToggle falseLabel="Parts" trueLabel="Marks"
checked={assignmentProgressContext?.displayIndividualMarks}
onChange={(e) => assignmentProgressContext?.setDisplayIndividualMarks?.(e.currentTarget.checked)}
/>
</div>}
</div>;
};

Expand Down Expand Up @@ -102,8 +111,8 @@ const GroupAssignmentTab = ({assignment, progress}: GroupAssignmentTabProps) =>
return "revoked";
}

const correctParts = studentProgress.correctQuestionPartsCount;
const incorrectParts = studentProgress.incorrectQuestionPartsCount;
const correctParts = studentProgress.correctQuestionMarksCount;
const incorrectParts = studentProgress.incorrectQuestionMarksCount;
const status = null;

return markClassesInternal(assignmentProgressContext?.attemptedOrCorrect ?? "CORRECT", studentProgress, status, correctParts, incorrectParts, totalParts);
Expand All @@ -114,12 +123,11 @@ const GroupAssignmentTab = ({assignment, progress}: GroupAssignmentTabProps) =>
return "revoked";
}


const question = questions[index];

const totalParts = question.questionPartsTotal;
const correctParts = (studentProgress.correctPartResults || [])[index];
const incorrectParts = (studentProgress.incorrectPartResults || [])[index];
const correctParts = markResultsToPartResults(studentProgress.correctMarkResults, studentProgress.markTotals)[index];
const incorrectParts = markResultsToPartResults(studentProgress.incorrectMarkResults, studentProgress.markTotals)[index];
const status = (studentProgress.questionResults || [])[index];

return markClassesInternal(assignmentProgressContext?.attemptedOrCorrect ?? "CORRECT", studentProgress, status, correctParts, incorrectParts, totalParts);
Expand Down Expand Up @@ -333,27 +341,29 @@ export const ProgressDetails = ({assignment}: { assignment: EnhancedAssignmentWi
const initialState = {
...p,
correctQuestionPagesCount: 0,
correctQuestionPartsCount: 0,
incorrectQuestionPartsCount: 0,
correctQuestionMarksCount: 0,
incorrectQuestionMarksCount: 0,
notAttemptedPartResults: []
};

const ret = (p.questionResults || []).reduce<AuthorisedAssignmentProgress>((oldP, results, i) => {
const correctQuestionsCount = [CompletionState.ALL_CORRECT].includes(results) ? oldP.correctQuestionPagesCount + 1 : oldP.correctQuestionPagesCount;
const questions = assignment.gameboard.contents;
const correctMarkTotal = (p.correctMarkResults || [])[i].reduce((a, b) => a + b, 0);
const incorrectMarkTotal = (p.incorrectMarkResults || [])[i].reduce((a, b) => a + b, 0);
const markTotal = (p.markTotals || [])[i].reduce((a, b) => a + b, 0);
return {
...oldP,
correctQuestionPagesCount: correctQuestionsCount,
correctQuestionPartsCount: oldP.correctQuestionPartsCount + (p.correctPartResults || [])[i],
incorrectQuestionPartsCount: oldP.incorrectQuestionPartsCount + (p.incorrectPartResults || [])[i],
correctQuestionMarksCount: oldP.correctQuestionMarksCount + correctMarkTotal,
incorrectQuestionMarksCount: oldP.incorrectQuestionMarksCount + incorrectMarkTotal,
notAttemptedPartResults: [
...oldP.notAttemptedPartResults,
(questions[i].questionPartsTotal - (p.correctPartResults || [])[i] - (p.incorrectPartResults || [])[i])
(markTotal - correctMarkTotal - incorrectMarkTotal)
]
};
}, initialState);
return [ret, questions.length === ret.correctQuestionPagesCount];
}), [assignment.gameboard.contents, assignment.progress, questions.length]);
}), [assignment.progress, questions.length]);

const progress = progressData.map(pd => pd[0]);

Expand Down
20 changes: 10 additions & 10 deletions src/app/components/pages/quizzes/QuizTeacherFeedback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
} from "../../../../IsaacAppTypes";
import {teacherQuizzesCrumbs} from "../../elements/quiz/QuizContentsComponent";
import {formatDate} from "../../elements/DateString";
import {ResultsTable} from "../../elements/quiz/QuizProgressCommon";
import {markResultsToPartResults, ResultsTable} from "../../elements/quiz/QuizProgressCommon";
import {
Alert,
Button,
Expand Down Expand Up @@ -197,8 +197,8 @@ export const QuizProgressDetails = ({assignment}: {assignment: QuizAssignmentDTO
return "revoked";
}

const correctParts = studentProgress.correctQuestionPartsCount;
const incorrectParts = studentProgress.incorrectQuestionPartsCount;
const correctParts = studentProgress.correctQuestionMarksCount;
const incorrectParts = studentProgress.incorrectQuestionMarksCount;
const total = questions.reduce((acc, q) => acc + (q.questionPartsTotal ?? 0), 0);

return markClassesInternal(assignmentProgressContext?.attemptedOrCorrect ?? "CORRECT", studentProgress, null, correctParts, incorrectParts, total);
Expand All @@ -209,31 +209,31 @@ export const QuizProgressDetails = ({assignment}: {assignment: QuizAssignmentDTO
return "revoked";
}

const correctParts = (studentProgress.correctPartResults || [])[index];
const incorrectParts = (studentProgress.incorrectPartResults || [])[index];
const correctParts = markResultsToPartResults(studentProgress.correctMarkResults, studentProgress.markTotals)[index];
const incorrectParts = markResultsToPartResults(studentProgress.incorrectMarkResults, studentProgress.markTotals)[index];
const totalParts = questions[index].questionPartsTotal ?? 0;

return markClassesInternal(assignmentProgressContext?.attemptedOrCorrect ?? "CORRECT", studentProgress, null, correctParts, incorrectParts, totalParts);
}

const totalParts = questions.length;

const progress : AuthorisedAssignmentProgress[] = !assignment.userFeedback ? [] : assignment.userFeedback.map(user => {
const progress: AuthorisedAssignmentProgress[] = !assignment.userFeedback ? [] : assignment.userFeedback.map(user => {
const partsCorrect = questions.reduce((acc, q) => acc + (user.feedback?.questionMarks?.[q?.id ?? -1]?.correct ?? 0), 0);
return {
user: user.user as UserSummaryDTO,
completed: user.feedback?.complete ?? false,
// a list of the correct parts of an answer, one list for each question
correctPartResults: questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.correct ?? 0),
incorrectPartResults: questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.incorrect ?? 0),
correctMarkResults: [questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.correct ?? 0)],
incorrectMarkResults: [questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.incorrect ?? 0)],
notAttemptedPartResults: user.feedback?.complete || user.feedback?.questionMarks !== undefined
? questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.notAttempted ?? 0)
// if the quiz has not been completed (i.e. submitted), then all parts are not attempted
: questions.map(q => q.questionPartsTotal ?? 0),
questionResults: [],
correctQuestionPagesCount: partsCorrect, // quizzes don't have pages, but QuizProgressCommon expects this key to be the "Correct" column value for sorting
correctQuestionPartsCount: partsCorrect,
incorrectQuestionPartsCount: questions.reduce((acc, q) => acc + (user.feedback?.questionMarks?.[q?.id ?? -1]?.incorrect ?? 0), 0),
correctQuestionMarksCount: partsCorrect,
incorrectQuestionMarksCount: questions.reduce((acc, q) => acc + (user.feedback?.questionMarks?.[q?.id ?? -1]?.incorrect ?? 0), 0),
};
});

Expand Down
2 changes: 2 additions & 0 deletions src/app/services/progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ export function useAssignmentProgressAccessibilitySettings({user}: {user: Regist
const [colourBlind, setColourBlind] = useState(false);
const [formatAsPercentage, setFormatAsPercentage] = useState(false);
const [attemptedOrCorrect, setAttemptedOrCorrect] = useState<"ATTEMPTED" | "CORRECT">("CORRECT");
const [displayIndividualMarks, setDisplayIndividualMarks] = useState(false);
const [assignmentOrder, setAssignmentOrder] = useState<AssignmentOrderSpec>(AssignmentOrder.startDateDescending);
const [groupSortOrder, setGroupSortOrder] = useState<GroupSortOrder>(GroupSortOrder.Alphabetical);

return {
colourBlind, setColourBlind,
formatAsPercentage, setFormatAsPercentage,
attemptedOrCorrect, setAttemptedOrCorrect,
displayIndividualMarks, setDisplayIndividualMarks,
assignmentOrder, setAssignmentOrder,
groupSortOrder, setGroupSortOrder,
isTeacher: isTeacherOrAbove(user),
Expand Down
28 changes: 14 additions & 14 deletions src/mocks/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6207,8 +6207,8 @@ export const mockProgress = {
"registeredContexts": [],
"id": 19
},
"correctPartResults": null,
"incorrectPartResults": null,
"correctMarkResults": null,
"incorrectMarkResults": null,
"questionResults": null,
"questionPartResults": null,
},
Expand All @@ -6226,13 +6226,13 @@ export const mockProgress = {
],
"id": 9
},
"correctPartResults": [
6,
1
"correctMarkResults": [
[1,1,1,1,1,1],
[1,0,0]
],
"incorrectPartResults": [
0,
2
"incorrectMarkResults": [
[0,0,0,0,0,0],
[0,1,1]
],
"questionResults": [
"ALL_CORRECT",
Expand Down Expand Up @@ -6268,13 +6268,13 @@ export const mockProgress = {
],
"id": 8
},
"correctPartResults": [
0,
0
"correctMarkResults": [
[0,0,0,0,0,0],
[0,0,0]
],
"incorrectPartResults": [
6,
0
"incorrectMarkResults": [
[1,1,1,1,1,1],
[0,0,0]
],
"questionResults": [
"ALL_INCORRECT",
Expand Down
Loading