145 lines
4.3 KiB
TypeScript
145 lines
4.3 KiB
TypeScript
import type { StatusCountKey } from "@/components/ui/ItProgress.vue";
|
|
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,
|
|
AssignmentCompletionStatus,
|
|
CourseSessionUser,
|
|
LearningContentAssignment,
|
|
LearningContentInterface,
|
|
UserAssignmentCompletionStatus,
|
|
} from "@/types";
|
|
import { sum } from "d3";
|
|
import pick from "lodash/pick";
|
|
|
|
export interface AssignmentLearningContent extends LearningContentInterface {
|
|
assignmentId: number;
|
|
}
|
|
|
|
export function calcAssignmentLearningContents(learningPath?: LearningPath) {
|
|
// TODO: filter by circle
|
|
if (!learningPath) return [];
|
|
|
|
return learningPath.circles.flatMap((circle) => {
|
|
const learningContents = circle.flatLearningContents.filter(
|
|
(lc) =>
|
|
lc.content_type === "learnpath.LearningContentAssignment" &&
|
|
lc.assignment_type === "CASEWORK"
|
|
) as LearningContentAssignment[];
|
|
return learningContents.map((lc) => {
|
|
return {
|
|
...lc,
|
|
assignmentId: lc.content_assignment_id,
|
|
};
|
|
});
|
|
}) as AssignmentLearningContent[];
|
|
}
|
|
|
|
export async function loadAssignmentCompletionStatusData(
|
|
assignmentId: number,
|
|
courseSessionId: number
|
|
) {
|
|
const cockpitStore = useCockpitStore();
|
|
|
|
const assignmentCompletionData = (await itGet(
|
|
`/api/assignment/${assignmentId}/${courseSessionId}/status/`
|
|
)) as UserAssignmentCompletionStatus[];
|
|
|
|
const courseSessionUsers = await cockpitStore.loadCourseSessionUsers(courseSessionId);
|
|
|
|
return calcUserAssignmentCompletionStatus(
|
|
courseSessionUsers,
|
|
assignmentCompletionData
|
|
);
|
|
}
|
|
|
|
export function calcUserAssignmentCompletionStatus(
|
|
courseSessionUsers: CourseSessionUser[],
|
|
assignmentCompletionStatusData: UserAssignmentCompletionStatus[]
|
|
) {
|
|
return courseSessionUsers.map((u) => {
|
|
let userStatus = "unknown" as AssignmentCompletionStatus;
|
|
const userAssignmentStatus = assignmentCompletionStatusData?.find(
|
|
(s) => s.assignment_user_id === u.user_id
|
|
);
|
|
if (userAssignmentStatus) {
|
|
userStatus = userAssignmentStatus.completion_status;
|
|
}
|
|
let progressStatus: StatusCountKey = "unknown";
|
|
if (
|
|
["SUBMITTED", "EVALUATION_IN_PROGRESS", "EVALUATION_SUBMITTED"].includes(
|
|
userStatus
|
|
)
|
|
) {
|
|
progressStatus = "success";
|
|
}
|
|
|
|
return {
|
|
userId: u.user_id,
|
|
userStatus,
|
|
progressStatus,
|
|
grade: userAssignmentStatus?.evaluation_grade ?? null,
|
|
};
|
|
});
|
|
}
|
|
|
|
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 = calcAssignmentLearningContents(
|
|
learningPathStore.learningPathForUser(
|
|
courseSessionsStore.currentCourseSession.course.slug,
|
|
userStore.id
|
|
)
|
|
);
|
|
|
|
const learningContent = learningContents.find(
|
|
(lc) => lc.assignmentId === 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;
|
|
}
|