Handle closing of self evaluation in KompetenzNavi

This commit is contained in:
Daniel Egger 2023-09-14 10:37:13 +02:00
parent 5dfdd470ae
commit dfa03baa25
12 changed files with 100 additions and 498 deletions

View File

@ -1,179 +0,0 @@
<script setup lang="ts">
import PerformanceCriteriaRow from "@/pages/competence-old/PerformanceCriteriaRow.vue";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import ItProgress from "@/components/ui/ItProgress.vue";
import { useCompetenceStore } from "@/stores/competence";
import maxBy from "lodash/maxBy";
import orderBy from "lodash/orderBy";
import * as log from "loglevel";
import { computed } from "vue";
log.debug("CompetenceIndexPage created");
const props = defineProps<{
courseSlug: string;
}>();
log.debug("CompetenceIndexPage created", props);
const competenceStore = useCompetenceStore();
const failedCriteria = computed(() => {
return competenceStore
.flatPerformanceCriteria()
.filter((criteria) => {
return criteria.completion_status === "FAIL";
})
.slice(0, 3);
});
const lastUpdatedCompetences = computed(() => {
return orderBy(
competenceStore.competences(),
[
(competence) => {
let criteria = competence.children;
if (competenceStore.selectedCircle.id != "all") {
criteria = criteria.filter((criteria) => {
return (
criteria.circle.translation_key === competenceStore.selectedCircle.id
);
});
}
return (
maxBy(criteria, "completion_status_updated_at")
?.completion_status_updated_at || ""
);
},
],
["desc"]
).slice(0, 3);
});
const countStatus = computed(() => {
return competenceStore.calcStatusCount(competenceStore.flatPerformanceCriteria());
});
</script>
<template>
<div class="container-large lg:mt-4">
<div
v-if="competenceStore.competenceProfilePage()"
class="mb-10 flex flex-col justify-between lg:flex-row lg:items-center"
>
<h1>{{ $t("competences.title") }}</h1>
<ItDropdownSelect
v-model="competenceStore.selectedCircle"
class="mt-4 w-full lg:mt-0 lg:w-96"
:items="competenceStore.availableCircles"
></ItDropdownSelect>
</div>
<div class="l mb-4 bg-white px-8 py-4 lg:mb-8 lg:py-8">
<div>
<h3 class="border-b pb-4">{{ $t("competences.lastImprovements") }}</h3>
<ul>
<li
v-for="competence in lastUpdatedCompetences"
:key="competence.id"
class="flex flex-col border-b py-4 last:mb-8 lg:flex-row lg:items-center"
>
<p class="mb-4 inline-block lg:mb-0 lg:mr-5 lg:w-1/4">
{{ competence.competence_id }} {{ competence.title }}
</p>
<ItProgress
:status-count="
competenceStore.calcStatusCount(
competenceStore.criteriaByCompetence(competence)
)
"
></ItProgress>
</li>
</ul>
<router-link
:to="`${
competenceStore.competenceProfilePage()?.frontend_url
}-old/competences`"
class="btn-text inline-flex items-center py-2 pl-0"
>
<span>{{ $t("general.showAll") }}</span>
<it-icon-arrow-right></it-icon-arrow-right>
</router-link>
</div>
</div>
<div class="l mb-4 bg-white px-8 py-4 lg:mb-8 lg:py-8">
<h3 class="mb-4 border-b pb-4 lg:border-0 lg:pb-0">
{{ $t("competences.assessment") }}
</h3>
<ul
class="mb-6 flex flex-col lg:flex-row lg:items-center lg:justify-between lg:gap-8"
>
<li
class="mb-4 inline-block flex-1 border-b pb-4 lg:mb-0 lg:border-b-0 lg:border-r lg:pb-0"
>
<h5 class="mb-4 text-gray-700">«{{ $t("selfEvaluation.no") }}»</h5>
<div class="flex flex-row items-center">
<it-icon-smiley-thinking class="h-16 w-16"></it-icon-smiley-thinking>
<p class="ml-4 inline-block text-7xl font-bold">{{ countStatus.FAIL }}</p>
</div>
</li>
<li
class="mb-4 inline-block flex-1 border-b pb-4 lg:mb-0 lg:border-b-0 lg:border-r lg:pb-0"
>
<h5 class="mb-4 text-gray-700">«{{ $t("selfEvaluation.yes") }}»</h5>
<div class="flex flex-row items-center">
<it-icon-smiley-happy class="h-16 w-16"></it-icon-smiley-happy>
<p class="ml-4 inline-block text-7xl font-bold">
{{ countStatus.SUCCESS }}
</p>
</div>
</li>
<li class="lg:mb-0flex-1 border-b pb-4 lg:border-b-0 lg:pb-0">
<h5 class="mb-4 text-gray-700">{{ $t("competences.notAssessed") }}</h5>
<div class="flex flex-row items-center">
<it-icon-smiley-neutral class="h-16 w-16"></it-icon-smiley-neutral>
<p class="ml-4 inline-block text-7xl font-bold">
{{ countStatus.UNKNOWN }}
</p>
</div>
</li>
</ul>
<router-link
:to="`${competenceStore.competenceProfilePage()?.frontend_url}-old/criteria`"
class="btn-text inline-flex items-center py-2 pl-0"
>
<span>{{ $t("general.showAll") }}</span>
<it-icon-arrow-right></it-icon-arrow-right>
</router-link>
</div>
<div
v-if="failedCriteria.length > 0"
class="l mb-4 bg-white px-8 py-4 lg:mb-8 lg:py-8"
>
<div class="mb-4 flex flex-row items-center border-b pb-4">
<it-icon-smiley-thinking class="mr-5 h-11 w-11"></it-icon-smiley-thinking>
<h3>«{{ $t("selfEvaluation.no") }}»</h3>
</div>
<ul class="mb-6">
<li
v-for="criteria in failedCriteria"
:key="criteria.id"
class="mb-4 border-b pb-4"
>
<PerformanceCriteriaRow
:criteria="criteria"
:course-slug="props.courseSlug"
></PerformanceCriteriaRow>
</li>
</ul>
<router-link
:to="`${competenceStore.competenceProfilePage()?.frontend_url}-old/criteria`"
class="btn-text inline-flex items-center py-2 pl-0"
>
<span>{{ $t("general.showAll") }}</span>
<it-icon-arrow-right></it-icon-arrow-right>
</router-link>
</div>
</div>
</template>
<style scoped></style>

View File

@ -1,34 +0,0 @@
<script setup lang="ts">
import { useCompetenceStore } from "@/stores/competence";
import * as log from "loglevel";
import { onMounted } from "vue";
log.debug("CompetenceParentPage created");
const props = defineProps<{
courseSlug: string;
}>();
const competenceStore = useCompetenceStore();
onMounted(async () => {
log.debug("CompetenceParentPage mounted", props.courseSlug);
try {
const competencePageSlug = props.courseSlug + "-competence";
await competenceStore.loadCompetenceProfilePage(competencePageSlug);
} catch (error) {
log.error(error);
}
});
</script>
<template>
<div class="bg-gray-200">
<main>
<router-view></router-view>
</main>
</div>
</template>
<style scoped></style>

View File

@ -1,122 +0,0 @@
<script setup lang="ts">
import { default as PerformanceCriteriaRow } from "@/pages/competence-old/PerformanceCriteriaRow.vue";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import { useCompetenceStore } from "@/stores/competence";
import type { CourseCompletionStatus } from "@/types";
import * as log from "loglevel";
import type { Ref } from "vue";
import { computed, ref } from "vue";
import { useTranslation } from "i18next-vue";
const props = defineProps<{
courseSlug: string;
}>();
interface MenuItem {
id: CourseCompletionStatus;
name: string;
iconName: string;
}
log.debug("PerformanceCriteriaPage created", props);
const competenceStore = useCompetenceStore();
const shownCriteria = computed(() => {
return competenceStore.flatPerformanceCriteria().filter((criteria) => {
return criteria.completion_status === activeMenuItem.value.id;
});
});
const { t } = useTranslation();
const mobileMenuItems: MenuItem[] = [
{
id: "FAIL",
name: `«${t("selfEvaluation.no")}»`,
iconName: "it-icon-smiley-thinking",
},
{
id: "SUCCESS",
name: `«${t("selfEvaluation.yes")}»`,
iconName: "it-icon-smiley-happy",
},
{
id: "UNKNOWN",
name: t("competences.notAssessed"),
iconName: "it-icon-smiley-neutral",
},
];
const activeMenuItem: Ref<MenuItem> = ref(mobileMenuItems[0]);
function updateActiveState(status: CourseCompletionStatus) {
activeMenuItem.value =
mobileMenuItems.find((item) => status === item.id) || mobileMenuItems[0];
}
</script>
<template>
<div class="container-large">
<nav class="py-4 lg:pb-8">
<router-link
class="btn-text inline-flex items-center pl-0"
:to="`${competenceStore.competenceProfilePage()?.frontend_url}-old`"
>
<it-icon-arrow-left />
<span>{{ $t("general.back") }}</span>
</router-link>
</nav>
<div class="mb-4 flex flex-col items-center justify-between lg:mb-10 lg:flex-row">
<h1>Einschätzungen</h1>
<ItDropdownSelect
v-model="competenceStore.selectedCircle"
class="mt-4 w-full lg:mt-0 lg:w-96"
:items="competenceStore.availableCircles"
></ItDropdownSelect>
<div class="w-full lg:hidden">
<ItDropdownSelect
v-model="activeMenuItem"
class="mt-4 w-full lg:mt-0 lg:w-96"
:items="mobileMenuItems"
></ItDropdownSelect>
</div>
</div>
<div class="bg-white p-8">
<div
class="mb-4 flex hidden flex-col justify-between border-b pb-4 lg:block lg:flex-row lg:items-center"
>
<button
v-for="item in mobileMenuItems"
:key="item.id"
:class="{
'bg-gray-200': activeMenuItem.id === item.id,
'mr-6': item.id !== 'UNKNOWN',
}"
class="mr-6 inline-block px-2 py-4"
@click="updateActiveState(item.id)"
>
<div class="flex flex-row items-center">
<span class="mr-2 inline-block">{{ item.name }}</span>
<component :is="item.iconName"></component>
</div>
</button>
</div>
<ul class="mb-6">
<li
v-for="criteria in shownCriteria"
:key="criteria.id"
class="mb-4 border-b pb-4"
>
<PerformanceCriteriaRow
:criteria="criteria"
:show-state="true"
:course-slug="props.courseSlug"
></PerformanceCriteriaRow>
</li>
</ul>
</div>
</div>
</template>
<style scoped></style>

View File

@ -1,70 +0,0 @@
<script setup lang="ts">
import { useCircleStore } from "@/stores/circle";
import { useCompetenceStore } from "@/stores/competence";
import * as log from "loglevel";
import LearningContentContainer from "@/pages/learningPath/learningContentPage/LearningContentContainer.vue";
import { computed } from "vue";
import { useRouter } from "vue-router";
const props = defineProps<{
courseSlug: string;
criteriaSlug: string;
}>();
log.debug("SinglePerformanceCriteriaPage.vue setup");
const competenceStore = useCompetenceStore();
const circleStore = useCircleStore();
const router = useRouter();
const singleCriteria = computed(() => {
return competenceStore.flatPerformanceCriteria().find((criteria) => {
return criteria.slug === props.criteriaSlug;
});
});
</script>
<template>
<div v-if="singleCriteria" class="absolute bottom-0 top-0 w-full bg-white">
<LearningContentContainer @exit="router.back()">
<div v-if="singleCriteria" class="container-medium">
<div class="mt-4 border p-6 lg:mt-8 lg:p-12">
<h2 class="heading-2">
{{ singleCriteria.competence_id }} {{ singleCriteria.title }}
</h2>
<div class="mt-4 flex flex-col justify-between gap-6 lg:mt-8 lg:flex-row">
<button
class="inline-flex flex-1 items-center border p-4 text-left"
:class="{
'border-green-500': singleCriteria.completion_status === 'SUCCESS',
'border-2': singleCriteria.completion_status === 'SUCCESS',
}"
data-cy="success"
@click="circleStore.markCompletion(singleCriteria, 'SUCCESS')"
>
<it-icon-smiley-happy class="mr-4 h-16 w-16"></it-icon-smiley-happy>
<span class="text-large font-bold">{{ $t("selfEvaluation.yes") }}</span>
</button>
<button
class="inline-flex flex-1 items-center border p-4 text-left"
:class="{
'border-orange-500': singleCriteria.completion_status === 'FAIL',
'border-2': singleCriteria.completion_status === 'FAIL',
}"
data-cy="fail"
@click="circleStore.markCompletion(singleCriteria, 'FAIL')"
>
<it-icon-smiley-thinking class="mr-4 h-16 w-16"></it-icon-smiley-thinking>
<span class="text-xl font-bold">{{ $t("selfEvaluation.no") }}</span>
</button>
</div>
</div>
</div>
</LearningContentContainer>
</div>
</template>
<style scoped></style>

View File

@ -1,11 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import PerformanceCriteriaRow from "@/pages/competence-old/PerformanceCriteriaRow.vue";
import ItProgress from "@/components/ui/ItProgress.vue";
import ItToggleArrow from "@/components/ui/ItToggleArrow.vue"; import ItToggleArrow from "@/components/ui/ItToggleArrow.vue";
import { useCompetenceStore } from "@/stores/competence"; import { useCompetenceStore } from "@/stores/competence";
import type { CompetencePage } from "@/types"; import type { CompetencePage } from "@/types";
import log from "loglevel"; import log from "loglevel";
import { ref } from "vue"; import { ref, watch } from "vue";
import SinglePerformanceCriteriaRow from "@/pages/competence/SinglePerformanceCriteriaRow.vue";
const competenceStore = useCompetenceStore(); const competenceStore = useCompetenceStore();
@ -14,17 +13,26 @@ interface Props {
courseSlug: string; courseSlug: string;
showAssessAgain?: boolean; showAssessAgain?: boolean;
isInline?: boolean; isInline?: boolean;
allOpen?: boolean;
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
showAssessAgain: true, showAssessAgain: true,
isInline: false, isInline: false,
allOpen: false,
}); });
log.debug("PerformanceCriteriaRow created", props); log.debug("PerformanceCriteriaRow created", props);
const isOpen = ref(false); const isOpen = ref(false);
watch(
() => props.allOpen,
(newValue) => {
isOpen.value = newValue;
}
);
const togglePerformanceCriteria = () => { const togglePerformanceCriteria = () => {
isOpen.value = !isOpen.value; isOpen.value = !isOpen.value;
}; };
@ -32,7 +40,7 @@ const togglePerformanceCriteria = () => {
<template> <template>
<div> <div>
<div :class="{ 'mb-4 border-b pb-8': isOpen }" class="-mx-8 px-8"> <div class="-mx-8 border-b px-8">
<div <div
class="flex flex-row items-center justify-between" class="flex flex-row items-center justify-between"
:class="props.isInline ? '' : 'mb-4'" :class="props.isInline ? '' : 'mb-4'"
@ -41,40 +49,27 @@ const togglePerformanceCriteria = () => {
@click="togglePerformanceCriteria()" @click="togglePerformanceCriteria()"
> >
<h2 :class="props.isInline ? ['text-bold', 'w-2/5'] : 'text-large'"> <h2 :class="props.isInline ? ['text-bold', 'w-2/5'] : 'text-large'">
{{ competence.competence_id }} {{ competence.title }} {{ competence.title }} ({{ competence.competence_id }})
</h2> </h2>
<ItProgress
v-if="isInline"
class="w-[330px]"
:status-count="
competenceStore.calcStatusCount(
competenceStore.criteriaByCompetence(competence)
)
"
></ItProgress>
<ItToggleArrow :is-open="isOpen" :small="isInline"></ItToggleArrow> <ItToggleArrow :is-open="isOpen" :small="isInline"></ItToggleArrow>
</div> </div>
<ItProgress
v-if="!isInline"
:status-count="
competenceStore.calcStatusCount(
competenceStore.criteriaByCompetence(competence)
)
"
></ItProgress>
</div> </div>
<ul v-if="isOpen"> <ul v-if="isOpen">
<li class="my-4 border-b pb-4 font-bold">
{{ $t("a.Leistungsziele") }}
</li>
<li <li
v-for="performanceCriteria in competenceStore.criteriaByCompetence(competence)" v-for="performanceCriteria in competenceStore.criteriaByCompetence(competence)"
:key="performanceCriteria.id" :key="performanceCriteria.id"
class="mb-4 border-b pb-4 last:border-0" class="my-4 border-b pb-4 last:border-0"
> >
<PerformanceCriteriaRow <SinglePerformanceCriteriaRow
:criteria="performanceCriteria" :criteria="performanceCriteria"
:show-state="true" :show-state="false"
:course-slug="props.courseSlug" :course-slug="props.courseSlug"
:show-assess-again="props.showAssessAgain" :show-assess-again="props.showAssessAgain"
></PerformanceCriteriaRow> ></SinglePerformanceCriteriaRow>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -2,6 +2,7 @@
import CompetenceDetail from "@/pages/competence/ActionCompetenceDetail.vue"; import CompetenceDetail from "@/pages/competence/ActionCompetenceDetail.vue";
import { useCompetenceStore } from "@/stores/competence"; import { useCompetenceStore } from "@/stores/competence";
import * as log from "loglevel"; import * as log from "loglevel";
import { ref } from "vue";
log.debug("CompetenceListPage created"); log.debug("CompetenceListPage created");
@ -10,21 +11,45 @@ const props = defineProps<{
}>(); }>();
const competenceStore = useCompetenceStore(); const competenceStore = useCompetenceStore();
const isOpenAll = ref(false);
function toggleOpen() {
log.debug("toggleOpen");
isOpenAll.value = !isOpenAll.value;
}
</script> </script>
<template> <template>
<div class="container-large"> <div class="container-large">
<h2 class="mb-4 lg:py-4">{{ $t("a.Handlungskompetenzen") }}</h2> <h2 class="py-4">{{ $t("a.Handlungskompetenzen") }}</h2>
<div class="flex justify-between py-8">
<div class="w-3/4 text-xl">
{{ $t("competence.listPageDescription") }}
</div>
<div class="whitespace-nowrap">
<button class="link" @click="toggleOpen()">
<span v-if="isOpenAll">
{{ $t("a.Alle zuklappen") }}
</span>
<span v-else>
{{ $t("a.Alle aufklappen") }}
</span>
</button>
</div>
</div>
<ul v-if="competenceStore.competenceProfilePage()"> <ul v-if="competenceStore.competenceProfilePage()">
<li <li
v-for="competence in competenceStore.competences()" v-for="competence in competenceStore.competences()"
:key="competence.id" :key="competence.id"
class="mb-8 bg-white p-8" class="mb-8 bg-white px-8 pt-6"
> >
<CompetenceDetail <CompetenceDetail
:competence="competence" :competence="competence"
:course-slug="props.courseSlug" :course-slug="props.courseSlug"
:all-open="isOpenAll"
></CompetenceDetail> ></CompetenceDetail>
</li> </li>
</ul> </ul>

View File

@ -26,31 +26,17 @@ const props = withDefaults(defineProps<Props>(), {
></it-icon-smiley-thinking> ></it-icon-smiley-thinking>
<it-icon-smiley-neutral v-else></it-icon-smiley-neutral> <it-icon-smiley-neutral v-else></it-icon-smiley-neutral>
</div> </div>
<div class="mb-4 pr-5 lg:mb-0 lg:mr-10"> <div class="mb-4 pr-4 lg:mb-0 lg:mr-8">
<h4 class="text-bold mb-2"> {{ criteria.title }}
{{ criteria.competence_id }} {{ criteria.title }}
</h4>
<p class="hidden lg:block">
{{ $t("general.learningUnit") }}:
<router-link class="link" :to="criteria.learning_unit.frontend_url">
{{ criteria.learning_unit.title }}
</router-link>
</p>
</div> </div>
</div> </div>
<p class="mb-2 lg:hidden">
{{ $t("general.learningUnit") }}:
<router-link class="link" :to="criteria.learning_unit.frontend_url">
{{ criteria.learning_unit.title }}
</router-link>
</p>
<span class="whitespace-nowrap"> <span class="whitespace-nowrap">
<router-link <router-link
v-if="props.showAssessAgain" v-if="props.showAssessAgain"
class="link" class="link"
:to="`/course/${props.courseSlug}/competence-old/criteria/${criteria.slug}`" :to="criteria.learning_unit.evaluate_url"
> >
{{ $t("competences.assessAgain") }} {{ $t("competences.assessAgain", { x: criteria.circle.title }) }}
</router-link> </router-link>
</span> </span>
</div> </div>

View File

@ -16,6 +16,7 @@ import MediaLibraryBlock from "./blocks/MediaLibraryBlock.vue";
import PlaceholderBlock from "./blocks/PlaceholderBlock.vue"; import PlaceholderBlock from "./blocks/PlaceholderBlock.vue";
import RichTextBlock from "./blocks/RichTextBlock.vue"; import RichTextBlock from "./blocks/RichTextBlock.vue";
import VideoBlock from "./blocks/VideoBlock.vue"; import VideoBlock from "./blocks/VideoBlock.vue";
import { getPreviousRoute } from "@/router/history";
const circleStore = useCircleStore(); const circleStore = useCircleStore();
@ -25,6 +26,8 @@ const props = defineProps<{
log.debug("LearningContentParent setup", props.learningContent); log.debug("LearningContentParent setup", props.learningContent);
const previousRoute = getPreviousRoute();
// can't use the type as component name, as some are reserved HTML components, e.g. video // can't use the type as component name, as some are reserved HTML components, e.g. video
const COMPONENTS: Record<LearningContentType, Component> = { const COMPONENTS: Record<LearningContentType, Component> = {
"learnpath.LearningContentAssignment": AssignmentBlock, "learnpath.LearningContentAssignment": AssignmentBlock,
@ -45,7 +48,7 @@ const component = computed(() => {
}); });
function handleFinishedLearningContent() { function handleFinishedLearningContent() {
circleStore.continueFromLearningContent(props.learningContent); circleStore.continueFromLearningContent(props.learningContent, previousRoute);
} }
eventBus.on("finishedLearningContent", handleFinishedLearningContent); eventBus.on("finishedLearningContent", handleFinishedLearningContent);
@ -57,7 +60,7 @@ onUnmounted(() => {
<template> <template>
<LearningContentContainer <LearningContentContainer
@exit="circleStore.closeLearningContent(props.learningContent)" @exit="circleStore.closeLearningContent(props.learningContent, previousRoute)"
> >
<div> <div>
<component :is="component" :content="learningContent"></component> <component :is="component" :content="learningContent"></component>

View File

@ -10,6 +10,7 @@ import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage
import eventBus from "@/utils/eventBus"; import eventBus from "@/utils/eventBus";
import { useRouteQuery } from "@vueuse/router"; import { useRouteQuery } from "@vueuse/router";
import { computed, onUnmounted } from "vue"; import { computed, onUnmounted } from "vue";
import { getPreviousRoute } from "@/router/history";
log.debug("LearningContent.vue setup"); log.debug("LearningContent.vue setup");
@ -18,6 +19,8 @@ const courseSession = useCurrentCourseSession();
const questionIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" }); const questionIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" });
const previousRoute = getPreviousRoute();
const props = defineProps<{ const props = defineProps<{
learningUnit: LearningUnit; learningUnit: LearningUnit;
}>(); }>();
@ -52,7 +55,7 @@ function handleBack() {
} }
function handleFinishedLearningContent() { function handleFinishedLearningContent() {
circleStore.closeSelfEvaluation(props.learningUnit); circleStore.closeSelfEvaluation(props.learningUnit, previousRoute);
} }
eventBus.on("finishedLearningContent", handleFinishedLearningContent); eventBus.on("finishedLearningContent", handleFinishedLearningContent);
@ -65,7 +68,7 @@ onUnmounted(() => {
<template> <template>
<div v-if="learningUnit"> <div v-if="learningUnit">
<LearningContentContainer <LearningContentContainer
@exit="circleStore.closeSelfEvaluation(props.learningUnit)" @exit="circleStore.closeSelfEvaluation(props.learningUnit, previousRoute)"
> >
<LearningContentMultiLayout <LearningContentMultiLayout
:current-step="questionIndex" :current-step="questionIndex"

View File

@ -23,9 +23,16 @@ export const addToHistory: NavigationGuard = (to, from, next) => {
next(); next();
}; };
export function getPreviousRoute() {
if (routeHistory.length > 0) {
return routeHistory[routeHistory.length - 1];
}
return undefined;
}
export function routerBackOrFallback(router: Router, fallbackRoute: RouteLocationRaw) { export function routerBackOrFallback(router: Router, fallbackRoute: RouteLocationRaw) {
// Check the latest route in history // Check the latest route in history
const previousRoute = routeHistory[routeHistory.length - 1]; const previousRoute = getPreviousRoute();
if (previousRoute) { if (previousRoute) {
router.back(); router.back();
} else { } else {

View File

@ -97,35 +97,6 @@ const router = createRouter({
}, },
], ],
}, },
{
path: "/course/:courseSlug/competence-old",
props: true,
component: () => import("@/pages/competence-old/CompetenceParentPage.vue"),
children: [
{
path: "",
props: true,
component: () => import("@/pages/competence-old/CompetenceIndexPage.vue"),
},
{
path: "competences",
props: true,
component: () => import("@/pages/competence/ActionCompetenceListPage.vue"),
},
{
path: "criteria",
props: true,
component: () => import("@/pages/competence-old/PerformanceCriteriaPage.vue"),
},
{
path: "criteria/:criteriaSlug",
props: true,
component: () =>
import("@/pages/competence-old/SinglePerformanceCriteriaPage.vue"),
},
],
},
{ {
path: "/course/:courseSlug/learn", path: "/course/:courseSlug/learn",
component: () => component: () =>

View File

@ -1,4 +1,3 @@
import { routerBackOrFallback } from "@/router/history";
import type { Circle } from "@/services/circle"; import type { Circle } from "@/services/circle";
import { useCompletionStore } from "@/stores/completion"; import { useCompletionStore } from "@/stores/completion";
import { useLearningPathStore } from "@/stores/learningPath"; import { useLearningPathStore } from "@/stores/learningPath";
@ -12,6 +11,7 @@ import type {
} from "@/types"; } from "@/types";
import * as log from "loglevel"; import * as log from "loglevel";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import type { RouteLocationNormalized } from "vue-router";
export type CircleStoreState = { export type CircleStoreState = {
circle: Circle | undefined; circle: Circle | undefined;
@ -127,22 +127,36 @@ export const useCircleStore = defineStore({
path: learningContent.frontend_url, path: learningContent.frontend_url,
}); });
}, },
closeLearningContent(learningContent: LearningContentInterface) { closeLearningContent(
routerBackOrFallback(this.router, { learningContent: LearningContentInterface,
path: `${this.circle?.frontend_url}`, returnRoute?: RouteLocationNormalized
hash: createLearningUnitHash(learningContent.parentLearningUnit), ) {
}); if (returnRoute) {
this.router.push(returnRoute);
} else {
this.router.push({
path: `${this.circle?.frontend_url}`,
hash: createLearningUnitHash(learningContent.parentLearningUnit),
});
}
}, },
openSelfEvaluation(learningUnit: LearningUnit) { openSelfEvaluation(learningUnit: LearningUnit) {
this.router.push({ this.router.push({
path: learningUnit.evaluate_url, path: learningUnit.evaluate_url,
}); });
}, },
closeSelfEvaluation(learningUnit: LearningUnit) { closeSelfEvaluation(
routerBackOrFallback(this.router, { learningUnit: LearningUnit,
path: `${this.circle?.frontend_url}`, returnRoute?: RouteLocationNormalized
hash: createLearningUnitHash(learningUnit), ) {
}); if (returnRoute) {
this.router.push(returnRoute);
} else {
this.router.push({
path: `${this.circle?.frontend_url}`,
hash: createLearningUnitHash(learningUnit),
});
}
}, },
calcSelfEvaluationStatus(learningUnit: LearningUnit): CourseCompletionStatus { calcSelfEvaluationStatus(learningUnit: LearningUnit): CourseCompletionStatus {
if (learningUnit.children.length > 0) { if (learningUnit.children.length > 0) {
@ -159,7 +173,10 @@ export const useCircleStore = defineStore({
} }
return "UNKNOWN"; return "UNKNOWN";
}, },
continueFromLearningContent(currentLearningContent: LearningContentInterface) { continueFromLearningContent(
currentLearningContent: LearningContentInterface,
returnRoute?: RouteLocationNormalized
) {
if (currentLearningContent) { if (currentLearningContent) {
if (currentLearningContent.can_user_self_toggle_course_completion) { if (currentLearningContent.can_user_self_toggle_course_completion) {
this.markCompletion(currentLearningContent, "SUCCESS"); this.markCompletion(currentLearningContent, "SUCCESS");
@ -167,7 +184,7 @@ export const useCircleStore = defineStore({
// reload completion data anyway // reload completion data anyway
currentLearningContent.parentCircle?.parentLearningPath?.reloadCompletionData(); currentLearningContent.parentCircle?.parentLearningPath?.reloadCompletionData();
} }
this.closeLearningContent(currentLearningContent); this.closeLearningContent(currentLearningContent, returnRoute);
} else { } else {
log.error("currentLearningContent is undefined"); log.error("currentLearningContent is undefined");
} }