Use sub routes

This commit is contained in:
Christian Cueni 2024-04-22 20:08:37 +02:00
parent 073c2a8a60
commit 0d982f937c
5 changed files with 178 additions and 173 deletions

View File

@ -28,104 +28,106 @@ const isLoaded = computed(() => !selfEvaluationFeedbackSummaries.loading.value);
</script> </script>
<template> <template>
<template v-if="isLoaded"> <div>
<!-- Self Evaluation --> <template v-if="isLoaded">
<div class="bg-white px-8 py-4 lg:mb-8 lg:py-8"> <!-- Self Evaluation -->
<div class="mb-8"> <div class="bg-white px-8 py-4 lg:mb-8 lg:py-8">
<h3 class="mb-4 pb-4 lg:pb-0"> <div class="mb-8">
{{ $t("a.Selbsteinschätzungen") }} <h3 class="mb-4 pb-4 lg:pb-0">
</h3> {{ $t("a.Selbsteinschätzungen") }}
<ul </h3>
class="mb-6 flex flex-col lg:flex-row lg:items-center lg:justify-between lg:gap-8" <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 pb-4 lg:mb-0 lg:w-1/3 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"
data-cy="self-evaluation-fail"
>
{{ selfAssessmentCounts?.fail }}
</p>
</div>
</li>
<li class="mb-4 inline-block flex-1 pb-4 lg:mb-0 lg:w-1/3 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"
data-cy="self-evaluation-success"
>
{{ selfAssessmentCounts?.pass }}
</p>
</div>
</li>
<li class="flex-1 pb-4 lg:mb-0 lg:w-1/3 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"
data-cy="self-evaluation-unknown"
>
{{ selfAssessmentCounts?.unknown }}
</p>
</div>
</li>
</ul>
</div>
<!-- Feedback Evaluation -->
<div
v-if="courseSession.course.configuration.enable_learning_mentor"
class="border-t pt-8"
> >
<li class="mb-4 inline-block flex-1 pb-4 lg:mb-0 lg:w-1/3 lg:pb-0"> <h3 class="mb-4 pb-4 lg:pb-0">
<h5 class="mb-4 text-gray-700">«{{ $t("selfEvaluation.no") }}»</h5> {{ $t("a.Fremdeinschätzungen") }}
<div class="flex flex-row items-center"> </h3>
<it-icon-smiley-thinking class="h-16 w-16"></it-icon-smiley-thinking> <ul
<p class="mb-6 flex flex-col lg:flex-row lg:items-center lg:justify-between lg:gap-8"
class="ml-4 inline-block text-7xl font-bold" >
data-cy="self-evaluation-fail" <li class="mb-4 inline-block flex-1 pb-4 lg:mb-0 lg:w-1/3 lg:pb-0">
> <h5 class="mb-4 text-gray-700">«{{ $t("receivedEvaluation.no") }}»</h5>
{{ selfAssessmentCounts?.fail }} <div class="flex flex-row items-center">
</p> <it-icon-smiley-thinking class="h-16 w-16"></it-icon-smiley-thinking>
</div> <p class="ml-4 inline-block text-7xl font-bold">
</li> {{ feedbackEvaluationCounts?.fail }}
<li class="mb-4 inline-block flex-1 pb-4 lg:mb-0 lg:w-1/3 lg:pb-0"> </p>
<h5 class="mb-4 text-gray-700">«{{ $t("selfEvaluation.yes") }}»</h5> </div>
<div class="flex flex-row items-center"> </li>
<it-icon-smiley-happy class="h-16 w-16"></it-icon-smiley-happy> <li class="mb-4 inline-block flex-1 pb-4 lg:mb-0 lg:w-1/3 lg:pb-0">
<p <h5 class="mb-4 text-gray-700">«{{ $t("receivedEvaluation.yes") }}»</h5>
class="ml-4 inline-block text-7xl font-bold" <div class="flex flex-row items-center">
data-cy="self-evaluation-success" <it-icon-smiley-happy class="h-16 w-16"></it-icon-smiley-happy>
> <p class="ml-4 inline-block text-7xl font-bold">
{{ selfAssessmentCounts?.pass }} {{ feedbackEvaluationCounts?.pass }}
</p> </p>
</div> </div>
</li> </li>
<li class="flex-1 pb-4 lg:mb-0 lg:w-1/3 lg:pb-0"> <li class="flex-1 pb-4 lg:mb-0 lg:w-1/3 lg:pb-0">
<h5 class="mb-4 text-gray-700">{{ $t("competences.notAssessed") }}</h5> <h5 class="mb-4 text-gray-700">{{ $t("competences.notAssessed") }}</h5>
<div class="flex flex-row items-center"> <div class="flex flex-row items-center">
<it-icon-smiley-neutral class="h-16 w-16"></it-icon-smiley-neutral> <it-icon-smiley-neutral class="h-16 w-16"></it-icon-smiley-neutral>
<p <p class="ml-4 inline-block text-7xl font-bold">
class="ml-4 inline-block text-7xl font-bold" {{ feedbackEvaluationCounts?.unknown }}
data-cy="self-evaluation-unknown" </p>
> </div>
{{ selfAssessmentCounts?.unknown }} </li>
</p> </ul>
</div> </div>
</li> <!-- Show All (always)-->
</ul> <button
</div> class="btn-text inline-flex items-center py-2 pl-0 pt-8"
<!-- Feedback Evaluation --> @click="emit('showAll')"
<div
v-if="courseSession.course.configuration.enable_learning_mentor"
class="border-t pt-8"
>
<h3 class="mb-4 pb-4 lg:pb-0">
{{ $t("a.Fremdeinschätzungen") }}
</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 pb-4 lg:mb-0 lg:w-1/3 lg:pb-0"> <span>{{ $t("general.showAll") }}</span>
<h5 class="mb-4 text-gray-700">«{{ $t("receivedEvaluation.no") }}»</h5> <it-icon-arrow-right></it-icon-arrow-right>
<div class="flex flex-row items-center"> </button>
<it-icon-smiley-thinking class="h-16 w-16"></it-icon-smiley-thinking>
<p class="ml-4 inline-block text-7xl font-bold">
{{ feedbackEvaluationCounts?.fail }}
</p>
</div>
</li>
<li class="mb-4 inline-block flex-1 pb-4 lg:mb-0 lg:w-1/3 lg:pb-0">
<h5 class="mb-4 text-gray-700">«{{ $t("receivedEvaluation.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">
{{ feedbackEvaluationCounts?.pass }}
</p>
</div>
</li>
<li class="flex-1 pb-4 lg:mb-0 lg:w-1/3 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">
{{ feedbackEvaluationCounts?.unknown }}
</p>
</div>
</li>
</ul>
</div> </div>
<!-- Show All (always)--> </template>
<button </div>
class="btn-text inline-flex items-center py-2 pl-0 pt-8"
@click="emit('showAll')"
>
<span>{{ $t("general.showAll") }}</span>
<it-icon-arrow-right></it-icon-arrow-right>
</button>
</div>
</template>
</template> </template>
<style scoped></style> <style scoped></style>

View File

@ -1,6 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import log from "loglevel"; import log from "loglevel";
import { COMPETENCE_NAVI_CERTIFICATE_QUERY } from "@/graphql/queries"; import {
COMPETENCE_NAVI_CERTIFICATE_FOR_USER_QUERY,
COMPETENCE_NAVI_CERTIFICATE_QUERY,
} from "@/graphql/queries";
import { useQuery } from "@urql/vue"; import { useQuery } from "@urql/vue";
import { computed, onMounted } from "vue"; import { computed, onMounted } from "vue";
import type { CompetenceCertificate } from "@/types"; import type { CompetenceCertificate } from "@/types";
@ -10,25 +13,44 @@ import CompetenceCertificateComponent from "@/pages/competence/CompetenceCertifi
const props = defineProps<{ const props = defineProps<{
courseSlug: string; courseSlug: string;
certificateSlug: string; certificateSlug: string;
userId?: string;
}>(); }>();
log.debug("CompetenceCertificateDetailPage setup", props); log.debug("CompetenceCertificateDetailPage setup", props);
const courseSession = useCurrentCourseSession(); const courseSession = useCurrentCourseSession();
const certificatesQuery = useQuery({ const certificatesQuery = (() => {
query: COMPETENCE_NAVI_CERTIFICATE_QUERY, if (props.userId) {
variables: { return useQuery({
courseSlug: props.courseSlug, query: COMPETENCE_NAVI_CERTIFICATE_FOR_USER_QUERY,
courseSessionId: courseSession.value.id, variables: {
}, courseSlug: props.courseSlug,
}); courseSessionId: courseSession.value.id,
userId: props.userId,
},
});
} else {
return useQuery({
query: COMPETENCE_NAVI_CERTIFICATE_QUERY,
variables: {
courseSlug: props.courseSlug,
courseSessionId: courseSession.value.id,
},
});
}
})();
const certificate = computed(() => { const certificate = computed(() => {
return ( const certificate = props.userId
(certificatesQuery.data.value?.competence_certificate_list ? certificatesQuery.data?.value?.competence_certificate_list_for_user
?.competence_certificates as unknown as CompetenceCertificate[]) ?? [] : certificatesQuery.data?.value?.competence_certificate_list;
).find((cc) => cc.slug.endsWith(props.certificateSlug)); if (certificate) {
return (
(certificate.competence_certificates as unknown as CompetenceCertificate[]) ?? []
).find((cc) => cc.slug.endsWith(props.certificateSlug));
}
return null;
}); });
onMounted(async () => { onMounted(async () => {

View File

@ -1,21 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import CockpitProfileContent from "@/components/userProfile/UserProfileContent.vue"; import CockpitProfileContent from "@/components/userProfile/UserProfileContent.vue";
import { computed } from "vue";
import SelfEvaluationAndFeedbackList from "@/components/selfEvaluationFeedback/SelfEvaluationAndFeedbackList.vue";
import SelfEvaluationAndFeedbackOverview from "@/components/selfEvaluationFeedback/SelfEvaluationAndFeedbackOverview.vue";
import { useCurrentCourseSession } from "@/composables"; import { useCurrentCourseSession } from "@/composables";
import CompetenceCertificateListPage from "@/pages/competence/CompetenceCertificateListPage.vue";
import CompetenceCertificateDetailPage from "@/pages/competence/CompetenceCertificateDetailPage.vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
type SubMenuType = "OVERVIEW" | "EVALUATIONS" | "CERTIFICATES" | "CERTIFICATE_DETAIL";
const subMenuOptions: SubMenuType[] = [
"OVERVIEW",
"EVALUATIONS",
"CERTIFICATES",
"CERTIFICATE_DETAIL",
];
const props = defineProps<{ const props = defineProps<{
userId: string; userId: string;
courseSlug: string; courseSlug: string;
@ -23,56 +10,47 @@ const props = defineProps<{
}>(); }>();
interface SubMenuItem { interface SubMenuItem {
type: SubMenuType;
label: string; label: string;
url: string; url: string;
inMenu: boolean; inMenu: boolean;
routeMatch: string[];
} }
const SUBPAGES: SubMenuItem[] = [ const SUBPAGES: SubMenuItem[] = [
{ {
type: "OVERVIEW",
label: "a.Übersicht", label: "a.Übersicht",
url: `/course/${props.courseSlug}/profile/${props.userId}/competence`, url: `/course/${props.courseSlug}/profile/${props.userId}/competence`,
inMenu: true, inMenu: true,
routeMatch: ["competenceMain"],
}, },
{ {
type: "EVALUATIONS",
label: useCurrentCourseSession().value.course.configuration.is_vv label: useCurrentCourseSession().value.course.configuration.is_vv
? "a.Selbst- und Fremdeinschätzungen" ? "a.Selbst- und Fremdeinschätzungen"
: "a.Selbsteinschätzungen", : "a.Selbsteinschätzungen",
url: `/course/${props.courseSlug}/profile/${props.userId}/competence/evaluations`, url: `/course/${props.courseSlug}/profile/${props.userId}/competence/evaluations`,
inMenu: true, inMenu: true,
routeMatch: ["competenceEvaluations"],
}, },
]; ];
if (useCurrentCourseSession().value.course.configuration.is_uk) { if (useCurrentCourseSession().value.course.configuration.is_uk) {
SUBPAGES.push( SUBPAGES.push(
{ {
type: "CERTIFICATES",
label: "Kompetenznachweise", label: "Kompetenznachweise",
url: `/course/${props.courseSlug}/profile/${props.userId}/competence/certificates`, url: `/course/${props.courseSlug}/profile/${props.userId}/competence/certificates`,
inMenu: true, inMenu: true,
routeMatch: ["competenceCertificates", "competenceCertificateDetail"],
}, },
{ {
type: "CERTIFICATE_DETAIL",
label: "", label: "",
url: "", url: "",
inMenu: false, inMenu: false,
routeMatch: [],
} }
); );
} }
const route = useRoute(); const route = useRoute();
const active = computed(() => {
const index = subMenuOptions.findIndex((option) =>
option.startsWith(route.meta?.subpage)
);
if (index > -1) {
return SUBPAGES[index];
}
return SUBPAGES[0];
});
</script> </script>
<template> <template>
@ -84,37 +62,26 @@ const active = computed(() => {
class="mb-2" class="mb-2"
> >
<router-link <router-link
v-if="active"
:to="entry.url" :to="entry.url"
class="flex w-full items-center space-x-2 p-2 pr-4 text-blue-900 hover:bg-gray-200 lg:pr-8" class="flex w-full items-center space-x-2 p-2 pr-4 text-blue-900 hover:bg-gray-200 lg:pr-8"
:class="{ 'text-bold bg-gray-200': entry.type.startsWith(active.type) }" :class="{
'text-bold bg-gray-200': route.matched.some((record) =>
entry.routeMatch.includes(record.name)
),
}"
> >
<span>{{ $t(entry.label) }}</span> <span>{{ $t(entry.label) }}</span>
</router-link> </router-link>
</div> </div>
</template> </template>
<template #main> <template #main>
<div v-if="active" class="container-large"> <div class="container-large">
<SelfEvaluationAndFeedbackOverview <router-view
v-if="active.type === 'OVERVIEW'"
:profile-user-id="props.userId" :profile-user-id="props.userId"
/> :user-id="props.userId"
<SelfEvaluationAndFeedbackList
v-else-if="active.type === 'EVALUATIONS'"
class="w-full"
:profile-user-id="props.userId"
/>
<CompetenceCertificateListPage
v-else-if="active.type === 'CERTIFICATES'"
:course-slug="useCurrentCourseSession().value.course.slug"
:user-id="userId"
/>
<CompetenceCertificateDetailPage
v-else-if="active.type === 'CERTIFICATE_DETAIL'"
:course-slug="useCurrentCourseSession().value.course.slug" :course-slug="useCurrentCourseSession().value.course.slug"
:certificate-slug="certificateSlug ? certificateSlug : ''" :certificate-slug="certificateSlug ? certificateSlug : ''"
:user-id="userId" ></router-view>
/>
</div> </div>
</template> </template>
</CockpitProfileContent> </CockpitProfileContent>

View File

@ -13,8 +13,16 @@ const props = defineProps<{
const { t } = useTranslation(); const { t } = useTranslation();
const pages = ref([ const pages = ref([
{ label: t("general.learningPath"), route: "profileLearningPath" }, {
{ label: t("a.KompetenzNavi"), route: "profileCompetence" }, label: t("general.learningPath"),
route: "profileLearningPath",
routeMatch: "profileLearningPath",
},
{
label: t("a.KompetenzNavi"),
route: "competenceMain",
routeMatch: "profileCompetence",
},
]); ]);
const courseSession = useCurrentCourseSession(); const courseSession = useCurrentCourseSession();
@ -54,7 +62,11 @@ onMounted(() => {
v-for="page in pages" v-for="page in pages"
:key="page.route" :key="page.route"
class="relative top-px mr-12 pb-3" class="relative top-px mr-12 pb-3"
:class="[route.name === page.route ? 'border-b-2 border-blue-900 pb-3' : '']" :class="[
route.matched.some((record) => record.name === page.routeMatch)
? 'border-b-2 border-blue-900 pb-3'
: '',
]"
> >
<router-link :to="{ name: page.route }"> <router-link :to="{ name: page.route }">
{{ page.label }} {{ page.label }}

View File

@ -178,29 +178,31 @@ const router = createRouter({
{ {
path: "", path: "",
name: "competenceMain", name: "competenceMain",
meta: { subpage: "OVERVIEW" }, component: () =>
component: () => import("@/pages/userProfile/CompetenceProfilePage.vue"), import(
"@/components/selfEvaluationFeedback/SelfEvaluationAndFeedbackOverview.vue"
),
}, },
{ {
path: "evaluations", path: "evaluations",
name: "competenceEvaluations", name: "competenceEvaluations",
meta: { subpage: "EVALUATIONS" }, component: () =>
component: () => import("@/pages/userProfile/CompetenceProfilePage.vue"), import(
"@/components/selfEvaluationFeedback/SelfEvaluationAndFeedbackList.vue"
),
},
{
path: "certificates/:certificateSlug",
name: "competenceCertificateDetail",
props: true,
component: () =>
import("@/pages/competence/CompetenceCertificateDetailPage.vue"),
}, },
{ {
path: "certificates", path: "certificates",
name: "profileCompetences", name: "competenceCertificates",
meta: { subpage: "CERTIFICATES" }, component: () =>
component: () => import("@/pages/userProfile/CompetenceProfilePage.vue"), import("@/pages/competence/CompetenceCertificateListPage.vue"),
children: [
{
path: ":certificateSlug",
props: true,
meta: { subpage: "CERTIFICATE_DETAIL" },
component: () =>
import("@/pages/userProfile/CompetenceProfilePage.vue"),
},
],
}, },
], ],
}, },