Refactor code and add filtering to circle progress displays
This commit is contained in:
parent
b780061641
commit
10cd228d56
|
|
@ -1,6 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LearningPathCircle from "@/pages/learningPath/learningPathPage/LearningPathCircle.vue";
|
import LearningPathCircle from "@/pages/learningPath/learningPathPage/LearningPathCircle.vue";
|
||||||
import { calculateCircleSectorData } from "@/pages/learningPath/learningPathPage/utils";
|
import {
|
||||||
|
calculateCircleSectorData,
|
||||||
|
filterCircles,
|
||||||
|
useCourseFilter,
|
||||||
|
} from "@/pages/learningPath/learningPathPage/utils";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { useCourseCircleProgress, useCourseDataWithCompletion } from "@/composables";
|
import { useCourseCircleProgress, useCourseDataWithCompletion } from "@/composables";
|
||||||
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
|
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
|
||||||
|
|
@ -48,9 +52,13 @@ const wrapperClasses = computed(() => {
|
||||||
return classes;
|
return classes;
|
||||||
});
|
});
|
||||||
|
|
||||||
const { inProgressCirclesCount, circlesCount } = useCourseCircleProgress(
|
const { filter } = useCourseFilter(props.courseSlug, props.courseSessionId);
|
||||||
lpQueryResult.circles
|
|
||||||
);
|
const filteredCircles = computed(() => {
|
||||||
|
return filterCircles(filter.value, circles.value);
|
||||||
|
});
|
||||||
|
const { inProgressCirclesCount, circlesCount } =
|
||||||
|
useCourseCircleProgress(filteredCircles);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -66,7 +74,7 @@ const { inProgressCirclesCount, circlesCount } = useCourseCircleProgress(
|
||||||
</h4>
|
</h4>
|
||||||
<div :class="wrapperClasses">
|
<div :class="wrapperClasses">
|
||||||
<LearningPathCircle
|
<LearningPathCircle
|
||||||
v-for="circle in circles"
|
v-for="circle in filteredCircles"
|
||||||
:key="circle.id"
|
:key="circle.id"
|
||||||
:sectors="calculateCircleSectorData(circle)"
|
:sectors="calculateCircleSectorData(circle)"
|
||||||
></LearningPathCircle>
|
></LearningPathCircle>
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ import {
|
||||||
useCurrentCourseSession,
|
useCurrentCourseSession,
|
||||||
} from "@/composables";
|
} from "@/composables";
|
||||||
import CourseSessionDueDatesList from "@/components/dueDates/CourseSessionDueDatesList.vue";
|
import CourseSessionDueDatesList from "@/components/dueDates/CourseSessionDueDatesList.vue";
|
||||||
import { useMutation, useQuery } from "@urql/vue";
|
import { useMutation } from "@urql/vue";
|
||||||
import { UPDATE_COURSE_PROFILE_MUTATION } from "@/graphql/mutations";
|
import { UPDATE_COURSE_PROFILE_MUTATION } from "@/graphql/mutations";
|
||||||
import { COURSE_QUERY } from "@/graphql/queries";
|
import { filterCircles, useCourseFilter } from "./utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSlug: string;
|
courseSlug: string;
|
||||||
|
|
@ -37,25 +37,17 @@ const course = computed(() => lpQueryResult.course.value);
|
||||||
|
|
||||||
const courseSession = useCurrentCourseSession();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
// todo: we do not use the courseStore, because the returned object has lost its reactivity and does not reflect cache changes. maybe this could be fixed in there, then we can use the same object here
|
const { filter } = useCourseFilter(props.courseSlug);
|
||||||
// todo: this could maybe go somewhere else, but useQuery must be used inside of a setup function. is there a better place?
|
|
||||||
const courseReactiveResult = useQuery({
|
const filteredCircles = computed(() => {
|
||||||
query: COURSE_QUERY,
|
if (lpQueryResult.circles.value === undefined) {
|
||||||
variables: { slug: props.courseSlug },
|
return [];
|
||||||
});
|
}
|
||||||
const courseReactive = computed(() => courseReactiveResult.data.value?.course);
|
return filterCircles(filter.value, lpQueryResult.circles.value);
|
||||||
const courseSessionUser = computed(() => {
|
|
||||||
return courseReactive.value?.course_session_users.find(
|
|
||||||
(e) => e?.course_session.id === courseSession.value.id
|
|
||||||
);
|
|
||||||
});
|
|
||||||
const filter = computed(() => {
|
|
||||||
return courseSessionUser.value?.chosen_profile || "";
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { inProgressCirclesCount, circlesCount } = useCourseCircleProgress(
|
const { inProgressCirclesCount, circlesCount } =
|
||||||
lpQueryResult.circles
|
useCourseCircleProgress(filteredCircles);
|
||||||
);
|
|
||||||
|
|
||||||
const updateCourseProfileMutation = useMutation(UPDATE_COURSE_PROFILE_MUTATION);
|
const updateCourseProfileMutation = useMutation(UPDATE_COURSE_PROFILE_MUTATION);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { computed } from "vue";
|
||||||
import type { LearningContentWithCompletion, TopicType } from "@/types";
|
import type { LearningContentWithCompletion, TopicType } from "@/types";
|
||||||
import LearningPathCircleColumn from "./LearningPathCircleColumn.vue";
|
import LearningPathCircleColumn from "./LearningPathCircleColumn.vue";
|
||||||
import { COURSE_PROFILE_ALL_FILTER } from "@/constants";
|
import { COURSE_PROFILE_ALL_FILTER } from "@/constants";
|
||||||
|
import { filterCircles } from "./utils";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
topic: TopicType;
|
topic: TopicType;
|
||||||
|
|
@ -22,17 +23,7 @@ const isLastCircle = (circleIndex: number, numCircles: number) =>
|
||||||
props.isLastTopic && circleIndex === numCircles - 1;
|
props.isLastTopic && circleIndex === numCircles - 1;
|
||||||
|
|
||||||
const filteredCircles = computed(() => {
|
const filteredCircles = computed(() => {
|
||||||
if (
|
return filterCircles(props.filter, props.topic.circles);
|
||||||
props.filter === undefined ||
|
|
||||||
props.filter === "" ||
|
|
||||||
props.filter === COURSE_PROFILE_ALL_FILTER
|
|
||||||
) {
|
|
||||||
return props.topic.circles;
|
|
||||||
}
|
|
||||||
return props.topic.circles.filter(
|
|
||||||
(circle) =>
|
|
||||||
circle.profiles.indexOf(props.filter as string) > -1 || circle.is_base_circle
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
|
import { COURSE_PROFILE_ALL_FILTER } from "@/constants";
|
||||||
|
import { COURSE_QUERY } from "@/graphql/queries";
|
||||||
import type {
|
import type {
|
||||||
CircleSectorData,
|
CircleSectorData,
|
||||||
CircleSectorProgress,
|
CircleSectorProgress,
|
||||||
|
|
@ -7,6 +10,8 @@ import {
|
||||||
someFinishedInLearningSequence,
|
someFinishedInLearningSequence,
|
||||||
} from "@/services/circle";
|
} from "@/services/circle";
|
||||||
import type { CircleType } from "@/types";
|
import type { CircleType } from "@/types";
|
||||||
|
import { useQuery } from "@urql/vue";
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
export function calculateCircleSectorData(circle: CircleType): CircleSectorData[] {
|
export function calculateCircleSectorData(circle: CircleType): CircleSectorData[] {
|
||||||
return circle.learning_sequences.map((ls) => {
|
return circle.learning_sequences.map((ls) => {
|
||||||
|
|
@ -21,3 +26,42 @@ export function calculateCircleSectorData(circle: CircleType): CircleSectorData[
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useCourseFilter(courseSlug: string, courseSessionId?: string) {
|
||||||
|
const csId = computed(() => {
|
||||||
|
if (courseSessionId) {
|
||||||
|
return courseSessionId;
|
||||||
|
}
|
||||||
|
// assume we're on a page with a current course session
|
||||||
|
const courseSession = useCurrentCourseSession();
|
||||||
|
return courseSession.value.id;
|
||||||
|
});
|
||||||
|
const courseReactiveResult = useQuery({
|
||||||
|
query: COURSE_QUERY,
|
||||||
|
variables: { slug: courseSlug },
|
||||||
|
});
|
||||||
|
const courseReactive = computed(() => courseReactiveResult.data.value?.course);
|
||||||
|
const courseSessionUser = computed(() => {
|
||||||
|
return courseReactive.value?.course_session_users.find(
|
||||||
|
(e) => e?.course_session.id === csId.value
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const filter = computed(() => {
|
||||||
|
return courseSessionUser.value?.chosen_profile || "";
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
filter,
|
||||||
|
courseReactive,
|
||||||
|
courseSessionUser,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function filterCircles(filter: string | undefined, circles: CircleType[]) {
|
||||||
|
if (filter === undefined || filter === "" || filter === COURSE_PROFILE_ALL_FILTER) {
|
||||||
|
return circles;
|
||||||
|
}
|
||||||
|
return circles.filter(
|
||||||
|
(circle) => circle.profiles.indexOf(filter as string) > -1 || circle.is_base_circle
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-07-25 14:27
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
import modelcluster.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("learnpath", "0020_auto_20240711_1736"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="circle",
|
||||||
|
name="profiles",
|
||||||
|
field=modelcluster.fields.ParentalManyToManyField(
|
||||||
|
related_name="circles", to="learnpath.courseprofile"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue