VBV-514: Termine nur für ausgewählte Circles anzeigen im Cockpit

This commit is contained in:
Daniel Egger 2023-09-15 14:50:52 +02:00
parent f5d44bcb90
commit db40368244
9 changed files with 89 additions and 34 deletions

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { formatDate } from "@/components/dueDates/dueDatesUtils";
import { formatDueDate } from "@/components/dueDates/dueDatesUtils";
import type { DueDate } from "@/types";
const props = defineProps<{
@ -30,7 +30,7 @@ const props = defineProps<{
</div>
</div>
<div>
{{ formatDate(props.dueDate.start, props.dueDate.end) }}
{{ formatDueDate(props.dueDate.start, props.dueDate.end) }}
</div>
</div>
</template>

View File

@ -1,38 +1,45 @@
import type { Dayjs } from "dayjs";
import dayjs from "dayjs";
import LocalizedFormat from "dayjs/plugin/localizedFormat";
import i18next from "i18next";
export const formatDate = (start: Dayjs, end: Dayjs) => {
const startDateString = getDateString(start);
const endDateString = getDateString(end);
export const formatDueDate = (start: string, end: string) => {
dayjs.extend(LocalizedFormat);
const startDayjs = dayjs(start);
const endDayjs = dayjs(end);
const startDateString = getDateString(startDayjs);
const endDateString = getDateString(endDayjs);
// if start isundefined, dont show the day twice
// if startDayjs isundefined, dont show the day twice
if (!start.isValid() && !end.isValid()) {
if (!startDayjs.isValid() && !endDayjs.isValid()) {
return i18next.t("Termin nicht festgelegt");
}
if (!start || (!start.isValid() && end.isValid())) {
return `${endDateString} ${getTimeString(end)} ${end.format("[Uhr]")}`;
if (!startDayjs || (!startDayjs.isValid() && endDayjs.isValid())) {
return `${endDateString} ${getTimeString(endDayjs)} ${endDayjs.format("[Uhr]")}`;
}
if (!end || (!end.isValid() && start.isValid())) {
return `${startDateString} ${getTimeString(start)} ${start.format("[Uhr]")}`;
if (!endDayjs || (!endDayjs.isValid() && startDayjs.isValid())) {
return `${startDateString} ${getTimeString(startDayjs)} ${startDayjs.format(
"[Uhr]"
)}`;
}
// if start and end are on the same day, dont show the day twice
// if startDayjs and endDayjs are on the same day, dont show the day twice
if (startDateString === endDateString) {
return `${startDateString} ${getTimeString(start)} - ${getTimeString(
end
)} ${end.format("[Uhr]")}`;
return `${startDateString} ${getTimeString(startDayjs)} - ${getTimeString(
endDayjs
)} ${endDayjs.format("[Uhr]")}`;
}
return `${startDateString} ${getTimeString(start)} - ${endDateString} ${getTimeString(
end
)}`;
return `${startDateString} ${getTimeString(
startDayjs
)} - ${endDateString} ${getTimeString(endDayjs)}`;
};
export const getTimeString = (date?: Dayjs) => {
if (date) {
return `${date.format("H:mm")}`;
return `${date.format("HH:mm")}`;
}
return "";
};

View File

@ -1,22 +1,33 @@
<script setup lang="ts">
import { useCurrentCourseSession } from "@/composables";
import DueDateSingle from "@/components/dueDates/DueDateSingle.vue";
import { computed } from "vue";
import { useCockpitStore } from "@/stores/cockpit";
const cockpitStore = useCockpitStore();
const courseSession = useCurrentCourseSession();
const dueDates = courseSession.value.due_dates.slice(0, 2);
const circleDates = computed(() => {
const dueDates = courseSession.value.due_dates.filter((dueDate) => {
return cockpitStore.selectedCircles.includes(
dueDate?.circle?.translation_key ?? ""
);
});
return dueDates.slice(0, 4);
});
</script>
<template>
<div class="flex flex-col space-y-2">
<h3 class="heading-3">{{ $t("Nächste Termine") }}</h3>
<div
v-for="dueDate in dueDates"
v-for="dueDate in circleDates"
:key="dueDate.id"
class="border-t border-gray-500 pt-2"
>
<DueDateSingle :due-date="dueDate" :single-line="true"></DueDateSingle>
</div>
<div v-if="dueDates.length === 0">{{ $t("dueDates.noDueDatesAvailable") }}</div>
<div v-if="circleDates.length === 0">{{ $t("dueDates.noDueDatesAvailable") }}</div>
<a class="border-t border-gray-500 pt-8 underline" href="">
{{ $t("dueDates.showAllDueDates") }}
</a>

View File

@ -2,7 +2,9 @@
<div class="mb-12 grid grid-cols-icon-card gap-x-4 grid-areas-icon-card">
<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">{{ formatDate(start, end) }}</p>
<p class="grid-in-value">
{{ formatDueDate(props.attendanceCourse.start, props.attendanceCourse.end) }}
</p>
</div>
<div class="mb-12 grid grid-cols-icon-card gap-x-4 grid-areas-icon-card">
<it-icon-location class="w-[60px] grid-in-icon" />
@ -20,7 +22,7 @@
</template>
<script setup lang="ts">
import { formatDate } from "@/components/dueDates/dueDatesUtils";
import { formatDueDate } from "@/components/dueDates/dueDatesUtils";
import type { CourseSessionAttendanceCourse } from "@/types";
import dayjs from "dayjs";
import LocalizedFormat from "dayjs/plugin/localizedFormat";
@ -33,8 +35,6 @@ export interface Props {
const props = defineProps<Props>();
dayjs.extend(LocalizedFormat);
const start = computed(() => dayjs(props.attendanceCourse.start));
const end = computed(() => dayjs(props.attendanceCourse.end));
const location = computed(() => props.attendanceCourse.location);
const trainer = computed(() => props.attendanceCourse.trainer);
</script>

View File

@ -40,10 +40,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
reload: reload,
})) as CourseSessionUser[];
cs.users = users;
cs.due_dates.forEach((dueDate) => {
dueDate.start = dayjs(dueDate.start);
dueDate.end = dayjs(dueDate.end);
});
sortDueDates(cs.due_dates);
})
);

View File

@ -1,6 +1,5 @@
import type { AssignmentCompletionStatus as AssignmentCompletionStatusGenerated } from "@/gql/graphql";
import type { Circle } from "@/services/circle";
import type { Dayjs } from "dayjs";
import type { Component } from "vue";
export type LoginMethod = "local" | "sso";
@ -624,8 +623,8 @@ export interface UserAssignmentCompletionStatus {
export type DueDate = {
id: number;
start: Dayjs;
end: Dayjs;
start: string;
end: string;
title: string;
assignment_type_translation_key: string;
date_type_translation_key: string;
@ -633,4 +632,5 @@ export type DueDate = {
url: string;
course_session: number | null;
page: number | null;
circle: CircleLight | null;
};

View File

@ -103,6 +103,16 @@ class CourseBasePage(Page):
return course_parent_page.specific.course
return None
def get_circle(self):
from vbv_lernwelt.learnpath.models import Circle
try:
return self.get_ancestors().exact_type(Circle).first()
except Exception:
# noop
pass
return None
def get_circles(self):
course_parent_page = self.get_course_parent()

View File

@ -97,6 +97,13 @@ class DueDate(models.Model):
return datetime.timedelta(0)
return self.end - self.start
def get_circle(self):
try:
return self.page.specific.get_circle()
except Exception:
# noop
return None
@classmethod
def get_users_next_events_qs(
cls, user: User, course_session: CourseSession = None, limit=10

View File

@ -4,6 +4,30 @@ from vbv_lernwelt.duedate.models import DueDate
class DueDateSerializer(serializers.ModelSerializer):
circle = serializers.SerializerMethodField()
class Meta:
model = DueDate
fields = "__all__"
fields = [
"start",
"end",
"manual_override_fields",
"title",
"assignment_type_translation_key",
"date_type_translation_key",
"subtitle",
"url",
"course_session",
"page",
"circle",
]
def get_circle(self, obj):
circle = obj.get_circle()
if circle:
return {
"id": circle.id,
"title": circle.title,
"translation_key": circle.translation_key,
}
return None