Add backend data to competence profile
This commit is contained in:
parent
22e3fce59e
commit
dc3b1a4ca6
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ComptenceProgress from "@/components/competences/CompetenceProgress.vue";
|
import ComptenceProgress from "@/components/competences/CompetenceProgress.vue";
|
||||||
import LeistungskriteriumRow from "@/components/competences/LeistungskriteriumRow.vue";
|
import LeistungskriteriumRow from "@/components/competences/PerformanceCriteriaRow.vue";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
@ -25,9 +25,9 @@ const userStateForCriteria = (id: string) =>
|
||||||
<h2 class="text-large">{{ competence.description }}</h2>
|
<h2 class="text-large">{{ competence.description }}</h2>
|
||||||
<button class="transition-transform" :class="{ 'rotate-180': isOpen }">
|
<button class="transition-transform" :class="{ 'rotate-180': isOpen }">
|
||||||
<it-icon-arrow-down
|
<it-icon-arrow-down
|
||||||
@click="togglePerformanceCriteria()"
|
|
||||||
class="h-10 w-10"
|
class="h-10 w-10"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
|
@click="togglePerformanceCriteria()"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -41,7 +41,7 @@ const userStateForCriteria = (id: string) =>
|
||||||
>
|
>
|
||||||
<LeistungskriteriumRow
|
<LeistungskriteriumRow
|
||||||
:state="userStateForCriteria(`${performanceCriteria.id}`)"
|
:state="userStateForCriteria(`${performanceCriteria.id}`)"
|
||||||
:showState="true"
|
:show-state="true"
|
||||||
:unit-url="performanceCriteria.learning_unit.slug"
|
:unit-url="performanceCriteria.learning_unit.slug"
|
||||||
:unit="performanceCriteria.pc_id"
|
:unit="performanceCriteria.pc_id"
|
||||||
:title="performanceCriteria.title"
|
:title="performanceCriteria.title"
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
interface Props {
|
|
||||||
title: string;
|
|
||||||
unit: string;
|
|
||||||
unitUrl: string;
|
|
||||||
unitId: number;
|
|
||||||
state?: string; // maybe enum
|
|
||||||
showState?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
title: "",
|
|
||||||
unit: "",
|
|
||||||
unitUrl: "",
|
|
||||||
unitId: -1,
|
|
||||||
state: "open",
|
|
||||||
showState: false,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="flex flex-col lg:flex-row lg:items-center justify-between">
|
|
||||||
<div class="flex flex-row items-center">
|
|
||||||
<div v-if="showState" class="h-8 w-8 mr-4">
|
|
||||||
<it-icon-smiley-happy v-if="state === 'done'"></it-icon-smiley-happy>
|
|
||||||
<it-icon-smiley-thinking
|
|
||||||
v-else-if="state === 'notDone'"
|
|
||||||
></it-icon-smiley-thinking>
|
|
||||||
<it-icon-smiley-neutral v-else></it-icon-smiley-neutral>
|
|
||||||
</div>
|
|
||||||
<div class="pr-5 lg:mr-10 mb-4 lg:mb-0">
|
|
||||||
<h4 class="text-bold mb-2">{{ title }}</h4>
|
|
||||||
<p>
|
|
||||||
Lerneinheit: <a :href="unitUrl">{{ unit }}</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<span class="whitespace-nowrap">Sich nochmals einschätzen</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { PerformanceCriteria } from "@/types";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
criteria: PerformanceCriteria;
|
||||||
|
showState: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
criteria: undefined,
|
||||||
|
showState: false,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col lg:flex-row lg:items-center justify-between">
|
||||||
|
<div class="flex flex-row items-center">
|
||||||
|
<div v-if="showState" class="h-8 w-8 mr-4">
|
||||||
|
<it-icon-smiley-happy
|
||||||
|
v-if="criteria.completion_status === 'success'"
|
||||||
|
></it-icon-smiley-happy>
|
||||||
|
<it-icon-smiley-thinking
|
||||||
|
v-else-if="criteria.completion_status === 'fail'"
|
||||||
|
></it-icon-smiley-thinking>
|
||||||
|
<it-icon-smiley-neutral v-else></it-icon-smiley-neutral>
|
||||||
|
</div>
|
||||||
|
<div class="pr-5 lg:mr-10 mb-4 lg:mb-0">
|
||||||
|
<h4 class="text-bold mb-2">{{ criteria.title }}</h4>
|
||||||
|
<p>
|
||||||
|
Lerneinheit:
|
||||||
|
<a class="link" :href="criteria.learning_unit.frontend_url">
|
||||||
|
{{ criteria.learning_unit.title }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="whitespace-nowrap">
|
||||||
|
<a class="link" :href="criteria.learning_unit.frontend_url">
|
||||||
|
Sich nochmals einschätzen
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LeistungskriteriumRow from "@/components/competences/LeistungskriteriumRow.vue";
|
import { default as PerformanceCriteriaRow } from "@/components/competences/PerformanceCriteriaRow.vue";
|
||||||
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { computed, Ref, ref } from "vue";
|
import { computed, Ref, ref } from "vue";
|
||||||
|
|
||||||
|
|
@ -11,6 +12,8 @@ enum UserCriteriaState {
|
||||||
Nok = "notDone",
|
Nok = "notDone",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const competenceStore = useCompetenceStore();
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
id: 340,
|
id: 340,
|
||||||
title: "Kompetenzprofil",
|
title: "Kompetenzprofil",
|
||||||
|
|
@ -86,17 +89,16 @@ const userProgress = {
|
||||||
const activeState: Ref<UserCriteriaState> = ref(UserCriteriaState.Nok);
|
const activeState: Ref<UserCriteriaState> = ref(UserCriteriaState.Nok);
|
||||||
|
|
||||||
const shownCriteria = computed(() => {
|
const shownCriteria = computed(() => {
|
||||||
return data.children.filter(
|
return competenceStore.flatPerformanceCriteria;
|
||||||
(criteria) => userProgress[`${criteria.id}`] === activeState.value
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mx-auto max-w-5xl">
|
<div class="container-large">
|
||||||
<nav>
|
<nav>
|
||||||
<a class="block mb-8 cursor-pointer flex items-center" @click="router.go(-1)"
|
<a class="block mb-8 cursor-pointer flex items-center" @click="router.go(-1)">
|
||||||
><it-icon-arrow-left /><span>zurück</span></a
|
<it-icon-arrow-left />
|
||||||
|
<span>zurück</span></a
|
||||||
>
|
>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="flex flex-col lg:flex-row items-center justify-between mb-10">
|
<div class="flex flex-col lg:flex-row items-center justify-between mb-10">
|
||||||
|
|
@ -110,25 +112,25 @@ const shownCriteria = computed(() => {
|
||||||
class="border-b border-gray-500 flex flex-col lg:flex-row lg:items-center pb-4 mb-4"
|
class="border-b border-gray-500 flex flex-col lg:flex-row lg:items-center pb-4 mb-4"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
@click="activeState = UserCriteriaState.Nok"
|
|
||||||
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Nok }"
|
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Nok }"
|
||||||
class="flex flex-row items-center py-4 px-2 mr-6"
|
class="flex flex-row items-center py-4 px-2 mr-6"
|
||||||
|
@click="activeState = UserCriteriaState.Nok"
|
||||||
>
|
>
|
||||||
<span class="inline-block mr-2">«Das muss ich nochmals anschauen»</span>
|
<span class="inline-block mr-2">«Das muss ich nochmals anschauen»</span>
|
||||||
<span><it-icon-smiley-thinking></it-icon-smiley-thinking></span>
|
<span><it-icon-smiley-thinking></it-icon-smiley-thinking></span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="activeState = UserCriteriaState.Done"
|
|
||||||
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Done }"
|
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Done }"
|
||||||
class="flex flex-row items-center py-4 px-2 mr-6"
|
class="flex flex-row items-center py-4 px-2 mr-6"
|
||||||
|
@click="activeState = UserCriteriaState.Done"
|
||||||
>
|
>
|
||||||
<span class="inline-block mr-2">«Ja, ich kann das»</span>
|
<span class="inline-block mr-2">«Ja, ich kann das»</span>
|
||||||
<span><it-icon-smiley-happy></it-icon-smiley-happy></span>
|
<span><it-icon-smiley-happy></it-icon-smiley-happy></span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="activeState = UserCriteriaState.Open"
|
|
||||||
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Open }"
|
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Open }"
|
||||||
class="flex flex-row items-center py-4 px-2"
|
class="flex flex-row items-center py-4 px-2"
|
||||||
|
@click="activeState = UserCriteriaState.Open"
|
||||||
>
|
>
|
||||||
<span class="inline-block mr-2">Nicht eingeschätzt</span>
|
<span class="inline-block mr-2">Nicht eingeschätzt</span>
|
||||||
<span><it-icon-smiley-neutral></it-icon-smiley-neutral></span>
|
<span><it-icon-smiley-neutral></it-icon-smiley-neutral></span>
|
||||||
|
|
@ -140,12 +142,7 @@ const shownCriteria = computed(() => {
|
||||||
:key="criteria.title"
|
:key="criteria.title"
|
||||||
class="mb-4 pb-4 border-b border-gray-500"
|
class="mb-4 pb-4 border-b border-gray-500"
|
||||||
>
|
>
|
||||||
<LeistungskriteriumRow
|
<PerformanceCriteriaRow :criteria="criteria"> </PerformanceCriteriaRow>
|
||||||
:unit-url="criteria.learning_unit.slug"
|
|
||||||
:unit="criteria.pc_id"
|
|
||||||
:title="criteria.title"
|
|
||||||
:unit-id="criteria.learning_unit.id"
|
|
||||||
></LeistungskriteriumRow>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ComptenceProgress from "@/components/competences/CompetenceProgress.vue";
|
import ComptenceProgress from "@/components/competences/CompetenceProgress.vue";
|
||||||
import LeistungskriteriumRow from "@/components/competences/LeistungskriteriumRow.vue";
|
import LeistungskriteriumRow from "@/components/competences/PerformanceCriteriaRow.vue";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
|
|
||||||
log.debug("CompetencesMainView created");
|
log.debug("CompetencesMainView created");
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,30 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { onMounted } from "vue";
|
import { onMounted } from "vue";
|
||||||
|
|
||||||
log.debug("CometencesView created");
|
log.debug("CometencesView created");
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
competencesPageSlug: string;
|
competenceProfilePageSlug: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const competenceStore = useCompetenceStore();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("CompetencesView mounted", props.competencesPageSlug);
|
log.debug("CompetencesView mounted", props.competenceProfilePageSlug);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await competenceStore.loadCompetenceProfilePage(props.competenceProfilePageSlug);
|
||||||
|
} catch (error) {
|
||||||
|
log.error(error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-200">
|
<div class="bg-gray-200">
|
||||||
<main class="px-8 py-8">
|
<main>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ const router = createRouter({
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/competences/:competencesPageSlug",
|
path: "/competence/:competenceProfilePageSlug",
|
||||||
props: true,
|
props: true,
|
||||||
component: () => import("@/pages/ComptencesView.vue"),
|
component: () => import("@/pages/ComptencesView.vue"),
|
||||||
children: [
|
children: [
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { itGet } from "@/fetchHelpers";
|
||||||
|
import type { CompetenceProfilePage } from "@/types";
|
||||||
|
import _ from "lodash";
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
|
export type CompetenceStoreState = {
|
||||||
|
competenceProfilePage: CompetenceProfilePage | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCompetenceStore = defineStore({
|
||||||
|
id: "competence",
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
competenceProfilePage: undefined,
|
||||||
|
} as CompetenceStoreState;
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
flatPerformanceCriteria: (state, circleTitle = "") => {
|
||||||
|
if (!state.competenceProfilePage) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
let criteria = _.orderBy(
|
||||||
|
state.competenceProfilePage.children.flatMap((competence) => {
|
||||||
|
return competence.children;
|
||||||
|
}),
|
||||||
|
["competence_id"],
|
||||||
|
["asc"]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (circleTitle) {
|
||||||
|
criteria = criteria.filter((c) => c.circle === circleTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return criteria;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
async loadCompetenceProfilePage(slug: string, reload = false) {
|
||||||
|
if (this.competenceProfilePage && !reload) {
|
||||||
|
return this.competenceProfilePage;
|
||||||
|
}
|
||||||
|
const competenceProfilePageData = await itGet(`/api/course/page/${slug}/`);
|
||||||
|
|
||||||
|
if (!competenceProfilePageData) {
|
||||||
|
throw `No competenceProfilePageData found with: ${slug}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.competenceProfilePage = competenceProfilePageData;
|
||||||
|
return this.competenceProfilePage;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -290,3 +290,23 @@ export interface MediaLibraryPage extends CourseWagtailPage {
|
||||||
course: Course;
|
course: Course;
|
||||||
children: MediaCategoryPage[];
|
children: MediaCategoryPage[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PerformanceCriteria extends CourseWagtailPage {
|
||||||
|
type: "competence.PerformanceCriteria";
|
||||||
|
competence_id: string;
|
||||||
|
circle: string;
|
||||||
|
course_category: CourseCategory;
|
||||||
|
learning_unit: CourseWagtailPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompetencePage extends CourseWagtailPage {
|
||||||
|
type: "competence.CompetencePage";
|
||||||
|
competence_id: string;
|
||||||
|
children: PerformanceCriteria[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompetenceProfilePage extends CourseWagtailPage {
|
||||||
|
type: "competence.CompetenceProfilePage";
|
||||||
|
course: Course;
|
||||||
|
children: CompetencePage[];
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,27 @@
|
||||||
{
|
{
|
||||||
"extends": "@vue/tsconfig/tsconfig.web.json",
|
"extends": "@vue/tsconfig/tsconfig.web.json",
|
||||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
"include": [
|
||||||
"exclude": ["src/**/__tests__/*"],
|
"env.d.ts",
|
||||||
|
"src/**/*",
|
||||||
|
"src/**/*.vue"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"src/**/__tests__/*"
|
||||||
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"lib": [
|
||||||
|
"ES2021",
|
||||||
|
"DOM",
|
||||||
|
"DOM.Iterable"
|
||||||
|
],
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ class CompetencePage(Page):
|
||||||
return get_it_serializer_class(
|
return get_it_serializer_class(
|
||||||
cls,
|
cls,
|
||||||
[
|
[
|
||||||
|
"competence_id",
|
||||||
"children",
|
"children",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue