Refactor code to use `useCourseSessionDetailQuery`
This commit is contained in:
parent
06d284b1ce
commit
f75590dd0b
|
|
@ -48,12 +48,30 @@ export function useCourseSessionDetailQuery(courSessionId?: string | number) {
|
|||
return queryResult.data.value?.course_session as CourseSessionDetail | undefined;
|
||||
});
|
||||
|
||||
function findAssignmentDetail(assignmentId: string) {
|
||||
function findAssignmentByAssignmentId(assignmentId: string) {
|
||||
return (courseSessionDetail.value?.assignments ?? []).find((a) => {
|
||||
return a.learning_content?.content_assignment?.id === assignmentId;
|
||||
});
|
||||
}
|
||||
|
||||
function findAssignment(learningContentId: string) {
|
||||
return (courseSessionDetail.value?.assignments ?? []).find((a) => {
|
||||
return a.learning_content.id === learningContentId;
|
||||
});
|
||||
}
|
||||
|
||||
function findEdoniqTest(learningContentId: string) {
|
||||
return (courseSessionDetail.value?.edoniq_tests ?? []).find((e) => {
|
||||
return e.learning_content.id === learningContentId;
|
||||
});
|
||||
}
|
||||
|
||||
function findAttendanceCourse(learningContentId: string) {
|
||||
return (courseSessionDetail.value?.attendance_courses ?? []).find((e) => {
|
||||
return e.learning_content.id === learningContentId;
|
||||
});
|
||||
}
|
||||
|
||||
function findUser(userId: string) {
|
||||
return (courseSessionDetail.value?.users ?? []).find((u) => {
|
||||
return u.user_id === userId;
|
||||
|
|
@ -72,6 +90,12 @@ export function useCourseSessionDetailQuery(courSessionId?: string | number) {
|
|||
});
|
||||
}
|
||||
|
||||
function filterCircleExperts(circleSlug: string) {
|
||||
return (courseSessionDetail.value?.users ?? []).filter((u) => {
|
||||
return u.role === "EXPERT" && u.circles.map((c) => c.slug).includes(circleSlug);
|
||||
});
|
||||
}
|
||||
|
||||
const dataLoaded = ref(false);
|
||||
|
||||
function waitForData() {
|
||||
|
|
@ -89,9 +113,13 @@ export function useCourseSessionDetailQuery(courSessionId?: string | number) {
|
|||
...queryResult,
|
||||
courseSessionDetail,
|
||||
waitForData,
|
||||
findAssignmentDetail,
|
||||
findAssignmentByAssignmentId,
|
||||
findAssignment,
|
||||
findEdoniqTest,
|
||||
findAttendanceCourse,
|
||||
findUser,
|
||||
findCurrentUser,
|
||||
filterMembers,
|
||||
filterCircleExperts,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }\n }\n": types.AssignmentCompletionQueryDocument,
|
||||
"\n query courseQuery($courseId: ID!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n": types.CourseQueryDocument,
|
||||
"\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 title\n id\n slug\n content_type\n frontend_url\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 }\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 }\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 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 competenceCertificateQuery($courseSlu
|
|||
/**
|
||||
* 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 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 }\n }\n }\n }\n"): (typeof documents)["\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 }\n }\n }\n }\n"];
|
||||
export function graphql(source: "\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"): (typeof documents)["\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"];
|
||||
/**
|
||||
* 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
|
|
@ -197,6 +197,11 @@ export const COURSE_SESSION_DETAIL_QUERY = graphql(`
|
|||
learning_content {
|
||||
id
|
||||
title
|
||||
content_assignment {
|
||||
id
|
||||
title
|
||||
assignment_type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,9 @@ function editTask(task: AssignmentEvaluationTask) {
|
|||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
|
||||
const assignmentDetail = computed(() => {
|
||||
return courseSessionDetailResult.findAssignmentDetail(props.assignment.id.toString());
|
||||
return courseSessionDetailResult.findAssignmentByAssignmentId(
|
||||
props.assignment.id.toString()
|
||||
);
|
||||
});
|
||||
|
||||
const dueDate = computed(() =>
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ const state = reactive({
|
|||
});
|
||||
|
||||
const assignmentDetail = computed(() => {
|
||||
return courseSessionDetailResult.findAssignmentDetail(
|
||||
props.learningContentAssignment.content_assignment_id.toString()
|
||||
return courseSessionDetailResult.findAssignment(
|
||||
props.learningContentAssignment.id.toString()
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { useCircleStore } from "@/stores/circle";
|
||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||
import type { CourseSessionUser } from "@/types";
|
||||
import { humanizeDuration } from "@/utils/humanizeDuration";
|
||||
import sumBy from "lodash/sumBy";
|
||||
|
|
@ -11,6 +10,7 @@ import CircleDiagram from "./CircleDiagram.vue";
|
|||
import CircleOverview from "./CircleOverview.vue";
|
||||
import DocumentSection from "./DocumentSection.vue";
|
||||
import LearningSequence from "./LearningSequence.vue";
|
||||
import { useCourseSessionDetailQuery } from "@/composables";
|
||||
|
||||
export interface Props {
|
||||
courseSlug: string;
|
||||
|
|
@ -20,7 +20,8 @@ export interface Props {
|
|||
}
|
||||
|
||||
const route = useRoute();
|
||||
const courseSessionsStore = useCourseSessionsStore();
|
||||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
const circleStore = useCircleStore();
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
readonly: false,
|
||||
|
|
@ -29,7 +30,12 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
|
||||
log.debug("CirclePage created", props.readonly, props.profileUser);
|
||||
|
||||
const circleStore = useCircleStore();
|
||||
const circleExperts = computed(() => {
|
||||
if (circleStore.circle) {
|
||||
return courseSessionDetailResult.filterCircleExperts(circleStore.circle.slug);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const duration = computed(() => {
|
||||
if (circleStore.circle) {
|
||||
|
|
@ -190,10 +196,7 @@ onMounted(async () => {
|
|||
})
|
||||
}}
|
||||
</div>
|
||||
<div
|
||||
v-for="expert in courseSessionsStore.circleExperts"
|
||||
:key="expert.user_id"
|
||||
>
|
||||
<div v-for="expert in circleExperts" :key="expert.user_id">
|
||||
<div class="mb-2 mt-2 flex flex-row items-center">
|
||||
<img
|
||||
class="mr-2 h-[45px] rounded-full"
|
||||
|
|
@ -205,8 +208,8 @@ onMounted(async () => {
|
|||
</div>
|
||||
</div>
|
||||
<a
|
||||
v-if="courseSessionsStore.circleExperts.length > 0"
|
||||
:href="'mailto:' + courseSessionsStore.circleExperts[0].email"
|
||||
v-if="circleExperts.length > 0"
|
||||
:href="'mailto:' + circleExperts[0].email"
|
||||
class="btn-secondary mt-4 text-xl"
|
||||
>
|
||||
{{ $t("circlePage.contactExpertButton") }}
|
||||
|
|
|
|||
|
|
@ -2,19 +2,19 @@
|
|||
import DateEmbedding from "@/components/dueDates/DateEmbedding.vue";
|
||||
import type { Assignment } from "@/types";
|
||||
import { useRouteQuery } from "@vueuse/router";
|
||||
import type { Dayjs } from "dayjs";
|
||||
import log from "loglevel";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
interface Props {
|
||||
assignment: Assignment;
|
||||
dueDate?: Dayjs;
|
||||
submissionDeadlineStart?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
dueDate: undefined,
|
||||
submissionDeadlineStart: "",
|
||||
});
|
||||
|
||||
log.debug("AssignmentIntroductionView created", props.assignment, props.dueDate);
|
||||
log.debug("AssignmentIntroductionView created", props.assignment);
|
||||
|
||||
const step = useRouteQuery("step");
|
||||
</script>
|
||||
|
|
@ -40,9 +40,10 @@ const step = useRouteQuery("step");
|
|||
</ul>
|
||||
|
||||
<h3 class="mb-4 mt-8">{{ $t("assignment.dueDateSubmission") }}</h3>
|
||||
<p v-if="props.dueDate?.toString() === 'Invalid Date'" class="text-large">
|
||||
|
||||
<p v-if="submissionDeadlineStart" class="text-large">
|
||||
{{ $t("assignment.dueDateIntroduction") }}
|
||||
<DateEmbedding :single-date="dueDate"></DateEmbedding>
|
||||
<DateEmbedding :single-date="dayjs(submissionDeadlineStart)"></DateEmbedding>
|
||||
</p>
|
||||
<p v-else class="text-large">
|
||||
{{ $t("assignment.dueDateNotSet") }}
|
||||
|
|
|
|||
|
|
@ -3,34 +3,36 @@ import DateEmbedding from "@/components/dueDates/DateEmbedding.vue";
|
|||
import ItButton from "@/components/ui/ItButton.vue";
|
||||
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
||||
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables";
|
||||
import { bustItGetCache } from "@/fetchHelpers";
|
||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||
import AssignmentSubmissionResponses from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionResponses.vue";
|
||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import type { Assignment, AssignmentCompletion, AssignmentTask } from "@/types";
|
||||
import { useMutation } from "@urql/vue";
|
||||
import type { Dayjs } from "dayjs";
|
||||
import log from "loglevel";
|
||||
import { computed, reactive } from "vue";
|
||||
import { useTranslation } from "i18next-vue";
|
||||
import eventBus from "@/utils/eventBus";
|
||||
import dayjs from "dayjs";
|
||||
import { useCircleStore } from "@/stores/circle";
|
||||
|
||||
const props = defineProps<{
|
||||
assignment: Assignment;
|
||||
learningContentId: number;
|
||||
assignmentCompletion?: AssignmentCompletion;
|
||||
courseSessionId: number;
|
||||
dueDate: Dayjs;
|
||||
submissionDeadlineStart?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "editTask", task: AssignmentTask): void;
|
||||
}>();
|
||||
|
||||
const courseSessionsStore = useCourseSessionsStore();
|
||||
const courseSession = useCurrentCourseSession();
|
||||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
const circleStore = useCircleStore();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const state = reactive({
|
||||
|
|
@ -38,8 +40,15 @@ const state = reactive({
|
|||
confirmPerson: false,
|
||||
});
|
||||
|
||||
const circleExperts = computed(() => {
|
||||
if (circleStore.circle) {
|
||||
return courseSessionDetailResult.filterCircleExperts(circleStore.circle.slug);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const circleExpert = computed(() => {
|
||||
return courseSessionsStore.circleExperts[0];
|
||||
return circleExperts.value[0];
|
||||
});
|
||||
|
||||
const circleExpertName = computed(() => {
|
||||
|
|
@ -138,9 +147,11 @@ const onSubmit = async () => {
|
|||
{{ $t("assignment.showAssessmentDocument") }}
|
||||
</a>
|
||||
</div>
|
||||
<p v-if="isCasework" class="pt-6">
|
||||
<p v-if="isCasework && props.submissionDeadlineStart" class="pt-6">
|
||||
{{ $t("assignment.dueDateSubmission") }}
|
||||
<DateEmbedding :single-date="dueDate"></DateEmbedding>
|
||||
<DateEmbedding
|
||||
:single-date="dayjs(props.submissionDeadlineStart)"
|
||||
></DateEmbedding>
|
||||
</p>
|
||||
<ItButton
|
||||
class="mt-6"
|
||||
|
|
|
|||
|
|
@ -1,26 +1,22 @@
|
|||
<script setup lang="ts">
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables";
|
||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
||||
import AssignmentIntroductionView from "@/pages/learningPath/learningContentPage/assignment/AssignmentIntroductionView.vue";
|
||||
import AssignmentSubmissionView from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionView.vue";
|
||||
import AssignmentTaskView from "@/pages/learningPath/learningContentPage/assignment/AssignmentTaskView.vue";
|
||||
import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue";
|
||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import type {
|
||||
Assignment,
|
||||
AssignmentCompletion,
|
||||
AssignmentTask,
|
||||
CourseSessionAssignment,
|
||||
CourseSessionUser,
|
||||
LearningContentAssignment,
|
||||
} from "@/types";
|
||||
import { useMutation, useQuery } from "@urql/vue";
|
||||
import { useRouteQuery } from "@vueuse/router";
|
||||
import dayjs from "dayjs";
|
||||
import * as log from "loglevel";
|
||||
import { computed, onMounted, reactive, ref, watchEffect } from "vue";
|
||||
import { computed, onMounted, ref, watchEffect } from "vue";
|
||||
import { useTranslation } from "i18next-vue";
|
||||
import { bustItGetCache } from "@/fetchHelpers";
|
||||
import { learningContentTypeData } from "@/utils/typeMaps";
|
||||
|
|
@ -30,14 +26,6 @@ const { t } = useTranslation();
|
|||
const courseSession = useCurrentCourseSession();
|
||||
const userStore = useUserStore();
|
||||
|
||||
interface State {
|
||||
courseSessionAssignment: CourseSessionAssignment | undefined;
|
||||
}
|
||||
|
||||
const state: State = reactive({
|
||||
courseSessionAssignment: undefined,
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
learningContent: LearningContentAssignment;
|
||||
}>();
|
||||
|
|
@ -52,10 +40,17 @@ const queryResult = useQuery({
|
|||
pause: true,
|
||||
});
|
||||
|
||||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
|
||||
const upsertAssignmentCompletionMutation = useMutation(
|
||||
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
|
||||
);
|
||||
|
||||
const submissionDeadline = computed(() => {
|
||||
return courseSessionDetailResult.findAssignment(props.learningContent.id.toString())
|
||||
?.submission_deadline;
|
||||
});
|
||||
|
||||
// FIXME daniel: `useRouteQuery` from usevue is currently the reason that we have to
|
||||
// fix the version of @vueuse/router and @vueuse/core to 10.1.0
|
||||
// it fails with version 10.2.0. I have a reminder to check out the situation
|
||||
|
|
@ -104,10 +99,6 @@ onMounted(async () => {
|
|||
props.learningContent
|
||||
);
|
||||
|
||||
state.courseSessionAssignment = useCourseSessionsStore().findCourseSessionAssignment(
|
||||
props.learningContent.id
|
||||
);
|
||||
|
||||
// create initial `AssignmentCompletion` first, so that it exists and we don't
|
||||
// have reactivity problem accessing it.
|
||||
await initUpsertAssignmentCompletion();
|
||||
|
|
@ -120,9 +111,7 @@ const numPages = computed(() => {
|
|||
});
|
||||
const showPreviousButton = computed(() => stepIndex.value != 0);
|
||||
const showNextButton = computed(() => stepIndex.value + 1 < numPages.value);
|
||||
const dueDate = computed(() =>
|
||||
dayjs(state.courseSessionAssignment?.submission_deadline_start)
|
||||
);
|
||||
|
||||
const currentTask = computed(() => {
|
||||
if (stepIndex.value > 0 && stepIndex.value <= numTasks.value) {
|
||||
return assignment.value?.tasks[stepIndex.value - 1];
|
||||
|
|
@ -194,9 +183,9 @@ const subTitle = computed(() => {
|
|||
});
|
||||
|
||||
const assignmentUser = computed(() => {
|
||||
return courseSession.value.users.find(
|
||||
(user) => user.user_id === userStore.id
|
||||
) as CourseSessionUser;
|
||||
return (courseSessionDetailResult.courseSessionDetail.value?.users ?? []).find(
|
||||
(u) => u.user_id === userStore.id
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
@ -204,7 +193,7 @@ const assignmentUser = computed(() => {
|
|||
<div v-if="queryResult.fetching.value"></div>
|
||||
<div v-else-if="queryResult.error.value">{{ queryResult.error.value }}</div>
|
||||
<div v-else>
|
||||
<div v-if="assignment && assignmentCompletion">
|
||||
<div v-if="assignment && assignmentCompletion && assignmentUser">
|
||||
<div class="flex flex-col lg:flex-row">
|
||||
<div
|
||||
v-if="assignmentCompletion?.completion_status === 'EVALUATION_SUBMITTED'"
|
||||
|
|
@ -239,8 +228,8 @@ const assignmentUser = computed(() => {
|
|||
<div>
|
||||
<AssignmentIntroductionView
|
||||
v-if="stepIndex === 0"
|
||||
:due-date="dueDate"
|
||||
:assignment="assignment"
|
||||
:submission-deadline-start="submissionDeadline?.start"
|
||||
></AssignmentIntroductionView>
|
||||
<AssignmentTaskView
|
||||
v-else-if="currentTask"
|
||||
|
|
@ -251,11 +240,11 @@ const assignmentUser = computed(() => {
|
|||
></AssignmentTaskView>
|
||||
<AssignmentSubmissionView
|
||||
v-else-if="stepIndex + 1 === numPages"
|
||||
:due-date="dueDate"
|
||||
:assignment="assignment"
|
||||
:assignment-completion="assignmentCompletion"
|
||||
:learning-content-id="props.learningContent.id"
|
||||
:course-session-id="courseSession.id"
|
||||
:submission-deadline-start="submissionDeadline?.start"
|
||||
@edit-task="jumpToTask($event)"
|
||||
></AssignmentSubmissionView>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@
|
|||
<it-icon-calendar-light class="w-[60px] grid-in-icon" />
|
||||
<h2 class="text-large font-bold grid-in-title">{{ $t("a.Datum") }}</h2>
|
||||
<p class="grid-in-value">
|
||||
{{ formatDueDate(props.attendanceCourse.start, props.attendanceCourse.end) }}
|
||||
{{
|
||||
formatDueDate(
|
||||
props.attendanceCourse.due_date.start,
|
||||
props.attendanceCourse.due_date.end
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="mb-12 grid grid-cols-icon-card gap-x-4 grid-areas-icon-card">
|
||||
|
|
@ -24,8 +29,6 @@
|
|||
<script setup lang="ts">
|
||||
import { formatDueDate } from "@/components/dueDates/dueDatesUtils";
|
||||
import type { CourseSessionAttendanceCourse } from "@/types";
|
||||
import dayjs from "dayjs";
|
||||
import LocalizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import { computed } from "vue";
|
||||
|
||||
export interface Props {
|
||||
|
|
@ -34,7 +37,6 @@ export interface Props {
|
|||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
dayjs.extend(LocalizedFormat);
|
||||
const location = computed(() => props.attendanceCourse.location);
|
||||
const trainer = computed(() => props.attendanceCourse.trainer);
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
import AttendanceCourse from "@/pages/learningPath/learningContentPage/attendanceCourse/AttendanceCourse.vue";
|
||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||
import type { LearningContentAttendanceCourse } from "@/types";
|
||||
import { computed } from "vue";
|
||||
import LearningContentSimpleLayout from "../layouts/LearningContentSimpleLayout.vue";
|
||||
|
||||
const courseSessionsStore = useCourseSessionsStore();
|
||||
import { useCourseSessionDetailQuery } from "@/composables";
|
||||
|
||||
const props = defineProps<{
|
||||
content: LearningContentAttendanceCourse;
|
||||
}>();
|
||||
|
||||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
|
||||
const courseSessionAttendanceCourse = computed(() => {
|
||||
return courseSessionsStore.findAttendanceCourse(props.content.id);
|
||||
return courseSessionDetailResult.findAttendanceCourse(props.content.id.toString());
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ import * as log from "loglevel";
|
|||
import { itPost } from "@/fetchHelpers";
|
||||
import { useQuery } from "@urql/vue";
|
||||
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables";
|
||||
import dayjs from "dayjs";
|
||||
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
|
||||
import {
|
||||
|
|
@ -24,10 +23,10 @@ const props = defineProps<{
|
|||
}>();
|
||||
|
||||
const courseSession = useCurrentCourseSession();
|
||||
const courseSessionsStore = useCourseSessionsStore();
|
||||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
|
||||
const courseSessionEdoniqTest = computed(() => {
|
||||
return courseSessionsStore.findCourseSessionEdoniqTest(props.content.id);
|
||||
return courseSessionDetailResult.findEdoniqTest(props.content.id.toString());
|
||||
});
|
||||
|
||||
const queryResult = useQuery({
|
||||
|
|
@ -53,7 +52,7 @@ const extendedTimeTest = ref(false);
|
|||
|
||||
const deadlineInPast = computed(() => {
|
||||
// with 16 minutes buffer
|
||||
return dayjs(courseSessionEdoniqTest.value?.deadline_start)
|
||||
return dayjs(courseSessionEdoniqTest.value?.deadline.start)
|
||||
.add(16, "minute")
|
||||
.isBefore(dayjs());
|
||||
});
|
||||
|
|
@ -90,7 +89,7 @@ async function startTest() {
|
|||
<p class="mt-2 text-lg">
|
||||
{{
|
||||
$t("edoniqTest.submitDateDescription", {
|
||||
x: formatDueDate(courseSessionEdoniqTest.deadline_start),
|
||||
x: formatDueDate(courseSessionEdoniqTest.deadline.start),
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
|
|
@ -158,7 +157,7 @@ async function startTest() {
|
|||
</div>
|
||||
<div v-else>
|
||||
{{ $t("a.Abgabetermin") }}:
|
||||
{{ getDateString(dayjs(courseSessionEdoniqTest?.deadline_start)) }}
|
||||
{{ getDateString(dayjs(courseSessionEdoniqTest?.deadline.start)) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,21 +10,21 @@ import {
|
|||
} from "@/pages/learningPath/learningContentPage/feedback/feedback.constants";
|
||||
import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue";
|
||||
import { useCircleStore } from "@/stores/circle";
|
||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||
import type { LearningContentFeedback } from "@/types";
|
||||
import { useMutation } from "@urql/vue";
|
||||
import { useRouteQuery } from "@vueuse/router";
|
||||
import log from "loglevel";
|
||||
import { computed, onMounted, reactive, ref } from "vue";
|
||||
import { useTranslation } from "i18next-vue";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables";
|
||||
|
||||
const props = defineProps<{
|
||||
content: LearningContentFeedback;
|
||||
}>();
|
||||
const courseSessionsStore = useCourseSessionsStore();
|
||||
const courseSession = useCurrentCourseSession();
|
||||
const circleStore = useCircleStore();
|
||||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const stepNo = useRouteQuery("step", "0", { transform: Number, mode: "push" });
|
||||
|
|
@ -33,6 +33,13 @@ const title = computed(
|
|||
() => `«${circleStore.circle?.title}»: ${t("feedback.areYouSatisfied")}`
|
||||
);
|
||||
|
||||
const circleExperts = computed(() => {
|
||||
if (circleStore.circle) {
|
||||
return courseSessionDetailResult.filterCircleExperts(circleStore.circle.slug);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const stepLabels = [
|
||||
t("general.introduction"),
|
||||
t("feedback.satisfactionLabel"),
|
||||
|
|
@ -244,7 +251,7 @@ onMounted(async () => {
|
|||
<p v-if="stepNo === 0" class="mt-10">
|
||||
{{
|
||||
$t("feedback.intro", {
|
||||
name: `${courseSessionsStore.circleExperts[0]?.first_name} ${courseSessionsStore.circleExperts[0]?.last_name}`,
|
||||
name: `${circleExperts[0]?.first_name} ${circleExperts[0]?.last_name}`,
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
|
|
@ -265,10 +272,10 @@ onMounted(async () => {
|
|||
</div>
|
||||
<FeedbackCompletition
|
||||
v-if="stepNo === 11"
|
||||
:avatar-url="courseSessionsStore.circleExperts[0].avatar_url"
|
||||
:avatar-url="circleExperts[0].avatar_url"
|
||||
:title="
|
||||
$t('feedback.completionTitle', {
|
||||
name: `${courseSessionsStore.circleExperts[0].first_name} ${courseSessionsStore.circleExperts[0].last_name}`,
|
||||
name: `${circleExperts[0].first_name} ${circleExperts[0].last_name}`,
|
||||
})
|
||||
"
|
||||
:description="$t('feedback.completionDescription')"
|
||||
|
|
|
|||
|
|
@ -147,23 +147,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
|||
return Boolean(isCourseExpert && (inLearningPath() || inCompetenceProfile()));
|
||||
});
|
||||
|
||||
// const circleExperts = computed(() => {
|
||||
// const circleStore = useCircleStore();
|
||||
// const circleTranslationKey = circleStore.circle?.translation_key;
|
||||
//
|
||||
// if (currentCourseSession.value && circleTranslationKey) {
|
||||
// return currentCourseSession.value.users.filter((u) => {
|
||||
// if (u.role === "EXPERT") {
|
||||
// return (u as ExpertSessionUser).circles
|
||||
// .map((c) => c.translation_key)
|
||||
// .includes(circleTranslationKey);
|
||||
// }
|
||||
// return false;
|
||||
// }) as ExpertSessionUser[];
|
||||
// }
|
||||
// return [];
|
||||
// });
|
||||
|
||||
// const canUploadCircleDocuments = computed(() => {
|
||||
// const userStore = useUserStore();
|
||||
// return (
|
||||
|
|
@ -249,36 +232,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
|||
);
|
||||
}
|
||||
|
||||
// function findAttendanceCourse(
|
||||
// contentId: number
|
||||
// ): CourseSessionAttendanceCourse | undefined {
|
||||
// if (currentCourseSession.value) {
|
||||
// return currentCourseSession.value.attendance_courses.find(
|
||||
// (attendanceCourse) => attendanceCourse.learning_content_id === contentId
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// function findCourseSessionAssignment(
|
||||
// contentId?: number
|
||||
// ): CourseSessionAssignment | undefined {
|
||||
// if (contentId && currentCourseSession.value) {
|
||||
// return currentCourseSession.value.assignments.find(
|
||||
// (a) => a.learning_content_id === contentId
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// function findCourseSessionEdoniqTest(
|
||||
// contentId?: number
|
||||
// ): CourseSessionEdoniqTest | undefined {
|
||||
// if (contentId && currentCourseSession.value) {
|
||||
// return currentCourseSession.value.edoniq_tests.find(
|
||||
// (a) => a.learning_content_id === contentId
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
return {
|
||||
uniqueCourseSessionsByCourse,
|
||||
allCurrentCourseSessions,
|
||||
|
|
|
|||
|
|
@ -496,9 +496,15 @@ export interface CourseSessionAssignment {
|
|||
export interface CourseSessionEdoniqTest {
|
||||
id: number;
|
||||
course_session_id: number;
|
||||
learning_content_id: number;
|
||||
deadline_id: number;
|
||||
deadline_start: string;
|
||||
deadline: SimpleDueDate;
|
||||
learning_content: {
|
||||
id: string;
|
||||
content_assignment: {
|
||||
id: string;
|
||||
title: string;
|
||||
assignment_type: AssignmentType;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface CourseSession {
|
||||
|
|
@ -559,6 +565,7 @@ export interface CourseSessionDetail {
|
|||
};
|
||||
assignments: CourseSessionAssignment[];
|
||||
attendance_courses: CourseSessionAttendanceCourse[];
|
||||
edoniq_tests: CourseSessionEdoniqTest[];
|
||||
users: CourseSessionUser[];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,13 @@ from graphene_django import DjangoObjectType
|
|||
from graphql import GraphQLError
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
|
||||
from vbv_lernwelt.course.models import Course, CourseBasePage, CoursePage, \
|
||||
CourseSession, CourseSessionUser
|
||||
from vbv_lernwelt.course.models import (
|
||||
Course,
|
||||
CourseBasePage,
|
||||
CoursePage,
|
||||
CourseSession,
|
||||
CourseSessionUser,
|
||||
)
|
||||
from vbv_lernwelt.course.permissions import has_course_access
|
||||
from vbv_lernwelt.course_session.graphql.types import (
|
||||
CourseSessionAttendanceCourseObjectType,
|
||||
|
|
@ -134,9 +139,7 @@ class CourseSessionUserObjectsType(DjangoObjectType):
|
|||
return self.role
|
||||
|
||||
def resolve_circles(self, info):
|
||||
return self.expert.all().values(
|
||||
"id", "title", "slug", "translation_key"
|
||||
)
|
||||
return self.expert.all().values("id", "title", "slug", "translation_key")
|
||||
|
||||
|
||||
class CourseSessionObjectType(DjangoObjectType):
|
||||
|
|
@ -165,10 +168,8 @@ class CourseSessionObjectType(DjangoObjectType):
|
|||
def resolve_assignments(self, info):
|
||||
return CourseSessionAssignment.objects.filter(course_session=self)
|
||||
|
||||
def resolve_edoniq_test(self, info):
|
||||
def resolve_edoniq_tests(self, info):
|
||||
return CourseSessionEdoniqTest.objects.filter(course_session=self)
|
||||
|
||||
def resolve_users(self, info):
|
||||
return CourseSessionUser.objects.filter(
|
||||
course_session_id=self.id
|
||||
).distinct()
|
||||
return CourseSessionUser.objects.filter(course_session_id=self.id).distinct()
|
||||
|
|
|
|||
|
|
@ -7,16 +7,6 @@ from vbv_lernwelt.course.models import (
|
|||
CourseCompletion,
|
||||
CourseSession,
|
||||
)
|
||||
from vbv_lernwelt.course_session.models import (
|
||||
CourseSessionAssignment,
|
||||
CourseSessionAttendanceCourse,
|
||||
CourseSessionEdoniqTest,
|
||||
)
|
||||
from vbv_lernwelt.course_session.serializers import (
|
||||
CourseSessionAssignmentSerializer,
|
||||
CourseSessionAttendanceCourseSerializer,
|
||||
CourseSessionEdoniqTestSerializer,
|
||||
)
|
||||
from vbv_lernwelt.duedate.models import DueDate
|
||||
from vbv_lernwelt.duedate.serializers import DueDateSerializer
|
||||
|
||||
|
|
@ -73,39 +63,12 @@ class CourseSessionSerializer(serializers.ModelSerializer):
|
|||
def get_course_url(self, obj):
|
||||
return obj.course.get_course_url()
|
||||
|
||||
def get_learning_path_url(self, obj):
|
||||
return obj.course.get_learning_path_url()
|
||||
|
||||
def get_cockpit_url(self, obj):
|
||||
return obj.course.get_cockpit_url()
|
||||
|
||||
def get_media_library_url(self, obj):
|
||||
return obj.course.get_media_library_url()
|
||||
|
||||
def get_competence_url(self, obj):
|
||||
return obj.course.get_competence_url()
|
||||
|
||||
def get_documents(self, obj):
|
||||
documents = CircleDocument.objects.filter(
|
||||
course_session=obj, file__upload_finished_at__isnull=False
|
||||
)
|
||||
return CircleDocumentSerializer(documents, many=True).data
|
||||
|
||||
def get_attendance_courses(self, obj):
|
||||
return CourseSessionAttendanceCourseSerializer(
|
||||
CourseSessionAttendanceCourse.objects.filter(course_session=obj), many=True
|
||||
).data
|
||||
|
||||
def get_assignments(self, obj):
|
||||
return CourseSessionAssignmentSerializer(
|
||||
CourseSessionAssignment.objects.filter(course_session=obj), many=True
|
||||
).data
|
||||
|
||||
def get_edoniq_tests(self, obj):
|
||||
return CourseSessionEdoniqTestSerializer(
|
||||
CourseSessionEdoniqTest.objects.filter(course_session=obj), many=True
|
||||
).data
|
||||
|
||||
def get_due_dates(self, obj):
|
||||
due_dates = DueDate.objects.filter(course_session=obj)
|
||||
return DueDateSerializer(due_dates, many=True).data
|
||||
|
|
@ -120,16 +83,7 @@ class CourseSessionSerializer(serializers.ModelSerializer):
|
|||
"title",
|
||||
"start_date",
|
||||
"end_date",
|
||||
# "additional_json_data",
|
||||
# "attendance_courses",
|
||||
# "assignments",
|
||||
# "edoniq_tests",
|
||||
# "learning_path_url",
|
||||
# "cockpit_url",
|
||||
# "competence_url",
|
||||
# "media_library_url",
|
||||
"course_url",
|
||||
# "documents",
|
||||
"due_dates",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from vbv_lernwelt.course.permissions import is_course_session_expert
|
|||
from vbv_lernwelt.course_session.models import (
|
||||
CourseSessionAttendanceCourse,
|
||||
CourseSessionAssignment,
|
||||
CourseSessionEdoniqTest,
|
||||
)
|
||||
from vbv_lernwelt.course_session.services.attendance import AttendanceUserStatus
|
||||
from vbv_lernwelt.duedate.graphql.types import DueDateObjectType
|
||||
|
|
@ -39,7 +40,6 @@ class CourseSessionAttendanceCourseObjectType(DjangoObjectType):
|
|||
fields = (
|
||||
"id",
|
||||
"course_session_id",
|
||||
"learning_content_id",
|
||||
"learning_content",
|
||||
"location",
|
||||
"trainer",
|
||||
|
|
@ -64,10 +64,9 @@ class CourseSessionAssignmentObjectType(DjangoObjectType):
|
|||
fields = (
|
||||
"id",
|
||||
"course_session_id",
|
||||
"learning_content_id",
|
||||
"learning_content",
|
||||
"submission_deadline",
|
||||
"evaluation_deadline",
|
||||
"learning_content",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -78,11 +77,10 @@ class CourseSessionEdoniqTestObjectType(DjangoObjectType):
|
|||
learning_content = graphene.Field(LearningContentEdoniqTestObjectType)
|
||||
|
||||
class Meta:
|
||||
model = CourseSessionAssignment
|
||||
model = CourseSessionEdoniqTest
|
||||
fields = (
|
||||
"id",
|
||||
"course_session_id",
|
||||
"learning_content_id",
|
||||
"deadline",
|
||||
"learning_content",
|
||||
"deadline",
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue