Refactor CirclePage
This commit is contained in:
parent
2eddb93be5
commit
627e4f6873
|
|
@ -1,9 +1,8 @@
|
|||
import { COURSE_SESSION_DETAIL_QUERY, LEARNING_PATH_QUERY } from "@/graphql/queries";
|
||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||
import type { CourseSession, CourseSessionDetail } from "@/types";
|
||||
import { useQuery } from "@urql/vue";
|
||||
|
||||
import { COURSE_SESSION_DETAIL_QUERY } from "@/graphql/queries";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import type { CourseSession, CourseSessionDetail, LearningPathType } from "@/types";
|
||||
import { useQuery } from "@urql/vue";
|
||||
import log from "loglevel";
|
||||
import type { ComputedRef } from "vue";
|
||||
import { computed, ref, watchEffect } from "vue";
|
||||
|
|
@ -123,3 +122,31 @@ export function useCourseSessionDetailQuery(courSessionId?: string) {
|
|||
filterCircleExperts,
|
||||
};
|
||||
}
|
||||
|
||||
export function useLearningPathQuery(courseSlug: string) {
|
||||
const queryResult = useQuery({
|
||||
query: LEARNING_PATH_QUERY,
|
||||
variables: {
|
||||
slug: `${courseSlug}-lp`,
|
||||
},
|
||||
});
|
||||
|
||||
const learningPath = computed(() => {
|
||||
return queryResult.data.value?.learning_path as LearningPathType | undefined;
|
||||
});
|
||||
|
||||
const circles = computed(() => {
|
||||
if (learningPath.value) {
|
||||
return learningPath.value.topics.flatMap((t) => t.circles);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
function findCircle(slug: string) {
|
||||
return (circles.value ?? []).find((c) => {
|
||||
return c.slug.endsWith(slug);
|
||||
});
|
||||
}
|
||||
|
||||
return { ...queryResult, learningPath, circles, findCircle };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ const documents = {
|
|||
"\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 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 }\n assignment_user {\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 ...CoursePageFields\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument,
|
||||
"\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\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 learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.LearningPathQueryDocument,
|
||||
"\n query learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n competence_certificate {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.LearningPathQueryDocument,
|
||||
"\n mutation SendFeedbackMutation(\n $courseSessionId: ID!\n $learningContentId: ID!\n $data: GenericScalar!\n $submitted: Boolean\n ) {\n send_feedback(\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n data: $data\n submitted: $submitted\n ) {\n feedback_response {\n id\n data\n submitted\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument,
|
||||
};
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ export function graphql(source: "\n query courseSessionDetail($courseSessionId:
|
|||
/**
|
||||
* 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 learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n query learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n competence_certificate {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n competence_certificate {\n ...CoursePageFields\n }\n }\n }\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.
|
||||
*/
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -22,46 +22,15 @@ type Query {
|
|||
|
||||
type LearningPathObjectType implements CoursePageInterface {
|
||||
id: ID!
|
||||
path: String!
|
||||
depth: Int!
|
||||
numchild: Int!
|
||||
translation_key: String!
|
||||
live: Boolean!
|
||||
has_unpublished_changes: Boolean!
|
||||
first_published_at: DateTime
|
||||
last_published_at: DateTime
|
||||
go_live_at: DateTime
|
||||
expire_at: DateTime
|
||||
expired: Boolean!
|
||||
locked: Boolean!
|
||||
locked_at: DateTime
|
||||
locked_by: UserObjectType
|
||||
title: String!
|
||||
draft_title: String!
|
||||
slug: String!
|
||||
content_type: String!
|
||||
url_path: String!
|
||||
owner: UserObjectType
|
||||
|
||||
"""
|
||||
Der Titel der Seite, dargestellt in Suchmaschinen-Ergebnissen als die verlinkte Überschrift.
|
||||
"""
|
||||
seo_title: String!
|
||||
|
||||
"""
|
||||
Ob ein Link zu dieser Seite in automatisch generierten Menüs auftaucht.
|
||||
"""
|
||||
show_in_menus: Boolean!
|
||||
|
||||
"""
|
||||
Die informative Beschreibung, dargestellt in Suchmaschinen-Ergebnissen unter der Überschrift.
|
||||
"""
|
||||
search_description: String!
|
||||
latest_revision_created_at: DateTime
|
||||
live: Boolean!
|
||||
translation_key: String!
|
||||
frontend_url: String!
|
||||
circle: CircleObjectType
|
||||
course: CourseObjectType
|
||||
topics: [TopicObjectType]
|
||||
topics: [TopicObjectType!]!
|
||||
}
|
||||
|
||||
interface CoursePageInterface {
|
||||
|
|
@ -88,7 +57,7 @@ type CircleObjectType implements CoursePageInterface {
|
|||
frontend_url: String!
|
||||
circle: CircleObjectType
|
||||
course: CourseObjectType
|
||||
learning_sequences: [LearningSequenceObjectType]
|
||||
learning_sequences: [LearningSequenceObjectType!]!
|
||||
}
|
||||
|
||||
type CourseObjectType {
|
||||
|
|
@ -109,10 +78,11 @@ type LearningSequenceObjectType implements CoursePageInterface {
|
|||
frontend_url: String!
|
||||
circle: CircleObjectType
|
||||
course: CourseObjectType
|
||||
learning_units: [LearningUnitObjectType]
|
||||
learning_units: [LearningUnitObjectType!]!
|
||||
}
|
||||
|
||||
type LearningUnitObjectType implements CoursePageInterface {
|
||||
title_hidden: Boolean!
|
||||
id: ID!
|
||||
title: String!
|
||||
slug: String!
|
||||
|
|
@ -141,44 +111,6 @@ interface LearningContentInterface {
|
|||
content: String
|
||||
}
|
||||
|
||||
"""
|
||||
The `DateTime` scalar type represents a DateTime
|
||||
value as specified by
|
||||
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
|
||||
"""
|
||||
scalar DateTime
|
||||
|
||||
type UserObjectType {
|
||||
"""
|
||||
Erforderlich. 150 Zeichen oder weniger. Nur Buchstaben, Ziffern und @/./+/-/_.
|
||||
"""
|
||||
username: String!
|
||||
first_name: String!
|
||||
last_name: String!
|
||||
id: UUID!
|
||||
avatar_url: String!
|
||||
email: String!
|
||||
language: CoreUserLanguageChoices!
|
||||
}
|
||||
|
||||
"""
|
||||
Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects
|
||||
in fields, resolvers and input.
|
||||
"""
|
||||
scalar UUID
|
||||
|
||||
"""An enumeration."""
|
||||
enum CoreUserLanguageChoices {
|
||||
"""Deutsch"""
|
||||
DE
|
||||
|
||||
"""Français"""
|
||||
FR
|
||||
|
||||
"""Italiano"""
|
||||
IT
|
||||
}
|
||||
|
||||
type TopicObjectType implements CoursePageInterface {
|
||||
is_visible: Boolean!
|
||||
id: ID!
|
||||
|
|
@ -190,7 +122,7 @@ type TopicObjectType implements CoursePageInterface {
|
|||
frontend_url: String!
|
||||
circle: CircleObjectType
|
||||
course: CourseObjectType
|
||||
circles: [CircleObjectType]
|
||||
circles: [CircleObjectType!]!
|
||||
}
|
||||
|
||||
type LearningContentMediaLibraryObjectType implements CoursePageInterface & LearningContentInterface {
|
||||
|
|
@ -223,6 +155,7 @@ type LearningContentAssignmentObjectType implements CoursePageInterface & Learni
|
|||
minutes: Int
|
||||
description: String
|
||||
content: String
|
||||
competence_certificate: CompetenceCertificateObjectType!
|
||||
}
|
||||
|
||||
type AssignmentObjectType implements CoursePageInterface {
|
||||
|
|
@ -316,6 +249,44 @@ type AssignmentCompletionObjectType {
|
|||
learning_content_page_id: ID
|
||||
}
|
||||
|
||||
"""
|
||||
Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects
|
||||
in fields, resolvers and input.
|
||||
"""
|
||||
scalar UUID
|
||||
|
||||
"""
|
||||
The `DateTime` scalar type represents a DateTime
|
||||
value as specified by
|
||||
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
|
||||
"""
|
||||
scalar DateTime
|
||||
|
||||
type UserObjectType {
|
||||
"""
|
||||
Erforderlich. 150 Zeichen oder weniger. Nur Buchstaben, Ziffern und @/./+/-/_.
|
||||
"""
|
||||
username: String!
|
||||
first_name: String!
|
||||
last_name: String!
|
||||
id: UUID!
|
||||
avatar_url: String!
|
||||
email: String!
|
||||
language: CoreUserLanguageChoices!
|
||||
}
|
||||
|
||||
"""An enumeration."""
|
||||
enum CoreUserLanguageChoices {
|
||||
"""Deutsch"""
|
||||
DE
|
||||
|
||||
"""Français"""
|
||||
FR
|
||||
|
||||
"""Italiano"""
|
||||
IT
|
||||
}
|
||||
|
||||
type CourseSessionObjectType {
|
||||
id: ID!
|
||||
created_at: DateTime!
|
||||
|
|
@ -428,6 +399,7 @@ type CourseSessionEdoniqTestObjectType {
|
|||
}
|
||||
|
||||
type LearningContentEdoniqTestObjectType implements CoursePageInterface & LearningContentInterface {
|
||||
checkbox_text: String!
|
||||
content_assignment: AssignmentObjectType
|
||||
id: ID!
|
||||
title: String!
|
||||
|
|
@ -441,6 +413,7 @@ type LearningContentEdoniqTestObjectType implements CoursePageInterface & Learni
|
|||
minutes: Int
|
||||
description: String
|
||||
content: String
|
||||
competence_certificate: CompetenceCertificateObjectType!
|
||||
}
|
||||
|
||||
type CourseSessionUserObjectsType {
|
||||
|
|
@ -612,42 +585,11 @@ type LearningContentDocumentListObjectType implements CoursePageInterface & Lear
|
|||
|
||||
type CompetenceCertificateListObjectType implements CoursePageInterface {
|
||||
id: ID!
|
||||
path: String!
|
||||
depth: Int!
|
||||
numchild: Int!
|
||||
translation_key: String!
|
||||
live: Boolean!
|
||||
has_unpublished_changes: Boolean!
|
||||
first_published_at: DateTime
|
||||
last_published_at: DateTime
|
||||
go_live_at: DateTime
|
||||
expire_at: DateTime
|
||||
expired: Boolean!
|
||||
locked: Boolean!
|
||||
locked_at: DateTime
|
||||
locked_by: UserObjectType
|
||||
title: String!
|
||||
draft_title: String!
|
||||
slug: String!
|
||||
content_type: String!
|
||||
url_path: String!
|
||||
owner: UserObjectType
|
||||
|
||||
"""
|
||||
Der Titel der Seite, dargestellt in Suchmaschinen-Ergebnissen als die verlinkte Überschrift.
|
||||
"""
|
||||
seo_title: String!
|
||||
|
||||
"""
|
||||
Ob ein Link zu dieser Seite in automatisch generierten Menüs auftaucht.
|
||||
"""
|
||||
show_in_menus: Boolean!
|
||||
|
||||
"""
|
||||
Die informative Beschreibung, dargestellt in Suchmaschinen-Ergebnissen unter der Überschrift.
|
||||
"""
|
||||
search_description: String!
|
||||
latest_revision_created_at: DateTime
|
||||
live: Boolean!
|
||||
translation_key: String!
|
||||
frontend_url: String!
|
||||
circle: CircleObjectType
|
||||
course: CourseObjectType
|
||||
|
|
|
|||
|
|
@ -213,6 +213,15 @@ export const LEARNING_PATH_QUERY = graphql(`
|
|||
content_assignment {
|
||||
id
|
||||
}
|
||||
competence_certificate {
|
||||
...CoursePageFields
|
||||
}
|
||||
}
|
||||
... on LearningContentEdoniqTestObjectType {
|
||||
checkbox_text
|
||||
competence_certificate {
|
||||
...CoursePageFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { useCircleStore } from "@/stores/circle";
|
||||
import type { CourseSessionUser } from "@/types";
|
||||
import { humanizeDuration } from "@/utils/humanizeDuration";
|
||||
import sumBy from "lodash/sumBy";
|
||||
import log from "loglevel";
|
||||
import { computed, onMounted } from "vue";
|
||||
import { computed, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import CircleDiagram from "./CircleDiagram.vue";
|
||||
import CircleOverview from "./CircleOverview.vue";
|
||||
import DocumentSection from "./DocumentSection.vue";
|
||||
import LearningSequence from "./LearningSequence.vue";
|
||||
import { useCourseSessionDetailQuery } from "@/composables";
|
||||
import { useCourseSessionDetailQuery, useLearningPathQuery } from "@/composables";
|
||||
import { stringifyParse } from "@/utils/utils";
|
||||
import { useCircleStore } from "@/stores/circle";
|
||||
import LearningSequence from "@/pages/learningPath/circlePage/LearningSequence.vue";
|
||||
|
||||
export interface Props {
|
||||
courseSlug: string;
|
||||
|
|
@ -28,81 +27,79 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
profileUser: undefined,
|
||||
});
|
||||
|
||||
log.debug("CirclePage created", props.readonly, props.profileUser);
|
||||
log.debug("CirclePage created", stringifyParse(props));
|
||||
|
||||
const circleExperts = computed(() => {
|
||||
if (circleStore.circle) {
|
||||
return courseSessionDetailResult.filterCircleExperts(circleStore.circle.slug);
|
||||
if (circle.value) {
|
||||
return courseSessionDetailResult.filterCircleExperts(circle.value.slug);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const duration = computed(() => {
|
||||
if (circleStore.circle) {
|
||||
const minutes = sumBy(circleStore.circle.learningSequences, "minutes");
|
||||
return humanizeDuration(minutes);
|
||||
}
|
||||
|
||||
// if (circleStore.circle) {
|
||||
// const minutes = sumBy(circleStore.circle.learningSequences, "minutes");
|
||||
// return humanizeDuration(minutes);
|
||||
// }
|
||||
return "";
|
||||
});
|
||||
|
||||
const showDuration = computed(() => {
|
||||
return (
|
||||
circleStore.circle && sumBy(circleStore.circle.learningSequences, "minutes") > 0
|
||||
);
|
||||
// return (
|
||||
// circleStore.circle && sumBy(circleStore.circle.learningSequences, "minutes") > 0
|
||||
// );
|
||||
return false;
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
log.debug(
|
||||
"CirclePage mounted",
|
||||
props.courseSlug,
|
||||
props.circleSlug,
|
||||
props.profileUser
|
||||
);
|
||||
const lpQueryResult = useLearningPathQuery(props.courseSlug);
|
||||
|
||||
try {
|
||||
if (props.profileUser) {
|
||||
await circleStore.loadCircle(
|
||||
props.courseSlug,
|
||||
props.circleSlug,
|
||||
props.profileUser.user_id
|
||||
);
|
||||
} else {
|
||||
await circleStore.loadCircle(props.courseSlug, props.circleSlug);
|
||||
}
|
||||
const circle = computed(() => {
|
||||
return lpQueryResult.findCircle(props.circleSlug);
|
||||
});
|
||||
|
||||
if (route.hash.startsWith("#ls-") || route.hash.startsWith("#lu-")) {
|
||||
const slugEnd = route.hash.replace("#", "");
|
||||
let wagtailPage = null;
|
||||
watch(
|
||||
() => circle.value,
|
||||
() => {
|
||||
if (circle.value) {
|
||||
log.debug("circle loaded", circle);
|
||||
|
||||
if (slugEnd.startsWith("ls-")) {
|
||||
wagtailPage = circleStore.circle?.learningSequences.find((ls) => {
|
||||
return ls.slug.endsWith(slugEnd);
|
||||
});
|
||||
} else if (slugEnd.startsWith("lu-")) {
|
||||
const learningUnits = circleStore.circle?.learningSequences.flatMap(
|
||||
(ls) => ls.learningUnits
|
||||
);
|
||||
if (learningUnits) {
|
||||
wagtailPage = learningUnits.find((lu) => {
|
||||
return lu.slug.endsWith(slugEnd);
|
||||
});
|
||||
try {
|
||||
if (route.hash.startsWith("#ls-") || route.hash.startsWith("#lu-")) {
|
||||
const slugEnd = route.hash.replace("#", "");
|
||||
|
||||
if (circle.value) {
|
||||
let wagtailPage = null;
|
||||
if (slugEnd.startsWith("ls-")) {
|
||||
wagtailPage = circle.value.learning_sequences.find((ls) => {
|
||||
return ls.slug.endsWith(slugEnd);
|
||||
});
|
||||
} else if (slugEnd.startsWith("lu-")) {
|
||||
const learningUnits = circle.value.learning_sequences.flatMap(
|
||||
(ls) => ls.learning_units
|
||||
);
|
||||
if (learningUnits) {
|
||||
wagtailPage = learningUnits.find((lu) => {
|
||||
return lu.slug.endsWith(slugEnd);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (wagtailPage) {
|
||||
document
|
||||
.getElementById(wagtailPage.slug)
|
||||
?.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wagtailPage) {
|
||||
document
|
||||
.getElementById(wagtailPage.slug)
|
||||
?.scrollIntoView({ behavior: "smooth" });
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
});
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="circle">
|
||||
<Teleport to="body">
|
||||
<CircleOverview
|
||||
:circle="circleStore.circle"
|
||||
|
|
@ -145,7 +142,7 @@ onMounted(async () => {
|
|||
</router-link>
|
||||
|
||||
<h1 class="text-blue-dark text-4xl lg:text-6xl" data-cy="circle-title">
|
||||
{{ circleStore.circle?.title }}
|
||||
{{ circle?.title }}
|
||||
</h1>
|
||||
|
||||
<div v-if="showDuration" class="mt-2">
|
||||
|
|
@ -176,7 +173,7 @@ onMounted(async () => {
|
|||
{{ $t("circlePage.circleContentBoxTitle") }}
|
||||
</h3>
|
||||
<div class="mt-4 leading-relaxed">
|
||||
{{ circleStore.circle?.description }}
|
||||
{{ circle?.description }}
|
||||
</div>
|
||||
|
||||
<button
|
||||
|
|
@ -192,7 +189,7 @@ onMounted(async () => {
|
|||
<div class="mt-4 leading-relaxed">
|
||||
{{
|
||||
$t("circlePage.contactExpertDescription", {
|
||||
circleName: circleStore.circle?.title,
|
||||
circleName: circle?.title,
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
|
|
@ -220,9 +217,8 @@ onMounted(async () => {
|
|||
|
||||
<ol class="flex-auto bg-gray-200 px-4 py-8 lg:px-24">
|
||||
<li
|
||||
v-for="learningSequence in circleStore.circle?.learningSequences ||
|
||||
[]"
|
||||
:key="learningSequence.translation_key"
|
||||
v-for="learningSequence in circle?.learning_sequences ?? []"
|
||||
:key="learningSequence.id"
|
||||
>
|
||||
<LearningSequence
|
||||
:learning-sequence="learningSequence"
|
||||
|
|
@ -239,15 +235,6 @@ onMounted(async () => {
|
|||
</template>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
.circle-container {
|
||||
/*background: linear-gradient(to right, white 0%, white 50%, theme(colors.gray.200) 50%, theme(colors.gray.200) 100%);*/
|
||||
}
|
||||
|
||||
.circle {
|
||||
/*max-width: 1440px;*/
|
||||
/*margin: 0 auto;*/
|
||||
}
|
||||
|
||||
.v-enter-active,
|
||||
.v-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
||||
import LearningContentBadge from "@/pages/learningPath/LearningContentTypeBadge.vue";
|
||||
import { showIcon } from "@/pages/learningPath/circlePage/learningSequenceUtils";
|
||||
import { useCircleStore } from "@/stores/circle";
|
||||
import type {
|
||||
CourseCompletionStatus,
|
||||
LearningContent,
|
||||
LearningContentAssignment,
|
||||
LearningContentEdoniqTest,
|
||||
LearningContentInterface,
|
||||
LearningSequence,
|
||||
} from "@/types";
|
||||
import findLast from "lodash/findLast";
|
||||
import { computed } from "vue";
|
||||
import { humanizeDuration } from "../../../utils/humanizeDuration";
|
||||
import {
|
||||
|
|
@ -30,52 +26,52 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
|
||||
const circleStore = useCircleStore();
|
||||
|
||||
function toggleCompleted(learningContent: LearningContentInterface) {
|
||||
let completionStatus: CourseCompletionStatus = "SUCCESS";
|
||||
if (learningContent.completion_status === "SUCCESS") {
|
||||
completionStatus = "FAIL";
|
||||
}
|
||||
circleStore.markCompletion(learningContent, completionStatus);
|
||||
function toggleCompleted(learningContent: LearningContent) {
|
||||
// let completionStatus: CourseCompletionStatus = "SUCCESS";
|
||||
// if (learningContent.completion_status === "SUCCESS") {
|
||||
// completionStatus = "FAIL";
|
||||
// }
|
||||
// circleStore.markCompletion(learningContent, completionStatus);
|
||||
}
|
||||
|
||||
const someFinished = computed(() => {
|
||||
if (props.learningSequence && circleStore.circle) {
|
||||
return circleStore.circle.someFinishedInLearningSequence(
|
||||
props.learningSequence.translation_key
|
||||
);
|
||||
}
|
||||
// if (props.learningSequence && circleStore.circle) {
|
||||
// return circleStore.circle.someFinishedInLearningSequence(
|
||||
// props.learningSequence.translation_key
|
||||
// );
|
||||
// }
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
const allFinished = computed(() => {
|
||||
if (props.learningSequence && circleStore.circle) {
|
||||
return circleStore.circle.allFinishedInLearningSequence(
|
||||
props.learningSequence.translation_key
|
||||
);
|
||||
}
|
||||
// if (props.learningSequence && circleStore.circle) {
|
||||
// return circleStore.circle.allFinishedInLearningSequence(
|
||||
// props.learningSequence.translation_key
|
||||
// );
|
||||
// }
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
const continueTranslationKeyTuple = computed(() => {
|
||||
if (props.learningSequence && circleStore.circle) {
|
||||
const lastFinished = findLast(
|
||||
circleStore.circle.flatLearningContents,
|
||||
(learningContent) => {
|
||||
return learningContent.completion_status === "SUCCESS";
|
||||
}
|
||||
);
|
||||
|
||||
if (!lastFinished) {
|
||||
// must be the first
|
||||
return [circleStore.circle.flatLearningContents[0].translation_key, true];
|
||||
}
|
||||
|
||||
if (lastFinished && lastFinished.nextLearningContent) {
|
||||
return [lastFinished.nextLearningContent.translation_key, false];
|
||||
}
|
||||
}
|
||||
// if (props.learningSequence && circleStore.circle) {
|
||||
// const lastFinished = findLast(
|
||||
// circleStore.circle.flatLearningContents,
|
||||
// (learningContent) => {
|
||||
// return learningContent.completion_status === "SUCCESS";
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// if (!lastFinished) {
|
||||
// // must be the first
|
||||
// return [circleStore.circle.flatLearningContents[0].translation_key, true];
|
||||
// }
|
||||
//
|
||||
// if (lastFinished && lastFinished.nextLearningContent) {
|
||||
// return [lastFinished.nextLearningContent.translation_key, false];
|
||||
// }
|
||||
// }
|
||||
|
||||
return "";
|
||||
});
|
||||
|
|
@ -97,8 +93,8 @@ const learningSequenceBorderClass = computed(() => {
|
|||
|
||||
function belongsToCompetenceCertificate(lc: LearningContent) {
|
||||
return (
|
||||
(lc.content_type === "learnpath.LearningContentAssignment" ||
|
||||
lc.content_type === "learnpath.LearningContentEdoniqTest") &&
|
||||
(lc.__typename === "LearningContentAssignmentObjectType" ||
|
||||
lc.__typename === "LearningContentEdoniqTestObjectType") &&
|
||||
lc.competence_certificate?.frontend_url
|
||||
);
|
||||
}
|
||||
|
|
@ -136,7 +132,7 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
|
|||
|
||||
<ol class="border bg-white px-4 lg:px-6" :class="learningSequenceBorderClass">
|
||||
<li
|
||||
v-for="learningUnit in learningSequence.learningUnits"
|
||||
v-for="learningUnit in learningSequence.learning_units"
|
||||
:id="learningUnit.slug"
|
||||
:key="learningUnit.id"
|
||||
class="pt-3 lg:pt-6"
|
||||
|
|
@ -154,7 +150,7 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
|
|||
</div>
|
||||
<ol>
|
||||
<li
|
||||
v-for="learningContent in learningUnit.learningContents"
|
||||
v-for="learningContent in learningUnit.learning_contents"
|
||||
:key="learningContent.id"
|
||||
>
|
||||
<div class="pb-6">
|
||||
|
|
@ -181,15 +177,15 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
|
|||
"
|
||||
@toggle="toggleCompleted(learningContent)"
|
||||
@click="
|
||||
(event: MouseEvent) => {
|
||||
// when disabled open the learning content directly
|
||||
if (!learningContent.can_user_self_toggle_course_completion) {
|
||||
circleStore.openLearningContent(learningContent);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
"
|
||||
(event: MouseEvent) => {
|
||||
// when disabled open the learning content directly
|
||||
if (!learningContent.can_user_self_toggle_course_completion) {
|
||||
circleStore.openLearningContent(learningContent);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
"
|
||||
/>
|
||||
<div
|
||||
class="flex flex-auto flex-col gap-4 xl:flex-row xl:justify-between"
|
||||
|
|
@ -258,31 +254,31 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
|
|||
</li>
|
||||
</ol>
|
||||
|
||||
<div
|
||||
v-if="learningUnit.children.length"
|
||||
:class="{ 'cursor-pointer': !props.readonly }"
|
||||
:data-cy="`${learningUnit.slug}`"
|
||||
@click="!props.readonly && circleStore.openSelfEvaluation(learningUnit)"
|
||||
>
|
||||
<div
|
||||
v-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'SUCCESS'"
|
||||
class="self-evaluation-success flex items-center gap-4 pb-6"
|
||||
>
|
||||
<it-icon-smiley-happy class="mr-4 h-8 w-8 flex-none" data-cy="success" />
|
||||
<div>{{ $t("selfEvaluation.selfEvaluationYes") }}</div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'FAIL'"
|
||||
class="self-evaluation-fail flex items-center gap-4 pb-6"
|
||||
>
|
||||
<it-icon-smiley-thinking class="mr-4 h-8 w-8 flex-none" data-cy="fail" />
|
||||
<div>{{ $t("selfEvaluation.selfEvaluationNo") }}</div>
|
||||
</div>
|
||||
<div v-else class="self-evaluation-unknown flex items-center gap-4 pb-6">
|
||||
<it-icon-smiley-neutral class="mr-4 h-8 w-8 flex-none" data-cy="unknown" />
|
||||
<div>{{ $t("a.Selbsteinschätzung") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div-->
|
||||
<!-- v-if="learningUnit.children.length"-->
|
||||
<!-- :class="{ 'cursor-pointer': !props.readonly }"-->
|
||||
<!-- :data-cy="`${learningUnit.slug}`"-->
|
||||
<!-- @click="!props.readonly && circleStore.openSelfEvaluation(learningUnit)"-->
|
||||
<!-- >-->
|
||||
<!-- <div-->
|
||||
<!-- v-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'SUCCESS'"-->
|
||||
<!-- class="self-evaluation-success flex items-center gap-4 pb-6"-->
|
||||
<!-- >-->
|
||||
<!-- <it-icon-smiley-happy class="mr-4 h-8 w-8 flex-none" data-cy="success" />-->
|
||||
<!-- <div>{{ $t("selfEvaluation.selfEvaluationYes") }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div-->
|
||||
<!-- v-else-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'FAIL'"-->
|
||||
<!-- class="self-evaluation-fail flex items-center gap-4 pb-6"-->
|
||||
<!-- >-->
|
||||
<!-- <it-icon-smiley-thinking class="mr-4 h-8 w-8 flex-none" data-cy="fail" />-->
|
||||
<!-- <div>{{ $t("selfEvaluation.selfEvaluationNo") }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-else class="self-evaluation-unknown flex items-center gap-4 pb-6">-->
|
||||
<!-- <it-icon-smiley-neutral class="mr-4 h-8 w-8 flex-none" data-cy="unknown" />-->
|
||||
<!-- <div>{{ $t("a.Selbsteinschätzung") }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<hr v-if="!learningUnit.last" class="-mx-4 text-gray-500" />
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import LearningContentContainer from "@/pages/learningPath/learningContentPage/L
|
|||
import DocumentListBlock from "@/pages/learningPath/learningContentPage/blocks/DocumentListBlock.vue";
|
||||
import EdoniqTestBlock from "@/pages/learningPath/learningContentPage/blocks/EdoniqTestBlock.vue";
|
||||
import { useCircleStore } from "@/stores/circle";
|
||||
import type { LearningContent, LearningContentType } from "@/types";
|
||||
import type { LearningContent, LearningContentContentType } from "@/types";
|
||||
import eventBus from "@/utils/eventBus";
|
||||
import log from "loglevel";
|
||||
import type { Component } from "vue";
|
||||
|
|
@ -29,7 +29,7 @@ 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
|
||||
const COMPONENTS: Record<LearningContentType, Component> = {
|
||||
const COMPONENTS: Record<LearningContentContentType, Component> = {
|
||||
"learnpath.LearningContentAssignment": AssignmentBlock,
|
||||
"learnpath.LearningContentAttendanceCourse": AttendanceCourseBlock,
|
||||
"learnpath.LearningContentDocumentList": DocumentListBlock,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,25 @@
|
|||
import type {
|
||||
AssignmentCompletionObjectType,
|
||||
AssignmentCompletionStatus as AssignmentCompletionStatusGenerated,
|
||||
CircleObjectType,
|
||||
CourseCourseSessionUserRoleChoices,
|
||||
CourseSessionObjectType,
|
||||
CourseSessionUserObjectsType,
|
||||
LearningContentAssignmentObjectType,
|
||||
LearningContentAttendanceCourseObjectType,
|
||||
LearningContentDocumentListObjectType,
|
||||
LearningContentEdoniqTestObjectType,
|
||||
LearningContentFeedbackObjectType,
|
||||
LearningContentLearningModuleObjectType,
|
||||
LearningContentMediaLibraryObjectType,
|
||||
LearningContentPlaceholderObjectType,
|
||||
LearningContentRichTextObjectType,
|
||||
LearningContentVideoObjectType,
|
||||
LearningPathObjectType,
|
||||
LearningSequenceObjectType,
|
||||
LearningUnitObjectType,
|
||||
TopicObjectType,
|
||||
} from "@/gql/graphql";
|
||||
import type { Circle } from "@/services/circle";
|
||||
import type { Component } from "vue";
|
||||
|
||||
export type LoginMethod = "local" | "sso";
|
||||
|
|
@ -29,101 +43,98 @@ export interface CircleLight {
|
|||
readonly title: string;
|
||||
}
|
||||
|
||||
// refine generated types
|
||||
export type LearningContentAssignment = LearningContentAssignmentObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentAssignment";
|
||||
};
|
||||
|
||||
export type LearningContentAttendanceCourse =
|
||||
LearningContentAttendanceCourseObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentAttendanceCourse";
|
||||
};
|
||||
|
||||
export type LearningContentDocumentList = LearningContentDocumentListObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentDocumentList";
|
||||
};
|
||||
|
||||
export type LearningContentEdoniqTest = LearningContentEdoniqTestObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentEdoniqTest";
|
||||
};
|
||||
|
||||
export type LearningContentFeedback = LearningContentFeedbackObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentFeedback";
|
||||
};
|
||||
|
||||
export type LearningContentLearningModule = LearningContentLearningModuleObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentLearningModule";
|
||||
};
|
||||
|
||||
export type LearningContentMediaLibrary = LearningContentMediaLibraryObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentMediaLibrary";
|
||||
};
|
||||
|
||||
export type LearningContentPlaceholder = LearningContentPlaceholderObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentPlaceholder";
|
||||
};
|
||||
|
||||
export type LearningContentRichText = LearningContentRichTextObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentRichText";
|
||||
};
|
||||
|
||||
export type LearningContentVideo = LearningContentVideoObjectType & {
|
||||
readonly content_type: "learnpath.LearningContentVideo";
|
||||
};
|
||||
|
||||
export type LearningContent =
|
||||
| LearningContentAssignment
|
||||
| LearningContentAttendanceCourse
|
||||
| LearningContentDocumentList
|
||||
| LearningContentEdoniqTest
|
||||
| LearningContentFeedback
|
||||
| LearningContentLearningModule
|
||||
| LearningContentMediaLibrary
|
||||
| LearningContentPlaceholder
|
||||
| LearningContentRichText
|
||||
| LearningContentEdoniqTest
|
||||
| LearningContentVideo;
|
||||
|
||||
export type LearningContentType = LearningContent["content_type"];
|
||||
export type LearningContentContentType = LearningContent["content_type"];
|
||||
|
||||
export interface LearningContentInterface extends BaseCourseWagtailPage {
|
||||
readonly content_type: LearningContentType;
|
||||
readonly minutes: number;
|
||||
readonly description: string;
|
||||
readonly content_url: string;
|
||||
readonly can_user_self_toggle_course_completion: boolean;
|
||||
parentCircle: Circle;
|
||||
parentLearningSequence?: LearningSequence;
|
||||
parentLearningUnit?: LearningUnit;
|
||||
nextLearningContent?: LearningContent;
|
||||
previousLearningContent?: LearningContent;
|
||||
}
|
||||
export type LearningUnit = Omit<
|
||||
LearningUnitObjectType,
|
||||
"content_type" | "learning_contents"
|
||||
> & {
|
||||
content_type: "learnpath.LearningUnit";
|
||||
learning_contents: LearningContent[];
|
||||
};
|
||||
|
||||
export interface LearningContentAssignment extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentAssignment";
|
||||
readonly content_assignment_id: string;
|
||||
readonly assignment_type: AssignmentType;
|
||||
readonly competence_certificate?: {
|
||||
id: string;
|
||||
title: string;
|
||||
slug: string;
|
||||
content_type: string;
|
||||
translation_key: string;
|
||||
frontend_url: string;
|
||||
} | null;
|
||||
}
|
||||
export type LearningSequence = Omit<
|
||||
LearningSequenceObjectType,
|
||||
"content_type" | "learning_units"
|
||||
> & {
|
||||
content_type: "learnpath.LearningSequence";
|
||||
learning_units: LearningUnit[];
|
||||
};
|
||||
|
||||
export interface LearningContentAttendanceCourse extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentAttendanceCourse";
|
||||
}
|
||||
export type CircleType = Omit<
|
||||
CircleObjectType,
|
||||
"content_type" | "learning_sequences"
|
||||
> & {
|
||||
content_type: "learnpath.Circle";
|
||||
learning_sequences: LearningSequence[];
|
||||
};
|
||||
|
||||
export interface LearningContentDocument {
|
||||
readonly type: "document";
|
||||
readonly id: string;
|
||||
readonly value: MediaLibraryContentBlockValue;
|
||||
}
|
||||
export type TopicType = Omit<TopicObjectType, "content_type" | "circles"> & {
|
||||
content_type: "learnpath.Topic";
|
||||
circles: CircleType[];
|
||||
};
|
||||
|
||||
export interface LearningContentDocumentList extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentDocumentList";
|
||||
readonly documents: LearningContentDocument[];
|
||||
}
|
||||
|
||||
export interface LearningContentFeedback extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentFeedback";
|
||||
}
|
||||
|
||||
export interface LearningContentLearningModule extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentLearningModule";
|
||||
}
|
||||
|
||||
export interface LearningContentMediaLibrary extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentMediaLibrary";
|
||||
}
|
||||
|
||||
export interface LearningContentPlaceholder extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentPlaceholder";
|
||||
}
|
||||
|
||||
export interface LearningContentRichText extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentRichText";
|
||||
readonly text: string;
|
||||
}
|
||||
|
||||
export interface LearningContentEdoniqTest extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentEdoniqTest";
|
||||
readonly checkbox_text: string;
|
||||
readonly has_extended_time_test: boolean;
|
||||
readonly content_assignment_id: string;
|
||||
readonly competence_certificate?: {
|
||||
id: string;
|
||||
title: string;
|
||||
slug: string;
|
||||
content_type: string;
|
||||
translation_key: string;
|
||||
frontend_url: string;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export interface LearningContentVideo extends LearningContentInterface {
|
||||
readonly content_type: "learnpath.LearningContentVideo";
|
||||
}
|
||||
export type LearningPathType = Omit<
|
||||
LearningPathObjectType,
|
||||
"content_type" | "topics"
|
||||
> & {
|
||||
content_type: "learnpath.LearningPath";
|
||||
topics: TopicType[];
|
||||
};
|
||||
|
||||
export interface LearningUnitPerformanceCriteria extends BaseCourseWagtailPage {
|
||||
readonly content_type: "competence.PerformanceCriteria";
|
||||
|
|
@ -132,66 +143,6 @@ export interface LearningUnitPerformanceCriteria extends BaseCourseWagtailPage {
|
|||
parentLearningUnit?: LearningUnit;
|
||||
}
|
||||
|
||||
export interface LearningUnit extends BaseCourseWagtailPage {
|
||||
readonly content_type: "learnpath.LearningUnit";
|
||||
readonly evaluate_url: string;
|
||||
readonly course_category: CourseCategory;
|
||||
readonly title_hidden: boolean;
|
||||
children: LearningUnitPerformanceCriteria[];
|
||||
|
||||
// additional frontend fields
|
||||
learningContents: LearningContent[];
|
||||
minutes: number;
|
||||
parentLearningSequence?: LearningSequence;
|
||||
parentCircle?: Circle;
|
||||
last?: boolean;
|
||||
}
|
||||
|
||||
export interface LearningSequence extends BaseCourseWagtailPage {
|
||||
readonly content_type: "learnpath.LearningSequence";
|
||||
icon: string;
|
||||
learningUnits: LearningUnit[];
|
||||
minutes: number;
|
||||
}
|
||||
|
||||
export type CircleChild = LearningContentInterface | LearningUnit | LearningSequence;
|
||||
|
||||
export interface WagtailLearningPath extends BaseCourseWagtailPage {
|
||||
readonly content_type: "learnpath.LearningPath";
|
||||
course: Course;
|
||||
children: LearningPathChild[];
|
||||
}
|
||||
|
||||
export interface CircleGoal {
|
||||
type: "goal";
|
||||
value: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface CircleJobSituation {
|
||||
type: "job_situation";
|
||||
value: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface WagtailCircle extends BaseCourseWagtailPage {
|
||||
readonly content_type: "learnpath.Circle";
|
||||
readonly description: string;
|
||||
readonly goal_description: string;
|
||||
readonly goals: CircleGoal[];
|
||||
readonly job_situation_description: string;
|
||||
readonly job_situations: CircleJobSituation[];
|
||||
readonly children: CircleChild[];
|
||||
}
|
||||
|
||||
export interface Topic extends BaseCourseWagtailPage {
|
||||
readonly content_type: "learnpath.Topic";
|
||||
readonly is_visible: boolean;
|
||||
circles: Circle[];
|
||||
}
|
||||
|
||||
export type LearningPathChild = Topic | WagtailCircle;
|
||||
|
||||
export interface CourseCompletion {
|
||||
readonly id: string;
|
||||
created_at: string;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@ export function assertUnreachable(msg: string): never {
|
|||
throw new Error("Didn't expect to get here, " + msg);
|
||||
}
|
||||
|
||||
export function stringifyParse(obj: any): any {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
function createCourseUrl(courseSlug: string | undefined, specificSub: string): string {
|
||||
if (!courseSlug) {
|
||||
return "/";
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class CompetenceCertificateListObjectType(DjangoObjectType):
|
|||
class Meta:
|
||||
model = CompetenceCertificateList
|
||||
interfaces = (CoursePageInterface,)
|
||||
fields = []
|
||||
|
||||
def resolve_competence_certificates(self, info):
|
||||
return CompetenceCertificate.objects.child_of(self)
|
||||
|
|
|
|||
|
|
@ -124,15 +124,21 @@ class LearningContentMediaLibraryObjectType(DjangoObjectType):
|
|||
|
||||
|
||||
class LearningContentEdoniqTestObjectType(DjangoObjectType):
|
||||
competence_certificate = graphene.Field(
|
||||
"vbv_lernwelt.competence.graphql.types.CompetenceCertificateObjectType",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = LearningContentEdoniqTest
|
||||
interfaces = (
|
||||
CoursePageInterface,
|
||||
LearningContentInterface,
|
||||
)
|
||||
fields = [
|
||||
"content_assignment",
|
||||
]
|
||||
fields = ["content_assignment", "checkbox_text", "has_extended_time_test"]
|
||||
|
||||
@staticmethod
|
||||
def resolve_competence_certificate(root: LearningContentEdoniqTest, info):
|
||||
return root.content_assignment.competence_certificate
|
||||
|
||||
|
||||
class LearningContentRichTextObjectType(DjangoObjectType):
|
||||
|
|
@ -146,6 +152,10 @@ class LearningContentRichTextObjectType(DjangoObjectType):
|
|||
|
||||
|
||||
class LearningContentAssignmentObjectType(DjangoObjectType):
|
||||
competence_certificate = graphene.Field(
|
||||
"vbv_lernwelt.competence.graphql.types.CompetenceCertificateObjectType",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = LearningContentAssignment
|
||||
interfaces = (
|
||||
|
|
@ -157,6 +167,10 @@ class LearningContentAssignmentObjectType(DjangoObjectType):
|
|||
"assignment_type",
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def resolve_competence_certificate(root: LearningContentAssignment, info):
|
||||
return root.content_assignment.competence_certificate
|
||||
|
||||
|
||||
class LearningContentDocumentListObjectType(DjangoObjectType):
|
||||
class Meta:
|
||||
|
|
@ -177,7 +191,7 @@ class LearningUnitObjectType(DjangoObjectType):
|
|||
class Meta:
|
||||
model = LearningUnit
|
||||
interfaces = (CoursePageInterface,)
|
||||
fields = ["evaluate_url"]
|
||||
fields = ["evaluate_url", "title_hidden"]
|
||||
|
||||
@staticmethod
|
||||
def resolve_evaluate_url(root: LearningUnit, info, **kwargs):
|
||||
|
|
@ -207,7 +221,9 @@ class LearningUnitObjectType(DjangoObjectType):
|
|||
|
||||
|
||||
class LearningSequenceObjectType(DjangoObjectType):
|
||||
learning_units = graphene.List(LearningUnitObjectType)
|
||||
learning_units = graphene.List(
|
||||
graphene.NonNull(LearningUnitObjectType), required=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = LearningSequence
|
||||
|
|
@ -236,7 +252,9 @@ class LearningSequenceObjectType(DjangoObjectType):
|
|||
|
||||
|
||||
class CircleObjectType(DjangoObjectType):
|
||||
learning_sequences = graphene.List(LearningSequenceObjectType)
|
||||
learning_sequences = graphene.List(
|
||||
graphene.NonNull(LearningSequenceObjectType), required=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Circle
|
||||
|
|
@ -273,7 +291,7 @@ class CircleObjectType(DjangoObjectType):
|
|||
|
||||
|
||||
class TopicObjectType(DjangoObjectType):
|
||||
circles = graphene.List(CircleObjectType)
|
||||
circles = graphene.List(graphene.NonNull(CircleObjectType), required=True)
|
||||
|
||||
class Meta:
|
||||
model = Topic
|
||||
|
|
@ -305,11 +323,12 @@ class TopicObjectType(DjangoObjectType):
|
|||
|
||||
|
||||
class LearningPathObjectType(DjangoObjectType):
|
||||
topics = graphene.List(TopicObjectType)
|
||||
topics = graphene.List(graphene.NonNull(TopicObjectType), required=True)
|
||||
|
||||
class Meta:
|
||||
model = LearningPath
|
||||
interfaces = (CoursePageInterface,)
|
||||
fields = []
|
||||
|
||||
@staticmethod
|
||||
def resolve_topics(root: LearningPath, info, **kwargs):
|
||||
|
|
|
|||
Loading…
Reference in New Issue