Singe circle selection
This commit is contained in:
parent
4d46426d4f
commit
4ba12cbec8
|
|
@ -22,8 +22,8 @@ onMounted(async () => {
|
||||||
log.debug("CockpitParentPage mounted", props.courseSlug);
|
log.debug("CockpitParentPage mounted", props.courseSlug);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await cockpitStore.loadCourseSessionUsers(courseSession.value.id);
|
const members = await cockpitStore.loadCourseSessionMembers(courseSession.value.id);
|
||||||
cockpitStore.courseSessionUsers?.forEach((csu) => {
|
members.forEach((csu) => {
|
||||||
competenceStore.loadCompetenceProfilePage(
|
competenceStore.loadCompetenceProfilePage(
|
||||||
props.courseSlug + "-competencenavi-competences",
|
props.courseSlug + "-competencenavi-competences",
|
||||||
csu.user_id
|
csu.user_id
|
||||||
|
|
@ -31,7 +31,11 @@ onMounted(async () => {
|
||||||
|
|
||||||
learningPathStore.loadLearningPath(props.courseSlug + "-lp", csu.user_id);
|
learningPathStore.loadLearningPath(props.courseSlug + "-lp", csu.user_id);
|
||||||
});
|
});
|
||||||
learningPathStore.loadLearningPath(props.courseSlug + "-lp", useUserStore().id);
|
await learningPathStore.loadLearningPath(
|
||||||
|
props.courseSlug + "-lp",
|
||||||
|
useUserStore().id
|
||||||
|
);
|
||||||
|
await cockpitStore.loadCircles(props.courseSlug, courseSession.value.id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(error);
|
log.error(error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ onMounted(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const user = computed(() => {
|
const user = computed(() => {
|
||||||
return cockpitStore.courseSessionUsers?.find((csu) => csu.user_id === props.userId);
|
return cockpitStore.courseSessionMembers?.find((csu) => csu.user_id === props.userId);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ const learningPath = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const user = computed(() => {
|
const user = computed(() => {
|
||||||
return cockpitStore.courseSessionUsers?.find((csu) => csu.user_id === props.userId);
|
return cockpitStore.courseSessionMembers?.find((csu) => csu.user_id === props.userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
function setActiveClasses(isActive: boolean) {
|
function setActiveClasses(isActive: boolean) {
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,10 @@ const assignmentDetail = computed(() =>
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="cockpitStore.courseSessionUsers?.length" class="mt-6">
|
<div v-if="cockpitStore.courseSessionMembers?.length" class="mt-6">
|
||||||
<ul>
|
<ul>
|
||||||
<ItPersonRow
|
<ItPersonRow
|
||||||
v-for="csu in cockpitStore.courseSessionUsers"
|
v-for="csu in cockpitStore.courseSessionMembers"
|
||||||
:key="csu.user_id + csu.session_title"
|
:key="csu.user_id + csu.session_title"
|
||||||
:name="`${csu.first_name} ${csu.last_name}`"
|
:name="`${csu.first_name} ${csu.last_name}`"
|
||||||
:avatar-url="csu.avatar_url"
|
:avatar-url="csu.avatar_url"
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ watch(
|
||||||
|
|
||||||
<div class="mt-4 flex flex-col bg-white p-6">
|
<div class="mt-4 flex flex-col bg-white p-6">
|
||||||
<div
|
<div
|
||||||
v-for="(csu, index) in cockpitStore.courseSessionUsers"
|
v-for="(csu, index) in cockpitStore.courseSessionMembers"
|
||||||
:key="csu.user_id + csu.session_title"
|
:key="csu.user_id + csu.session_title"
|
||||||
>
|
>
|
||||||
<ItPersonRow
|
<ItPersonRow
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,9 @@ const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
const circleDates = computed(() => {
|
const circleDates = computed(() => {
|
||||||
const dueDates = courseSession.value.due_dates.filter((dueDate) => {
|
const dueDates = courseSession.value.due_dates.filter((dueDate) => {
|
||||||
return cockpitStore.selectedCircles.includes(
|
if (!cockpitStore.selectedCircle) return false;
|
||||||
dueDate?.circle?.translation_key ?? ""
|
return (
|
||||||
|
cockpitStore.selectedCircle.translation_key == dueDate?.circle?.translation_key
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return dueDates.slice(0, 4);
|
return dueDates.slice(0, 4);
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,10 @@ import SubmissionsOverview from "@/pages/cockpit/cockpitPage/SubmissionsOverview
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
import { useCompetenceStore } from "@/stores/competence";
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import { useUserStore } from "@/stores/user";
|
|
||||||
import groupBy from "lodash/groupBy";
|
import groupBy from "lodash/groupBy";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed } from "vue";
|
|
||||||
import CockpitDates from "@/pages/cockpit/cockpitPage/CockpitDates.vue";
|
import CockpitDates from "@/pages/cockpit/cockpitPage/CockpitDates.vue";
|
||||||
|
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSlug: string;
|
courseSlug: string;
|
||||||
|
|
@ -20,54 +19,19 @@ const props = defineProps<{
|
||||||
|
|
||||||
log.debug("CockpitIndexPage created", props.courseSlug);
|
log.debug("CockpitIndexPage created", props.courseSlug);
|
||||||
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const cockpitStore = useCockpitStore();
|
const cockpitStore = useCockpitStore();
|
||||||
const competenceStore = useCompetenceStore();
|
const competenceStore = useCompetenceStore();
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
const courseSession = useCurrentCourseSession();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
||||||
function userCountStatusForCircle(userId: string, translationKey: string) {
|
function userCountStatusForCircle(userId: string, translationKey: string) {
|
||||||
const criteria = competenceStore.flatPerformanceCriteria(
|
if (!cockpitStore.selectedCircle) return { FAIL: 0, SUCCESS: 0, UNKNOWN: 0 };
|
||||||
userId,
|
const criteria = competenceStore.flatPerformanceCriteria(userId, [
|
||||||
cockpitStore.selectedCircles
|
cockpitStore.selectedCircle.translation_key,
|
||||||
);
|
]);
|
||||||
const grouped = groupBy(criteria, "circle.translation_key");
|
const grouped = groupBy(criteria, "circle.translation_key");
|
||||||
|
|
||||||
return competenceStore.calcStatusCount(grouped[translationKey] as []);
|
return competenceStore.calcStatusCount(grouped[translationKey] as []);
|
||||||
}
|
}
|
||||||
|
|
||||||
const circles = computed(() => {
|
|
||||||
const learningPathCircles = learningPathStore
|
|
||||||
.learningPathForUser(props.courseSlug, userStore.id)
|
|
||||||
?.circles.map((c) => {
|
|
||||||
return {
|
|
||||||
id: c.id,
|
|
||||||
title: c.title,
|
|
||||||
slug: c.slug,
|
|
||||||
translation_key: c.translation_key,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
if (cockpitStore.cockpitSessionUser?.circles?.length) {
|
|
||||||
return cockpitStore.cockpitSessionUser.circles;
|
|
||||||
} else if (learningPathCircles) {
|
|
||||||
return learningPathCircles;
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const selectedCirclesTitles = computed(() => {
|
|
||||||
return circles.value
|
|
||||||
.filter((c) => cockpitStore.selectedCircles.includes(c.translation_key))
|
|
||||||
.map((c) => c.title) as string[];
|
|
||||||
});
|
|
||||||
|
|
||||||
function setActiveClasses(translationKey: string) {
|
|
||||||
return cockpitStore.selectedCircles.indexOf(translationKey) > -1
|
|
||||||
? ["bg-blue-900", "text-white"]
|
|
||||||
: ["text-bg-900"];
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -76,161 +40,160 @@ function setActiveClasses(translationKey: string) {
|
||||||
<div class="mb-9 flex items-end justify-between">
|
<div class="mb-9 flex items-end justify-between">
|
||||||
<h1>Cockpit</h1>
|
<h1>Cockpit</h1>
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<p class="text-base">{{ $t("general.circles") }}:</p>
|
<ItDropdownSelect
|
||||||
<ul class="ml-4 flex flex-row text-base font-bold leading-7">
|
v-model="cockpitStore.selectedCircle"
|
||||||
<li
|
class="mt-4 w-full lg:mt-0 lg:w-96"
|
||||||
v-for="circle in circles"
|
:items="cockpitStore.circles"
|
||||||
:key="circle.translation_key"
|
></ItDropdownSelect>
|
||||||
class="mr-4 last:mr-0"
|
</div>
|
||||||
>
|
</div>
|
||||||
<button
|
<template v-if="cockpitStore.selectedCircle">
|
||||||
class="mr-4 rounded-full border-2 border-blue-900 px-4 last:mr-0"
|
<!-- Status -->
|
||||||
:class="setActiveClasses(circle.translation_key)"
|
<div class="mb-4 gap-4 lg:grid lg:grid-cols-3 lg:grid-rows-none">
|
||||||
@click="cockpitStore.toggleCircleSelection(circle.translation_key)"
|
<div class="my-4 flex flex-col justify-between bg-white p-6 lg:my-0">
|
||||||
|
<div>
|
||||||
|
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
||||||
|
{{ $t("Trainerunterlagen") }}
|
||||||
|
</h3>
|
||||||
|
<div class="mb-4">
|
||||||
|
{{ $t("cockpit.trainerFilesText") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a
|
||||||
|
href="https://vbvbern.sharepoint.com/sites/myVBV-AFA_K-CI"
|
||||||
|
class="btn-secondary min-w-min"
|
||||||
|
target="_blank"
|
||||||
>
|
>
|
||||||
{{ circle.title }}
|
{{ $t("MS Teams öffnen") }}
|
||||||
</button>
|
</a>
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Status -->
|
|
||||||
<div class="mb-4 gap-4 lg:grid lg:grid-cols-3 lg:grid-rows-none">
|
|
||||||
<div class="my-4 flex flex-col justify-between bg-white p-6 lg:my-0">
|
|
||||||
<div>
|
|
||||||
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
|
||||||
{{ $t("Trainerunterlagen") }}
|
|
||||||
</h3>
|
|
||||||
<div class="mb-4">
|
|
||||||
{{ $t("cockpit.trainerFilesText") }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="my-4 flex flex-col justify-between bg-white p-6 lg:my-0">
|
||||||
<a
|
<div>
|
||||||
href="https://vbvbern.sharepoint.com/sites/myVBV-AFA_K-CI"
|
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
||||||
class="btn-secondary min-w-min"
|
{{ $t("Anwesenheitskontrolle Präsenzkurse") }}
|
||||||
target="_blank"
|
</h3>
|
||||||
>
|
<div class="mb-4">
|
||||||
{{ $t("MS Teams öffnen") }}
|
{{
|
||||||
</a>
|
$t(
|
||||||
</div>
|
"Hier überprüfst und bestätigst du die Anwesenheit deiner Teilnehmenden."
|
||||||
</div>
|
)
|
||||||
<div class="my-4 flex flex-col justify-between bg-white p-6 lg:my-0">
|
}}
|
||||||
<div>
|
</div>
|
||||||
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
</div>
|
||||||
{{ $t("Anwesenheitskontrolle Präsenzkurse") }}
|
<div>
|
||||||
</h3>
|
<router-link
|
||||||
<div class="mb-4">
|
:to="`/course/${props.courseSlug}/cockpit/attendance`"
|
||||||
{{
|
class="btn-secondary min-w-min"
|
||||||
$t(
|
>
|
||||||
"Hier überprüfst und bestätigst du die Anwesenheit deiner Teilnehmenden."
|
{{ $t("Anwesenheit prüfen") }}
|
||||||
)
|
</router-link>
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="bg-white p-6">
|
||||||
<router-link
|
<CockpitDates></CockpitDates>
|
||||||
:to="`/course/${props.courseSlug}/cockpit/attendance`"
|
|
||||||
class="btn-secondary min-w-min"
|
|
||||||
>
|
|
||||||
{{ $t("Anwesenheit prüfen") }}
|
|
||||||
</router-link>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white p-6">
|
<SubmissionsOverview
|
||||||
<CockpitDates></CockpitDates>
|
:course-session="courseSession"
|
||||||
</div>
|
:selected-circle="cockpitStore.selectedCircle.id"
|
||||||
</div>
|
></SubmissionsOverview>
|
||||||
<SubmissionsOverview
|
<div class="pt-4">
|
||||||
:course-session="courseSession"
|
<!-- progress -->
|
||||||
:selected-circles="selectedCirclesTitles"
|
<div v-if="cockpitStore.courseSessionMembers" class="bg-white p-6">
|
||||||
></SubmissionsOverview>
|
<h1 class="heading-3 mb-5">{{ $t("cockpit.progress") }}</h1>
|
||||||
<div class="pt-4">
|
<ul>
|
||||||
<!-- progress -->
|
<ItPersonRow
|
||||||
<div v-if="cockpitStore.courseSessionUsers" class="bg-white p-6">
|
v-for="csu in cockpitStore.courseSessionMembers"
|
||||||
<h1 class="heading-3 mb-5">{{ $t("cockpit.progress") }}</h1>
|
:key="csu.user_id + csu.session_title"
|
||||||
<ul>
|
:name="`${csu.first_name} ${csu.last_name}`"
|
||||||
<ItPersonRow
|
:avatar-url="csu.avatar_url"
|
||||||
v-for="csu in cockpitStore.courseSessionUsers"
|
>
|
||||||
:key="csu.user_id + csu.session_title"
|
<template #center>
|
||||||
:name="`${csu.first_name} ${csu.last_name}`"
|
<div
|
||||||
:avatar-url="csu.avatar_url"
|
class="mt-2 flex w-full flex-col items-center justify-between lg:mt-0 lg:flex-row"
|
||||||
>
|
>
|
||||||
<template #center>
|
<LearningPathDiagram
|
||||||
<div
|
v-if="
|
||||||
class="mt-2 flex w-full flex-col items-center justify-between lg:mt-0 lg:flex-row"
|
learningPathStore.learningPathForUser(
|
||||||
>
|
props.courseSlug,
|
||||||
<ul class="w-full">
|
csu.user_id
|
||||||
<li
|
)
|
||||||
v-for="(circle, i) of cockpitStore.selectedCircles"
|
"
|
||||||
:key="i"
|
:learning-path="
|
||||||
class="flex flex-col justify-between lg:h-12 lg:flex-row lg:items-center"
|
|
||||||
>
|
|
||||||
<LearningPathDiagram
|
|
||||||
v-if="
|
|
||||||
learningPathStore.learningPathForUser(
|
|
||||||
props.courseSlug,
|
|
||||||
csu.user_id
|
|
||||||
)
|
|
||||||
"
|
|
||||||
:learning-path="
|
|
||||||
learningPathStore.learningPathForUser(
|
learningPathStore.learningPathForUser(
|
||||||
props.courseSlug,
|
props.courseSlug,
|
||||||
csu.user_id
|
csu.user_id
|
||||||
) as LearningPath
|
) as LearningPath
|
||||||
"
|
"
|
||||||
:postfix="`cockpit-${csu.user_id}-${i}`"
|
:profile-user-id="`${csu.user_id}`"
|
||||||
:profile-user-id="`${csu.user_id}`"
|
:show-circle-translation-keys="[
|
||||||
:show-circle-translation-keys="[circle]"
|
cockpitStore.selectedCircle.translation_key,
|
||||||
:pull-up="false"
|
]"
|
||||||
diagram-type="singleSmall"
|
:pull-up="false"
|
||||||
class="mr-4"
|
diagram-type="singleSmall"
|
||||||
></LearningPathDiagram>
|
class="mr-4"
|
||||||
<p class="lg:min-w-[150px]">
|
></LearningPathDiagram>
|
||||||
{{ selectedCirclesTitles[i] }}
|
<p class="lg:min-w-[150px]">
|
||||||
</p>
|
{{ cockpitStore.selectedCircle.name }}
|
||||||
<div class="ml-4 flex flex-row items-center">
|
</p>
|
||||||
<div class="mr-6 flex flex-row items-center">
|
<div class="ml-4 flex flex-row items-center">
|
||||||
<it-icon-smiley-thinking
|
<div class="mr-6 flex flex-row items-center">
|
||||||
class="mr-2 inline-block h-8 w-8"
|
<it-icon-smiley-thinking
|
||||||
></it-icon-smiley-thinking>
|
class="mr-2 inline-block h-8 w-8"
|
||||||
<p class="text-bold inline-block w-6">
|
></it-icon-smiley-thinking>
|
||||||
{{ userCountStatusForCircle(csu.user_id, circle).FAIL }}
|
<p class="text-bold inline-block w-6">
|
||||||
</p>
|
{{
|
||||||
</div>
|
userCountStatusForCircle(
|
||||||
<li class="mr-6 flex flex-row items-center">
|
csu.user_id,
|
||||||
<it-icon-smiley-happy
|
cockpitStore.selectedCircle.translation_key
|
||||||
class="mr-2 inline-block h-8 w-8"
|
).FAIL
|
||||||
></it-icon-smiley-happy>
|
}}
|
||||||
<p class="text-bold inline-block w-6">
|
</p>
|
||||||
{{ userCountStatusForCircle(csu.user_id, circle).SUCCESS }}
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li class="flex flex-row items-center">
|
|
||||||
<it-icon-smiley-neutral
|
|
||||||
class="mr-2 inline-block h-8 w-8"
|
|
||||||
></it-icon-smiley-neutral>
|
|
||||||
<p class="text-bold inline-block w-6">
|
|
||||||
{{ userCountStatusForCircle(csu.user_id, circle).UNKNOWN }}
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
<li class="mr-6 flex flex-row items-center">
|
||||||
</ul>
|
<it-icon-smiley-happy
|
||||||
</div>
|
class="mr-2 inline-block h-8 w-8"
|
||||||
</template>
|
></it-icon-smiley-happy>
|
||||||
<template #link>
|
<p class="text-bold inline-block w-6">
|
||||||
<router-link
|
{{
|
||||||
:to="`/course/${props.courseSlug}/cockpit/profile/${csu.user_id}`"
|
userCountStatusForCircle(
|
||||||
class="link w-full lg:text-right"
|
csu.user_id,
|
||||||
>
|
cockpitStore.selectedCircle.translation_key
|
||||||
{{ $t("general.profileLink") }}
|
).SUCCESS
|
||||||
</router-link>
|
}}
|
||||||
</template>
|
</p>
|
||||||
</ItPersonRow>
|
</li>
|
||||||
</ul>
|
<li class="flex flex-row items-center">
|
||||||
|
<it-icon-smiley-neutral
|
||||||
|
class="mr-2 inline-block h-8 w-8"
|
||||||
|
></it-icon-smiley-neutral>
|
||||||
|
<p class="text-bold inline-block w-6">
|
||||||
|
{{
|
||||||
|
userCountStatusForCircle(
|
||||||
|
csu.user_id,
|
||||||
|
cockpitStore.selectedCircle.translation_key
|
||||||
|
).UNKNOWN
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #link>
|
||||||
|
<router-link
|
||||||
|
:to="`/course/${props.courseSlug}/cockpit/profile/${csu.user_id}`"
|
||||||
|
class="link w-full lg:text-right"
|
||||||
|
>
|
||||||
|
{{ $t("general.profileLink") }}
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
</ItPersonRow>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ const cockpitStore = useCockpitStore();
|
||||||
const completeFeedbacks = ref(0);
|
const completeFeedbacks = ref(0);
|
||||||
|
|
||||||
const numFeedbacks = computed(() => {
|
const numFeedbacks = computed(() => {
|
||||||
return cockpitStore.courseSessionUsers?.length ?? 0;
|
return cockpitStore.courseSessionMembers?.length ?? 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ interface Submittable {
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSession: CourseSession;
|
courseSession: CourseSession;
|
||||||
selectedCircles: string[];
|
selectedCircle: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
log.debug("SubmissionsOverview created", props.courseSession.id);
|
log.debug("SubmissionsOverview created", props.courseSession.id);
|
||||||
|
|
@ -46,7 +46,7 @@ const submittables = computed(() => {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return learningPath.circles
|
return learningPath.circles
|
||||||
.filter((circle) => props.selectedCircles.includes(circle.title))
|
.filter((circle) => props.selectedCircle == circle.id)
|
||||||
.flatMap((circle) => {
|
.flatMap((circle) => {
|
||||||
const learningContents = circle.flatLearningContents.filter(
|
const learningContents = circle.flatLearningContents.filter(
|
||||||
(lc) =>
|
(lc) =>
|
||||||
|
|
@ -128,7 +128,7 @@ const getIconName = (lc: LearningContent) => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-white px-6 py-2">
|
<div class="bg-white px-6 py-2">
|
||||||
<div v-if="cockpitStore.courseSessionUsers" class="divide-y divide-gray-500">
|
<div v-if="cockpitStore.courseSessionMembers" class="divide-y divide-gray-500">
|
||||||
<div
|
<div
|
||||||
v-for="submittable in submittables"
|
v-for="submittable in submittables"
|
||||||
:key="submittable.id"
|
:key="submittable.id"
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,9 @@ export async function loadAssignmentCompletionStatusData(
|
||||||
`/api/assignment/${assignmentId}/${courseSessionId}/status/`
|
`/api/assignment/${assignmentId}/${courseSessionId}/status/`
|
||||||
)) as UserAssignmentCompletionStatus[];
|
)) as UserAssignmentCompletionStatus[];
|
||||||
|
|
||||||
const courseSessionUsers = await cockpitStore.loadCourseSessionUsers(courseSessionId);
|
const courseSessionUsers = await cockpitStore.loadCourseSessionMembers(
|
||||||
|
courseSessionId
|
||||||
|
);
|
||||||
|
|
||||||
const gradedUsers: GradedUser[] = [];
|
const gradedUsers: GradedUser[] = [];
|
||||||
const assignmentSubmittedUsers: CourseSessionUser[] = [];
|
const assignmentSubmittedUsers: CourseSessionUser[] = [];
|
||||||
|
|
|
||||||
|
|
@ -2,27 +2,58 @@ import { itGetCached } from "@/fetchHelpers";
|
||||||
import type { CourseSessionUser, ExpertSessionUser } from "@/types";
|
import type { CourseSessionUser, ExpertSessionUser } from "@/types";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
|
|
||||||
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export type CockpitStoreState = {
|
export type CockpitStoreState = {
|
||||||
courseSessionUsers: CourseSessionUser[] | undefined;
|
courseSessionMembers: CourseSessionUser[] | undefined;
|
||||||
cockpitSessionUser: ExpertSessionUser | undefined;
|
selectedCircle:
|
||||||
selectedCircles: string[];
|
| {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
translation_key: string;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
circles: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
translation_key: string;
|
||||||
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useCockpitStore = defineStore({
|
export const useCockpitStore = defineStore({
|
||||||
id: "cockpit",
|
id: "cockpit",
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
courseSessionUsers: undefined,
|
courseSessionMembers: undefined,
|
||||||
cockpitSessionUser: undefined,
|
selectedCircle: undefined,
|
||||||
selectedCircles: [],
|
circles: [],
|
||||||
} as CockpitStoreState;
|
} as CockpitStoreState;
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async loadCourseSessionUsers(courseSessionId: number, reload = false) {
|
async loadCircles(courseSlug: string, courseSessionId: number) {
|
||||||
log.debug("loadCockpitData called");
|
log.debug("loadCircles called");
|
||||||
|
|
||||||
|
const f = await courseCircles(courseSlug, courseSessionId);
|
||||||
|
|
||||||
|
this.circles = f.map((c) => {
|
||||||
|
return {
|
||||||
|
id: c.id,
|
||||||
|
name: c.title,
|
||||||
|
slug: c.slug,
|
||||||
|
translation_key: c.translation_key,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.circles.length > 0) {
|
||||||
|
this.selectedCircle = this.circles[0];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadCourseSessionMembers(courseSessionId: number, reload = false) {
|
||||||
|
log.debug("loadCourseSessionMembers called");
|
||||||
const users = (await itGetCached(
|
const users = (await itGetCached(
|
||||||
`/api/course/sessions/${courseSessionId}/users/`,
|
`/api/course/sessions/${courseSessionId}/users/`,
|
||||||
{
|
{
|
||||||
|
|
@ -30,38 +61,42 @@ export const useCockpitStore = defineStore({
|
||||||
}
|
}
|
||||||
)) as CourseSessionUser[];
|
)) as CourseSessionUser[];
|
||||||
|
|
||||||
this.courseSessionUsers = users.filter((user) => user.role === "MEMBER");
|
this.courseSessionMembers = users.filter((user) => user.role === "MEMBER");
|
||||||
|
return this.courseSessionMembers;
|
||||||
const userStore = useUserStore();
|
|
||||||
const currentUser = users.find((user) => user.user_id === userStore.id);
|
|
||||||
|
|
||||||
if (currentUser && currentUser.role === "EXPERT") {
|
|
||||||
this.cockpitSessionUser = currentUser as ExpertSessionUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.selectedCircles.length === 0) {
|
|
||||||
// workaround to select first circle by default, when nothing is selected...
|
|
||||||
// TODO: is this the right place to do this?
|
|
||||||
if (this.cockpitSessionUser && this.cockpitSessionUser.circles?.length > 0) {
|
|
||||||
this.selectedCircles = [this.cockpitSessionUser.circles[0].translation_key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.courseSessionUsers) {
|
|
||||||
throw `No courseSessionUsers data found for user`;
|
|
||||||
}
|
|
||||||
return this.courseSessionUsers;
|
|
||||||
},
|
|
||||||
toggleCircleSelection(translationKey: string) {
|
|
||||||
if (this.selectedCircles.indexOf(translationKey) < 0) {
|
|
||||||
this.selectedCircles.push(translationKey);
|
|
||||||
} else {
|
|
||||||
if (this.selectedCircles.length === 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const index = this.selectedCircles.indexOf(translationKey);
|
|
||||||
this.selectedCircles.splice(index, 1);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function courseCircles(courseSlug: string, courseSessionId: number) {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const userId = userStore.id;
|
||||||
|
|
||||||
|
const users = (await itGetCached(`/api/course/sessions/${courseSessionId}/users/`, {
|
||||||
|
reload: false,
|
||||||
|
})) as CourseSessionUser[];
|
||||||
|
|
||||||
|
// First check if current user is an expert for this course session
|
||||||
|
const currentUser = users.find((user) => user.user_id === userId);
|
||||||
|
if (currentUser && currentUser.role === "EXPERT") {
|
||||||
|
const expert = currentUser as ExpertSessionUser;
|
||||||
|
return expert.circles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return all circles from learning path for admin users
|
||||||
|
if (userStore.is_superuser) {
|
||||||
|
const learningPathStore = useLearningPathStore();
|
||||||
|
const learningPathCircles = learningPathStore
|
||||||
|
.learningPathForUser(courseSlug, userId)
|
||||||
|
?.circles.map((c) => {
|
||||||
|
return {
|
||||||
|
id: c.id,
|
||||||
|
title: c.title,
|
||||||
|
slug: c.slug,
|
||||||
|
translation_key: c.translation_key,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return learningPathCircles || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue