diff --git a/src/Pages/Calendar.vue b/src/Pages/Calendar.vue index d095cdc055431b06d4dd8720a0cab12ccee32cd2..3962329ca97d432fd2ff03713aa88cd617b7b5a6 100644 --- a/src/Pages/Calendar.vue +++ b/src/Pages/Calendar.vue @@ -101,7 +101,7 @@ import { useRoute, useRouter } from 'vue-router' import { useI18n } from '@/i18n' import { useAuthStore, useRRuleStore, useShowStore, useTimeSlotStore } from '@/stores' import { SteeringUser, useHasUserPermission } from '@/stores/auth' -import { calculateDurationSeconds, getNextAvailableSlot, sanitizeHTML, useQuery } from '@/util' +import { ensureDate, getNextAvailableSlot, sanitizeHTML, useQuery } from '@/util' import { getISODateString } from '@/utilities' import AScheduleCreateDialog from '@/components/schedule/AScheduleCreateDialog.vue' @@ -181,10 +181,14 @@ const calendarEvents = computedAsync(async () => { const isEmpty = timeslot.playlistId === null const emptyText = isEmpty ? t('calendar.empty') : '' + const durationMinutes = + (ensureDate(timeslot.end).getTime() - ensureDate(timeslot.start).getTime()) / 1000 / 60 const show = await showStore.retrieve(timeslot.showId, { useCached: true }) const isOwner = show?.ownerIds?.includes?.(authStore?.steeringUser?.id as SteeringUser['id']) ?? false const className = ['calendar-event', isOwner ? 'is-mine' : 'is-not-mine'] + if (durationMinutes < 0) className.push('is-invalid') + const title = sanitizeHTML(show?.name ?? '') + ` (${emptyText})` const slot = { id: timeslot.id, @@ -195,8 +199,7 @@ const calendarEvents = computedAsync(async () => { extendedProps: { title, id: timeslot.id, - durationMinutes: - calculateDurationSeconds(parseISO(timeslot.start), parseISO(timeslot.end)) / 60, + durationMinutes: Math.abs(durationMinutes), }, } calendarEventsCache.set(cacheKey, slot) diff --git a/src/tailwind.css b/src/tailwind.css index c74dc17588aa23f44afffe52cc8756859e238174..deb1a39cb2993f6d94bce49d7c98ed105ffc8fd3 100644 --- a/src/tailwind.css +++ b/src/tailwind.css @@ -259,6 +259,19 @@ thead .fc-day-selected:hover { @apply tw-bg-gray-700 tw-border-gray-800 tw-text-white hocus:tw-bg-gray-800; } + &.is-invalid { + @apply tw-bg-amber-200 tw-border-amber-300 tw-text-amber-950 hocus:tw-bg-amber-300; + & .fc-event-main { + @apply tw-relative tw-h-full; + + &::after { + @apply tw-absolute tw-inset-0 tw-bg-stripes tw-block tw-bg-transparent; + content: ''; + background-size: 10px 10px; + } + } + } + &.is-new { @apply tw-bg-emerald-200 tw-border-emerald-300 tw-text-emerald-900 hocus:tw-bg-emerald-300; }