fix(calendar): apply ensureUTC to FullCalendar event start/end

FullCalendar treats naive datetime strings as already being in the
display timezone, causing double-offset. Appending 'Z' forces correct
UTC interpretation before conversion to user timezone.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-03-04 10:48:26 +00:00
parent 2f1babd11d
commit bf96fcf22c
2 changed files with 6 additions and 6 deletions

View File

@@ -60,7 +60,7 @@ import type { CalendarOptions, EventInput, DatesSetArg, EventDropArg } from '@fu
import { bookingsApi, adminBookingsApi, handleApiError } from '@/services/api' import { bookingsApi, adminBookingsApi, handleApiError } from '@/services/api'
import { useAuthStore } from '@/stores/auth' import { useAuthStore } from '@/stores/auth'
import { useIsMobile } from '@/composables/useMediaQuery' import { useIsMobile } from '@/composables/useMediaQuery'
import { formatDateTime as formatDateTimeUtil } from '@/utils/datetime' import { formatDateTime as formatDateTimeUtil, ensureUTC } from '@/utils/datetime'
import BookingPreviewModal from '@/components/BookingPreviewModal.vue' import BookingPreviewModal from '@/components/BookingPreviewModal.vue'
import type { Booking } from '@/types' import type { Booking } from '@/types'
@@ -126,8 +126,8 @@ const events = computed<EventInput[]>(() => {
return bookings.value.map((booking) => ({ return bookings.value.map((booking) => ({
id: String(booking.id), id: String(booking.id),
title: booking.space?.name ? `${booking.space.name} - ${booking.title}` : booking.title, title: booking.space?.name ? `${booking.space.name} - ${booking.title}` : booking.title,
start: booking.start_datetime, start: ensureUTC(booking.start_datetime),
end: booking.end_datetime, end: ensureUTC(booking.end_datetime),
backgroundColor: STATUS_COLORS[booking.status] || '#9E9E9E', backgroundColor: STATUS_COLORS[booking.status] || '#9E9E9E',
borderColor: STATUS_COLORS[booking.status] || '#9E9E9E', borderColor: STATUS_COLORS[booking.status] || '#9E9E9E',
extendedProps: { extendedProps: {

View File

@@ -61,7 +61,7 @@ import type { CalendarOptions, EventInput, DatesSetArg, EventDropArg } from '@fu
import type { EventResizeDoneArg } from '@fullcalendar/interaction' import type { EventResizeDoneArg } from '@fullcalendar/interaction'
import { bookingsApi, adminBookingsApi, handleApiError } from '@/services/api' import { bookingsApi, adminBookingsApi, handleApiError } from '@/services/api'
import { useAuthStore } from '@/stores/auth' import { useAuthStore } from '@/stores/auth'
import { formatDateTime as formatDateTimeUtil } from '@/utils/datetime' import { formatDateTime as formatDateTimeUtil, ensureUTC } from '@/utils/datetime'
import { useIsMobile } from '@/composables/useMediaQuery' import { useIsMobile } from '@/composables/useMediaQuery'
import BookingPreviewModal from '@/components/BookingPreviewModal.vue' import BookingPreviewModal from '@/components/BookingPreviewModal.vue'
import type { Booking } from '@/types' import type { Booking } from '@/types'
@@ -136,8 +136,8 @@ const events = computed<EventInput[]>(() => {
return bookings.value.map((booking) => ({ return bookings.value.map((booking) => ({
id: String(booking.id), id: String(booking.id),
title: booking.title, title: booking.title,
start: booking.start_datetime, start: ensureUTC(booking.start_datetime),
end: booking.end_datetime, end: ensureUTC(booking.end_datetime),
backgroundColor: STATUS_COLORS[booking.status] || '#9E9E9E', backgroundColor: STATUS_COLORS[booking.status] || '#9E9E9E',
borderColor: STATUS_COLORS[booking.status] || '#9E9E9E', borderColor: STATUS_COLORS[booking.status] || '#9E9E9E',
extendedProps: { extendedProps: {