wip: Add user certificate query, modify components

This commit is contained in:
Christian Cueni 2024-04-22 15:49:31 +02:00
parent 2318135f50
commit 073c2a8a60
10 changed files with 255 additions and 29 deletions

View File

@ -19,6 +19,7 @@ const documents = {
"\n query attendanceCheckQuery($courseSessionId: ID!) {\n course_session_attendance_course(id: $courseSessionId) {\n id\n attendance_user_list {\n user_id\n status\n }\n }\n }\n": types.AttendanceCheckQueryDocument, "\n query attendanceCheckQuery($courseSessionId: ID!) {\n course_session_attendance_course(id: $courseSessionId) {\n id\n attendance_user_list {\n user_id\n status\n }\n }\n }\n": types.AttendanceCheckQueryDocument,
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n needs_expert_evaluation\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n solution_sample {\n id\n url\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n first_name\n last_name\n }\n assignment_user {\n avatar_url\n first_name\n last_name\n id\n }\n evaluation_points\n evaluation_max_points\n evaluation_passed\n edoniq_extended_time_flag\n completion_data\n task_completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument, "\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n needs_expert_evaluation\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n solution_sample {\n id\n url\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n first_name\n last_name\n }\n assignment_user {\n avatar_url\n first_name\n last_name\n id\n }\n evaluation_points\n evaluation_max_points\n evaluation_passed\n edoniq_extended_time_flag\n completion_data\n task_completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
"\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument, "\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument,
"\n query competenceCertificateForUserQuery(\n $courseSlug: String!\n $courseSessionId: ID!\n $userId: UUID!\n ) {\n competence_certificate_list_for_user(course_slug: $courseSlug, user_id: $userId) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateForUserQueryDocument,
"\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n configuration {\n id\n enable_circle_documents\n enable_learning_mentor\n enable_competence_certificates\n }\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n": types.CourseSessionDetailDocument, "\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n configuration {\n id\n enable_circle_documents\n enable_learning_mentor\n enable_competence_certificates\n }\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n": types.CourseSessionDetailDocument,
"\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n configuration {\n id\n enable_circle_documents\n enable_learning_mentor\n enable_competence_certificates\n is_uk\n }\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.CourseQueryDocument, "\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n configuration {\n id\n enable_circle_documents\n enable_learning_mentor\n enable_competence_certificates\n is_uk\n }\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.CourseQueryDocument,
"\n query dashboardConfig {\n dashboard_config {\n id\n slug\n name\n dashboard_type\n course_configuration {\n id\n enable_circle_documents\n enable_learning_mentor\n enable_competence_certificates\n is_uk\n }\n }\n }\n": types.DashboardConfigDocument, "\n query dashboardConfig {\n dashboard_config {\n id\n slug\n name\n dashboard_type\n course_configuration {\n id\n enable_circle_documents\n enable_learning_mentor\n enable_competence_certificates\n is_uk\n }\n }\n }\n": types.DashboardConfigDocument,
@ -67,6 +68,10 @@ export function graphql(source: "\n query assignmentCompletionQuery(\n $assi
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql(source: "\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n"]; export function graphql(source: "\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query competenceCertificateForUserQuery(\n $courseSlug: String!\n $courseSessionId: ID!\n $userId: UUID!\n ) {\n competence_certificate_list_for_user(course_slug: $courseSlug, user_id: $userId) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query competenceCertificateForUserQuery(\n $courseSlug: String!\n $courseSessionId: ID!\n $userId: UUID!\n ) {\n competence_certificate_list_for_user(course_slug: $courseSlug, user_id: $userId) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */

File diff suppressed because one or more lines are too long

View File

@ -21,6 +21,7 @@ type Query {
learning_content_document_list: LearningContentDocumentListObjectType learning_content_document_list: LearningContentDocumentListObjectType
competence_certificate(id: ID, slug: String): CompetenceCertificateObjectType competence_certificate(id: ID, slug: String): CompetenceCertificateObjectType
competence_certificate_list(id: ID, slug: String, course_id: ID, course_slug: String): CompetenceCertificateListObjectType competence_certificate_list(id: ID, slug: String, course_id: ID, course_slug: String): CompetenceCertificateListObjectType
competence_certificate_list_for_user(id: ID, slug: String, course_id: ID, course_slug: String, user_id: UUID): CompetenceCertificateListObjectType
assignment(id: ID, slug: String): AssignmentObjectType assignment(id: ID, slug: String): AssignmentObjectType
assignment_completion(assignment_id: ID!, course_session_id: ID!, learning_content_page_id: ID, assignment_user_id: UUID): AssignmentCompletionObjectType assignment_completion(assignment_id: ID!, course_session_id: ID!, learning_content_page_id: ID, assignment_user_id: UUID): AssignmentCompletionObjectType
} }

View File

@ -117,6 +117,42 @@ export const COMPETENCE_NAVI_CERTIFICATE_QUERY = graphql(`
} }
`); `);
export const COMPETENCE_NAVI_CERTIFICATE_FOR_USER_QUERY = graphql(`
query competenceCertificateForUserQuery(
$courseSlug: String!
$courseSessionId: ID!
$userId: UUID!
) {
competence_certificate_list_for_user(course_slug: $courseSlug, user_id: $userId) {
...CoursePageFields
competence_certificates {
...CoursePageFields
assignments {
...CoursePageFields
assignment_type
max_points
completion(course_session_id: $courseSessionId) {
id
completion_status
submitted_at
evaluation_points
evaluation_max_points
evaluation_passed
}
learning_content {
...CoursePageFields
circle {
id
title
slug
}
}
}
}
}
}
`);
export const COURSE_SESSION_DETAIL_QUERY = graphql(` export const COURSE_SESSION_DETAIL_QUERY = graphql(`
query courseSessionDetail($courseSessionId: ID!) { query courseSessionDetail($courseSessionId: ID!) {
course_session(id: $courseSessionId) { course_session(id: $courseSessionId) {

View File

@ -15,6 +15,7 @@ log.debug("CompetenceCertificateComponent setup");
const props = defineProps<{ const props = defineProps<{
competenceCertificate: CompetenceCertificate; competenceCertificate: CompetenceCertificate;
detailView: boolean; detailView: boolean;
frontendUrl?: string;
}>(); }>();
const totalPointsEvaluatedAssignments = computed(() => { const totalPointsEvaluatedAssignments = computed(() => {
@ -40,6 +41,12 @@ const progressStatusCount = computed(() => {
props.competenceCertificate.assignments props.competenceCertificate.assignments
); );
}); });
const frontendUrl = computed(() => {
return props.frontendUrl
? props.frontendUrl
: props.competenceCertificate.frontend_url;
});
</script> </script>
<template> <template>
@ -90,7 +97,7 @@ const progressStatusCount = computed(() => {
<div v-if="!props.detailView"> <div v-if="!props.detailView">
<router-link <router-link
:to="competenceCertificate.frontend_url" :to="frontendUrl"
class="btn-text mt-4 inline-flex items-center py-2 pl-0" class="btn-text mt-4 inline-flex items-center py-2 pl-0"
:data-cy="`certificate-${competenceCertificate.slug}-detail-link`" :data-cy="`certificate-${competenceCertificate.slug}-detail-link`"
> >

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,27 +13,45 @@ import {
assignmentsMaxEvaluationPoints, assignmentsMaxEvaluationPoints,
assignmentsUserPoints, assignmentsUserPoints,
} from "@/pages/competence/utils"; } from "@/pages/competence/utils";
import { useRoute } from "vue-router";
const props = defineProps<{ const props = defineProps<{
courseSlug: string; courseSlug: string;
userId?: string;
}>(); }>();
log.debug("CompetenceCertificateListPage setup", props); log.debug("CompetenceCertificateListPage setup", props);
const courseSession = useCurrentCourseSession(); const courseSession = useCurrentCourseSession();
const route = useRoute();
const certificatesQuery = useQuery({ const certificatesQuery = (() => {
if (props.userId) {
return useQuery({
query: COMPETENCE_NAVI_CERTIFICATE_FOR_USER_QUERY,
variables: {
courseSlug: props.courseSlug,
courseSessionId: courseSession.value.id,
userId: props.userId,
},
});
} else {
return useQuery({
query: COMPETENCE_NAVI_CERTIFICATE_QUERY, query: COMPETENCE_NAVI_CERTIFICATE_QUERY,
variables: { variables: {
courseSlug: props.courseSlug, courseSlug: props.courseSlug,
courseSessionId: courseSession.value.id, courseSessionId: courseSession.value.id,
}, },
}); });
}
})();
const competenceCertificates = computed(() => { const competenceCertificates = computed(() => {
const certificates = props.userId
? certificatesQuery.data?.value?.competence_certificate_list_for_user
: certificatesQuery.data?.value?.competence_certificate_list;
return ( return (
(certificatesQuery.data.value?.competence_certificate_list (certificates?.competence_certificates as unknown as CompetenceCertificate[]) ?? []
?.competence_certificates as unknown as CompetenceCertificate[]) ?? []
); );
}); });
@ -52,6 +73,17 @@ const numAssignmentsEvaluated = computed(() => {
}).length; }).length;
}); });
const certificateFrontendUrl = function (frontendUrl: string) {
if (props.userId) {
const pathSegments = frontendUrl.split("/");
const lastSegment = pathSegments[pathSegments.length - 1];
// Assuming you want to navigate to the current path + last segment
return `${route.path}/${lastSegment}`;
}
return frontendUrl;
};
onMounted(async () => { onMounted(async () => {
// log.debug("AssignmentView mounted", props.assignmentId, props.userId); // log.debug("AssignmentView mounted", props.assignmentId, props.userId);
}); });
@ -92,6 +124,7 @@ onMounted(async () => {
<CompetenceCertificateComponent <CompetenceCertificateComponent
:competence-certificate="competenceCertificate" :competence-certificate="competenceCertificate"
:detail-view="false" :detail-view="false"
:frontend-url="certificateFrontendUrl(competenceCertificate.frontend_url)"
></CompetenceCertificateComponent> ></CompetenceCertificateComponent>
</div> </div>
</div> </div>

View File

@ -5,27 +5,36 @@ import SelfEvaluationAndFeedbackList from "@/components/selfEvaluationFeedback/S
import SelfEvaluationAndFeedbackOverview from "@/components/selfEvaluationFeedback/SelfEvaluationAndFeedbackOverview.vue"; import SelfEvaluationAndFeedbackOverview from "@/components/selfEvaluationFeedback/SelfEvaluationAndFeedbackOverview.vue";
import { useCurrentCourseSession } from "@/composables"; import { useCurrentCourseSession } from "@/composables";
import CompetenceCertificateListPage from "@/pages/competence/CompetenceCertificateListPage.vue"; 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" | "COMPETENCES"; type SubMenuType = "OVERVIEW" | "EVALUATIONS" | "CERTIFICATES" | "CERTIFICATE_DETAIL";
const subMenuOptions: SubMenuType[] = ["OVERVIEW", "EVALUATIONS", "COMPETENCES"]; const subMenuOptions: SubMenuType[] = [
"OVERVIEW",
"EVALUATIONS",
"CERTIFICATES",
"CERTIFICATE_DETAIL",
];
const props = defineProps<{ const props = defineProps<{
userId: string; userId: string;
courseSlug: string; courseSlug: string;
certificateSlug?: string;
}>(); }>();
interface SubMenuItem { interface SubMenuItem {
type: SubMenuType; type: SubMenuType;
label: string; label: string;
url: string; url: string;
inMenu: boolean;
} }
const MENU_ENTRIES: SubMenuItem[] = [ const SUBPAGES: SubMenuItem[] = [
{ {
type: "OVERVIEW", 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,
}, },
{ {
type: "EVALUATIONS", type: "EVALUATIONS",
@ -33,36 +42,52 @@ const MENU_ENTRIES: SubMenuItem[] = [
? "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,
}, },
]; ];
if (useCurrentCourseSession().value.course.configuration.is_uk) { if (useCurrentCourseSession().value.course.configuration.is_uk) {
MENU_ENTRIES.push({ SUBPAGES.push(
type: "COMPETENCES", {
type: "CERTIFICATES",
label: "Kompetenznachweise", label: "Kompetenznachweise",
url: `/course/${props.courseSlug}/profile/${props.userId}/competence/competences`, url: `/course/${props.courseSlug}/profile/${props.userId}/competence/certificates`,
}); inMenu: true,
},
{
type: "CERTIFICATE_DETAIL",
label: "",
url: "",
inMenu: false,
}
);
} }
const route = useRoute(); const route = useRoute();
const active = computed(() => { const active = computed(() => {
const index = subMenuOptions.indexOf(route.meta?.subpage); const index = subMenuOptions.findIndex((option) =>
option.startsWith(route.meta?.subpage)
);
if (index > -1) { if (index > -1) {
return MENU_ENTRIES[index]; return SUBPAGES[index];
} }
return MENU_ENTRIES[0]; return SUBPAGES[0];
}); });
</script> </script>
<template> <template>
<CockpitProfileContent> <CockpitProfileContent>
<template #side> <template #side>
<div v-for="(entry, index) in MENU_ENTRIES" :key="index" class="mb-2"> <div
v-for="(entry, index) in SUBPAGES.filter((p) => p.inMenu)"
:key="index"
class="mb-2"
>
<router-link <router-link
v-if="active" 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': active.type === entry.type }" :class="{ 'text-bold bg-gray-200': entry.type.startsWith(active.type) }"
> >
<span>{{ $t(entry.label) }}</span> <span>{{ $t(entry.label) }}</span>
</router-link> </router-link>
@ -80,8 +105,15 @@ const active = computed(() => {
:profile-user-id="props.userId" :profile-user-id="props.userId"
/> />
<CompetenceCertificateListPage <CompetenceCertificateListPage
v-else-if="active.type === 'COMPETENCES'" v-else-if="active.type === 'CERTIFICATES'"
:course-slug="useCurrentCourseSession().value.course.slug" :course-slug="useCurrentCourseSession().value.course.slug"
:user-id="userId"
/>
<CompetenceCertificateDetailPage
v-else-if="active.type === 'CERTIFICATE_DETAIL'"
:course-slug="useCurrentCourseSession().value.course.slug"
:certificate-slug="certificateSlug ? certificateSlug : ''"
:user-id="userId"
/> />
</div> </div>
</template> </template>

View File

@ -176,22 +176,31 @@ const router = createRouter({
name: "profileCompetence", name: "profileCompetence",
children: [ children: [
{ {
path: "", // Default path (e.g., /competence) path: "",
name: "competenceMain", name: "competenceMain",
meta: { subpage: "OVERVIEW" }, meta: { subpage: "OVERVIEW" },
component: () => import("@/pages/userProfile/CompetenceProfilePage.vue"), component: () => import("@/pages/userProfile/CompetenceProfilePage.vue"),
}, },
{ {
path: "evaluations", // Subpath (e.g., /competence/evaluations) path: "evaluations",
name: "competenceEvaluations", name: "competenceEvaluations",
meta: { subpage: "EVALUATIONS" }, meta: { subpage: "EVALUATIONS" },
component: () => import("@/pages/userProfile/CompetenceProfilePage.vue"), component: () => import("@/pages/userProfile/CompetenceProfilePage.vue"),
}, },
{ {
path: "competences", // Another subpath (e.g., /competence/competences) path: "certificates",
name: "profileCompetences", name: "profileCompetences",
meta: { subpage: "COMPETENCES" }, meta: { subpage: "CERTIFICATES" },
component: () => import("@/pages/userProfile/CompetenceProfilePage.vue"), component: () => import("@/pages/userProfile/CompetenceProfilePage.vue"),
children: [
{
path: ":certificateSlug",
props: true,
meta: { subpage: "CERTIFICATE_DETAIL" },
component: () =>
import("@/pages/userProfile/CompetenceProfilePage.vue"),
},
],
}, },
], ],
}, },

View File

@ -101,6 +101,10 @@ class AssignmentObjectType(DjangoObjectType):
lp = self.find_attached_learning_content() lp = self.find_attached_learning_content()
if lp: if lp:
learning_content_page_id = lp.id learning_content_page_id = lp.id
if not assignment_user_id:
assignment_user_id = getattr(info.context, "assignment_user_id", None)
return resolve_assignment_completion( return resolve_assignment_completion(
info=info, info=info,
course_session_id=course_session_id, course_session_id=course_session_id,

View File

@ -9,6 +9,8 @@ from vbv_lernwelt.competence.models import (
CompetenceCertificateList, CompetenceCertificateList,
) )
from vbv_lernwelt.course.graphql.types import resolve_course_page from vbv_lernwelt.course.graphql.types import resolve_course_page
from vbv_lernwelt.course.models import CourseSessionUser
from vbv_lernwelt.iam.permissions import can_view_profile
class CompetenceCertificateQuery(object): class CompetenceCertificateQuery(object):
@ -24,6 +26,15 @@ class CompetenceCertificateQuery(object):
course_slug=graphene.String(), course_slug=graphene.String(),
) )
competence_certificate_list_for_user = graphene.Field(
CompetenceCertificateListObjectType,
id=graphene.ID(),
slug=graphene.String(),
course_id=graphene.ID(),
course_slug=graphene.String(),
user_id=graphene.UUID(),
)
def resolve_competence_certificate(root, info, id=None, slug=None): def resolve_competence_certificate(root, info, id=None, slug=None):
return resolve_course_page(CompetenceCertificate, root, info, id=id, slug=slug) return resolve_course_page(CompetenceCertificate, root, info, id=id, slug=slug)
@ -39,3 +50,26 @@ class CompetenceCertificateQuery(object):
course_id=course_id, course_id=course_id,
course_slug=course_slug, course_slug=course_slug,
) )
def resolve_competence_certificate_list_for_user(
root, info, id=None, slug=None, course_id=None, course_slug=None, user_id=None
):
try:
course_session_user = CourseSessionUser.objects.get(user__id=user_id)
except CourseSessionUser.DoesNotExist:
return None
if not can_view_profile(info.context.user, course_session_user):
return None
setattr(info.context, "assignment_user_id", user_id)
return resolve_course_page(
CompetenceCertificateList,
root,
info,
id=id,
slug=slug,
course_id=course_id,
course_slug=course_slug,
)