fix: service calendar edit modal saves and displays correct time
- Force FullCalendar remount after save/delete via calendarKey ref - Fix datetime construction to use proper ISO 8601 format (T separator, zero-padded) - Add console.log for save debugging - Root cause was TIMESTAMPTZ column with PDT server timezone causing +3h offset for EDT users; fixed by converting column to TIMESTAMP WITHOUT TIME ZONE via raw SQL Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -104,7 +104,7 @@
|
||||
|
||||
<!-- FullCalendar -->
|
||||
<div class="calendar-body p-6">
|
||||
<FullCalendar ref="fullCalendar" :options="calendarOptions" />
|
||||
<FullCalendar ref="fullCalendar" :key="calendarKey" :options="calendarOptions" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -122,6 +122,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import FullCalendar from '@fullcalendar/vue3';
|
||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||
import interactionPlugin from '@fullcalendar/interaction';
|
||||
@@ -131,11 +132,13 @@ import { serviceService } from '../../services/serviceService';
|
||||
import { authService } from '../../services/authService';
|
||||
import { AxiosResponse, AxiosError, ServiceCall } from '../../types/models';
|
||||
import { getFederalHolidays, type Holiday } from '../../utils/holidays';
|
||||
import { notify } from '@kyvg/vue3-notification';
|
||||
|
||||
// Reactive data
|
||||
const user = ref(null)
|
||||
const selectedServiceForEdit = ref(null as Partial<ServiceCall> | null)
|
||||
const fullCalendar = ref()
|
||||
const calendarKey = ref(0)
|
||||
const currentView = ref('dayGridMonth')
|
||||
const holidays = ref<Holiday[]>([])
|
||||
const currentDate = ref(new Date())
|
||||
@@ -163,9 +166,10 @@ const isHolidayDate = (dateStr: string): Holiday | undefined => {
|
||||
|
||||
// Event handlers
|
||||
const handleEventClick = (clickInfo: EventClickArg): void => {
|
||||
const start = clickInfo.event.start;
|
||||
selectedServiceForEdit.value = {
|
||||
id: parseInt(clickInfo.event.id),
|
||||
scheduled_date: clickInfo.event.startStr,
|
||||
scheduled_date: start ? dayjs(start).format('YYYY-MM-DDTHH:mm:ss') : '',
|
||||
customer_name: clickInfo.event.title.split(': ')[1] || 'Unknown Customer',
|
||||
customer_id: clickInfo.event.extendedProps.customer_id,
|
||||
type_service_call: clickInfo.event.extendedProps.type_service_call,
|
||||
@@ -182,12 +186,8 @@ const TYPE_CLASS: Record<number, string> = {
|
||||
4: 'event-other',
|
||||
}
|
||||
|
||||
// Fetch events function for FullCalendar
|
||||
const fetchCalendarEvents = async (
|
||||
fetchInfo: { startStr: string; endStr: string },
|
||||
successCallback: (events: any[]) => void,
|
||||
failureCallback: (error: Error) => void
|
||||
) => {
|
||||
// Fetch and render all events imperatively
|
||||
const fetchCalendarEvents = async () => {
|
||||
try {
|
||||
const response = await serviceService.getAll();
|
||||
const rawEvents: any[] = response.data?.events || [];
|
||||
@@ -206,14 +206,19 @@ const fetchCalendarEvents = async (
|
||||
start: holiday.date,
|
||||
allDay: true,
|
||||
display: 'background',
|
||||
classNames: ['holiday-event']
|
||||
classNames: ['holiday-event'],
|
||||
}));
|
||||
|
||||
successCallback([...serviceEvents, ...holidayEvents]);
|
||||
const allEvents = [...serviceEvents, ...holidayEvents];
|
||||
calendarOptions.value.events = allEvents as any;
|
||||
|
||||
const api = (fullCalendar.value as any)?.getApi();
|
||||
if (api) {
|
||||
api.removeAllEvents();
|
||||
allEvents.forEach((e: any) => api.addEvent(e));
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
const error = err as AxiosError;
|
||||
console.error("Failed to fetch calendar events:", error);
|
||||
failureCallback(error as Error);
|
||||
console.error("Failed to fetch calendar events:", err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -280,7 +285,7 @@ const calendarOptions = ref({
|
||||
headerToolbar: false,
|
||||
weekends: true,
|
||||
height: 'auto',
|
||||
events: fetchCalendarEvents,
|
||||
events: [],
|
||||
eventClick: handleEventClick,
|
||||
dayCellClassNames: getDayCellClassNames,
|
||||
eventDisplay: 'block',
|
||||
@@ -297,24 +302,21 @@ const closeEditModal = () => {
|
||||
const handleSaveChanges = async (updatedService: ServiceCall) => {
|
||||
try {
|
||||
await serviceService.update(updatedService.id, updatedService);
|
||||
const calendarApi = (fullCalendar.value as any).getApi();
|
||||
if (calendarApi) {
|
||||
calendarApi.refetchEvents();
|
||||
}
|
||||
await fetchCalendarEvents();
|
||||
calendarKey.value++;
|
||||
closeEditModal();
|
||||
notify({ title: 'Saved', text: 'Service call updated.', type: 'success' });
|
||||
} catch (error) {
|
||||
console.error("Failed to save changes:", error);
|
||||
alert("An error occurred while saving. Please check the console.");
|
||||
notify({ title: 'Error', text: 'Failed to save service call.', type: 'error' });
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteService = async (serviceId: number) => {
|
||||
try {
|
||||
await serviceService.delete(serviceId);
|
||||
const calendarApi = (fullCalendar.value as any).getApi();
|
||||
if (calendarApi) {
|
||||
calendarApi.refetchEvents();
|
||||
}
|
||||
await fetchCalendarEvents();
|
||||
calendarKey.value++;
|
||||
closeEditModal();
|
||||
} catch (error) {
|
||||
console.error("Error deleting event:", error);
|
||||
@@ -333,9 +335,10 @@ const userStatus = () => {
|
||||
}
|
||||
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
userStatus();
|
||||
loadHolidays();
|
||||
await fetchCalendarEvents();
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -163,19 +163,13 @@ const getServiceParts = (customerId: number) => {
|
||||
.finally(() => { isLoadingParts.value = false; });
|
||||
}
|
||||
|
||||
const saveChanges = async () => {
|
||||
const saveChanges = () => {
|
||||
const date = editableService.value.date;
|
||||
const time = editableService.value.time || 0;
|
||||
const combinedDateTime = dayjs(`${date} ${time}:00`).format('YYYY-MM-DDTHH:mm:ss');
|
||||
const time = editableService.value.time ?? 0;
|
||||
const combinedDateTime = dayjs(`${date}T${String(time).padStart(2, '0')}:00:00`).format('YYYY-MM-DDTHH:mm:ss');
|
||||
console.log('[ServiceEditModal] saving - date:', date, 'time:', time, 'combinedDateTime:', combinedDateTime);
|
||||
const finalPayload = { ...props.service, ...editableService.value, scheduled_date: combinedDateTime };
|
||||
|
||||
try {
|
||||
await serviceService.update(finalPayload.id!, finalPayload);
|
||||
emit('save-changes', finalPayload as ServiceCall);
|
||||
} catch (error) {
|
||||
console.error("Failed to save changes:", error);
|
||||
alert("An error occurred while saving. Please check the console.");
|
||||
}
|
||||
emit('save-changes', finalPayload as ServiceCall);
|
||||
}
|
||||
|
||||
const confirmDelete = () => {
|
||||
|
||||
Reference in New Issue
Block a user