vbv/client/src/services/assignmentService.ts

133 lines
4.0 KiB
TypeScript

import { itGet } from "@/fetchHelpers";
import type { LearningPath } from "@/services/learningPath";
import { useCockpitStore } from "@/stores/cockpit";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useLearningPathStore } from "@/stores/learningPath";
import { useUserStore } from "@/stores/user";
import type {
Assignment,
AssignmentCompletion,
CourseSessionUser,
LearningContentAssignment,
UserAssignmentCompletionStatus,
} from "@/types";
import { sum } from "d3";
import pick from "lodash/pick";
export interface GradedUser {
user: CourseSessionUser;
grade: number;
points: number;
}
export function calcLearningContentAssignments(learningPath?: LearningPath) {
// TODO: filter by circle
if (!learningPath) return [];
return learningPath.circles.flatMap((circle) => {
return circle.flatLearningContents.filter(
(lc) => lc.content_type === "learnpath.LearningContentAssignment"
) as LearningContentAssignment[];
});
}
export async function loadAssignmentCompletionStatusData(
assignmentId: number,
courseSessionId: number,
learningContentId: number
) {
const cockpitStore = useCockpitStore();
const assignmentCompletionData = (await itGet(
`/api/assignment/${assignmentId}/${courseSessionId}/status/`
)) as UserAssignmentCompletionStatus[];
const courseSessionUsers = await cockpitStore.loadCourseSessionMembers(
courseSessionId
);
const gradedUsers: GradedUser[] = [];
const assignmentSubmittedUsers: CourseSessionUser[] = [];
for (const csu of courseSessionUsers) {
const userAssignmentStatus = assignmentCompletionData.find(
(s) =>
s.assignment_user_id === csu.user_id &&
s.learning_content_page_id === learningContentId
);
if (
userAssignmentStatus?.completion_status === "SUBMITTED" ||
userAssignmentStatus?.completion_status === "EVALUATION_IN_PROGRESS" ||
userAssignmentStatus?.completion_status === "EVALUATION_SUBMITTED"
) {
assignmentSubmittedUsers.push(csu);
}
if (userAssignmentStatus?.completion_status === "EVALUATION_SUBMITTED") {
gradedUsers.push({
user: csu,
grade: userAssignmentStatus.evaluation_grade ?? 0,
points: userAssignmentStatus.evaluation_points ?? 0,
});
}
}
return {
assignmentSubmittedUsers: assignmentSubmittedUsers,
gradedUsers: gradedUsers,
total: courseSessionUsers.length,
};
}
export function findAssignmentDetail(assignmentId: number) {
const learningPathStore = useLearningPathStore();
const userStore = useUserStore();
const courseSessionsStore = useCourseSessionsStore();
// TODO: filter by selected circle
if (!courseSessionsStore.currentCourseSession) {
return undefined;
}
const learningContents = calcLearningContentAssignments(
learningPathStore.learningPathForUser(
courseSessionsStore.currentCourseSession.course.slug,
userStore.id
)
);
const learningContent = learningContents.find(
(lc) => lc.content_assignment_id === assignmentId
);
return courseSessionsStore.findCourseSessionAssignment(learningContent?.id);
}
export function maxAssignmentPoints(assignment: Assignment) {
return sum(assignment.evaluation_tasks.map((task) => task.value.max_points));
}
export function userAssignmentPoints(
assignment: Assignment,
assignmentCompletion: AssignmentCompletion
) {
const evaluationTaskIds = assignment.evaluation_tasks.map((task) => {
return task.id;
});
return sum(
// transform the object of { [expert_id]: { expert_data: { points } } } to an array
// of [ [expert_id, { expert_data: { points } }], ... ] so that we can easily sum
// the points of the user
Object.entries(pick(assignmentCompletion.completion_data, evaluationTaskIds)).map(
(entry) => {
return entry[1]?.expert_data?.points ?? 0;
}
)
);
}
export function pointsToGrade(points: number, maxPoints: number) {
// round to half-grades
const grade = Math.round((points / maxPoints) * 10);
const halfGrade = grade / 2;
return Math.min(halfGrade, 5) + 1;
}