Completion data in Performance Criteria view

This commit is contained in:
Daniel Egger 2022-10-07 14:20:42 +02:00
parent dc3b1a4ca6
commit 46ad6cab36
6 changed files with 97 additions and 98 deletions

View File

@ -3,7 +3,7 @@ import type { PerformanceCriteria } from "@/types";
interface Props {
criteria: PerformanceCriteria;
showState: boolean;
showState?: boolean;
}
const props = withDefaults(defineProps<Props>(), {

View File

@ -1,95 +1,20 @@
<script setup lang="ts">
import { default as PerformanceCriteriaRow } from "@/components/competences/PerformanceCriteriaRow.vue";
import { useCompetenceStore } from "@/stores/competence";
import type { CourseCompletionStatus } from "@/types";
import * as log from "loglevel";
import { computed, Ref, ref } from "vue";
log.debug("CompetencesMainView created");
enum UserCriteriaState {
Open = "open",
Done = "done",
Nok = "notDone",
}
const competenceStore = useCompetenceStore();
const data = {
id: 340,
title: "Kompetenzprofil",
slug: "versicherungsvermittlerin-competence",
type: "competence.CompetenceProfilePage",
translation_key: "a3adb9ac-606d-42fd-b115-842af3706926",
course: {
id: -1,
title: "Versicherungsvermittler/in",
category_name: "Handlungsfeld",
},
children: [
{
id: 341,
title:
"Innerhalb des Handlungsfelds «Fahrzeug» bin ich fähig, die Ziele und Pläne des Kunden zu ergründen (SOLL).",
slug: "kompetenzprofil-crit-innerhalb-des-handlungsfelds-fahrzeug-bin-ich-fähig-die-ziele-und-pläne-des-kunden-zu-ergründen-soll",
type: "competence.PerformanceCriteria",
translation_key: "e4aeeb81-0730-44f5-9c70-cec84d162569",
pc_id: "B1.3 Fahrzeug",
learning_unit: {
id: 123,
title: "Auto verkaufen",
slug: "versicherungsvermittlerin-lp-circle-analyse-lu-fahrzeug",
type: "learnpath.LearningUnit",
translation_key: "c4797663-90c3-493f-9f21-e95ad0a37eb2",
},
circle: "Analyse",
},
{
id: 342,
title:
"Innerhalb des Handlungsfelds «Fahrzeug» bin ich fähig, die IST-Situation des Kunden mit der geeigneten Gesprächs-/Fragetechnik zu erfassen.",
slug: "kompetenzprofil-crit-innerhalb-des-handlungsfelds-fahrzeug-bin-ich-fähig-die-ist-situation-des-kunden-mit-der-geeigneten-gesprächs-fragetechnik-zu-erfassen",
type: "competence.PerformanceCriteria",
translation_key: "25d56b74-4151-49bd-ac1f-5e706a660aae",
pc_id: "B2.1 Fahrzeug",
learning_unit: {
id: 123,
title: "Auto verkaufen",
slug: "versicherungsvermittlerin-lp-circle-analyse-lu-fahrzeug",
type: "learnpath.LearningUnit",
translation_key: "c4797663-90c3-493f-9f21-e95ad0a37eb2",
},
circle: "Analyse",
},
{
id: 343,
title:
"Innerhalb des Handlungsfelds «Fahrzeug» bin ich fähig, die Risiken aufzuzeigen.",
slug: "kompetenzprofil-crit-innerhalb-des-handlungsfelds-fahrzeug-bin-ich-fähig-die-risiken-aufzuzeigen",
type: "competence.PerformanceCriteria",
translation_key: "71bfb708-70c7-4e50-a424-104fe10ab7bc",
pc_id: "B2.2 Fahrzeug",
learning_unit: {
id: 123,
title: "Auto verkaufen",
slug: "versicherungsvermittlerin-lp-circle-analyse-lu-fahrzeug",
type: "learnpath.LearningUnit",
translation_key: "c4797663-90c3-493f-9f21-e95ad0a37eb2",
},
circle: "Analyse",
},
],
};
const userProgress = {
341: "open",
342: "notDone",
343: "done",
};
const activeState: Ref<UserCriteriaState> = ref(UserCriteriaState.Nok);
const activeState: Ref<CourseCompletionStatus> = ref("fail");
const shownCriteria = computed(() => {
return competenceStore.flatPerformanceCriteria;
return competenceStore.flatPerformanceCriteria.filter((criteria) => {
return criteria.completion_status === activeState.value;
});
});
</script>
@ -112,25 +37,25 @@ const shownCriteria = computed(() => {
class="border-b border-gray-500 flex flex-col lg:flex-row lg:items-center pb-4 mb-4"
>
<button
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Nok }"
:class="{ 'bg-gray-200': activeState === 'fail' }"
class="flex flex-row items-center py-4 px-2 mr-6"
@click="activeState = UserCriteriaState.Nok"
@click="activeState = 'fail'"
>
<span class="inline-block mr-2">«Das muss ich nochmals anschauen»</span>
<span><it-icon-smiley-thinking></it-icon-smiley-thinking></span>
</button>
<button
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Done }"
:class="{ 'bg-gray-200': activeState === 'success' }"
class="flex flex-row items-center py-4 px-2 mr-6"
@click="activeState = UserCriteriaState.Done"
@click="activeState = 'success'"
>
<span class="inline-block mr-2">«Ja, ich kann das»</span>
<span><it-icon-smiley-happy></it-icon-smiley-happy></span>
</button>
<button
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Open }"
:class="{ 'bg-gray-200': activeState === 'unknown' }"
class="flex flex-row items-center py-4 px-2"
@click="activeState = UserCriteriaState.Open"
@click="activeState = 'unknown'"
>
<span class="inline-block mr-2">Nicht eingeschätzt</span>
<span><it-icon-smiley-neutral></it-icon-smiley-neutral></span>
@ -139,10 +64,13 @@ const shownCriteria = computed(() => {
<ul class="mb-6">
<li
v-for="criteria in shownCriteria"
:key="criteria.title"
:key="criteria.id"
class="mb-4 pb-4 border-b border-gray-500"
>
<PerformanceCriteriaRow :criteria="criteria"> </PerformanceCriteriaRow>
<PerformanceCriteriaRow
:criteria="criteria"
:show-state="true"
></PerformanceCriteriaRow>
</li>
</ul>
</div>

View File

@ -1,9 +1,7 @@
import * as log from "loglevel";
import { defineStore } from "pinia";
import { itPost } from "@/fetchHelpers";
import type { Circle } from "@/services/circle";
import { useCompletionStore } from "@/stores/completion";
import { useLearningPathStore } from "@/stores/learningPath";
import type {
CourseCompletionStatus,
@ -11,6 +9,7 @@ import type {
LearningUnit,
LearningUnitPerformanceCriteria,
} from "@/types";
import { defineStore } from "pinia";
export type CircleStoreState = {
circle: Circle | undefined;
@ -89,12 +88,11 @@ export const useCircleStore = defineStore({
page: LearningContent | LearningUnitPerformanceCriteria,
completion_status: CourseCompletionStatus = "success"
) {
const completionStore = useCompletionStore();
try {
page.completion_status = completion_status;
const completionData = await itPost("/api/course/completion/mark/", {
page_key: page.translation_key,
completion_status: page.completion_status,
});
const completionData = await completionStore.markPage(page);
if (this.circle) {
this.circle.parseCompletionData(completionData);
}

View File

@ -1,4 +1,5 @@
import { itGet } from "@/fetchHelpers";
import { useCompletionStore } from "@/stores/completion";
import type { CompetenceProfilePage } from "@/types";
import _ from "lodash";
import { defineStore } from "pinia";
@ -38,6 +39,7 @@ export const useCompetenceStore = defineStore({
actions: {
async loadCompetenceProfilePage(slug: string, reload = false) {
if (this.competenceProfilePage && !reload) {
await this.parseCompletionData();
return this.competenceProfilePage;
}
const competenceProfilePageData = await itGet(`/api/course/page/${slug}/`);
@ -47,7 +49,32 @@ export const useCompetenceStore = defineStore({
}
this.competenceProfilePage = competenceProfilePageData;
await this.parseCompletionData();
return this.competenceProfilePage;
},
async parseCompletionData() {
if (this.competenceProfilePage) {
const completionStore = useCompletionStore();
const completionData = await completionStore.loadCompletionData(
this.competenceProfilePage.course.id
);
if (completionData) {
this.competenceProfilePage.children.forEach((competence) => {
competence.children.forEach((performanceCriteria) => {
const completion = completionData.find(
(c) => c.page_key === performanceCriteria.translation_key
);
if (completion) {
performanceCriteria.completion_status = completion.completion_status;
} else {
performanceCriteria.completion_status = "unknown";
}
});
});
}
}
},
},
});

View File

@ -0,0 +1,44 @@
import { itGet, itPost } from "@/fetchHelpers";
import type { CourseCompletion, CourseWagtailPage } from "@/types";
import { defineStore } from "pinia";
export type CompletionStoreState = {
completionData: CourseCompletion[] | undefined;
};
export const useCompletionStore = defineStore({
id: "completion",
state: () => {
return {
completionData: undefined,
} as CompletionStoreState;
},
getters: {},
actions: {
async loadCompletionData(courseId: number, reload = false) {
if (this.completionData && !reload) {
return this.completionData;
}
const completionData = await itGet(`/api/course/completion/${courseId}/`);
if (!completionData) {
throw `No completionData found with: ${courseId}`;
}
this.completionData = completionData;
return this.completionData || [];
},
async markPage(page: CourseWagtailPage) {
const completionData = await itPost("/api/course/completion/mark/", {
page_key: page.translation_key,
completion_status: page.completion_status,
});
if (completionData) {
this.completionData = completionData;
}
return this.completionData || [];
},
},
});

View File

@ -1,5 +1,6 @@
import { itGet } from "@/fetchHelpers";
import { LearningPath } from "@/services/learningPath";
import { useCompletionStore } from "@/stores/completion";
import { defineStore } from "pinia";
export type LearningPathStoreState = {
@ -18,12 +19,13 @@ export const useLearningPathStore = defineStore({
getters: {},
actions: {
async loadLearningPath(slug: string, reload = false) {
const completionStore = useCompletionStore();
if (this.learningPath && !reload) {
return this.learningPath;
}
const learningPathData = await itGet(`/api/course/page/${slug}/`);
const completionData = await itGet(
`/api/course/completion/${learningPathData.course.id}/`
const completionData = await completionStore.loadCompletionData(
learningPathData.course.id
);
if (!learningPathData) {