Fix: Preserve timezone used in create and update modal (#301)

- Fix timezone field display in event modals to show original timezone from server
- Fix formatDateToICal to use moment.utc(date).tz(timezone) for correct UTC instant preservation
- Fix parseCalendarEvent to convert event.start/end to ISO UTC strings after parsing
- Fix eventToFullCalendarFormat to ensure event times are ISO UTC before passing to FullCalendar
- Fix getEvent to normalize event.start/end to ISO UTC strings
- Ensure event.timezone is always set (defaults to Etc/UTC if not detected)
- Update eventUtils.test.ts to match new timezone conversion logic
- Fix event time shift issue on calendar grid display

This ensures:
- Events display in correct time slots on calendar grid
- Event times are correctly converted between timezones
- Original timezone from server is preserved and displayed
- All event times are stored as ISO UTC strings internally

* refactor: eliminate datetime format detection code duplication

- Add constants for datetime format strings and magic number (DATETIME_WITH_SECONDS_LENGTH, DATETIME_FORMAT_WITH_SECONDS, DATETIME_FORMAT_WITHOUT_SECONDS)
- Create shared detectDateTimeFormat() function to replace duplicated format detection logic
- Refactor convertFormDateTimeToISO, convertEventDateTimeToISO, and convertDateTimeStringToISO to use shared helper
- Add console.warn logging when invalid datetime is encountered (addresses silent fallback issue)
- Add comprehensive test coverage for dateTimeHelpers with full test suite
This commit is contained in:
lenhanphung
2025-11-20 15:32:15 +07:00
committed by GitHub
parent 8e7b6e18eb
commit bff1af31bd
10 changed files with 951 additions and 138 deletions
+12 -6
View File
@@ -793,8 +793,10 @@ const CalendarSlice = createSlice({
state[type][action.payload.calId].color;
state[type][action.payload.calId].events[id].calId =
action.payload.calId;
state[type][action.payload.calId].events[id].timezone =
Intl.DateTimeFormat().resolvedOptions().timeZone;
if (!state[type][action.payload.calId].events[id].timezone) {
state[type][action.payload.calId].events[id].timezone =
Intl.DateTimeFormat().resolvedOptions().timeZone;
}
}
);
}
@@ -827,8 +829,10 @@ const CalendarSlice = createSlice({
state[type][action.payload.calId].color;
state[type][action.payload.calId].events[id].calId =
action.payload.calId;
state[type][action.payload.calId].events[id].timezone =
Intl.DateTimeFormat().resolvedOptions().timeZone;
if (!state[type][action.payload.calId].events[id].timezone) {
state[type][action.payload.calId].events[id].timezone =
Intl.DateTimeFormat().resolvedOptions().timeZone;
}
}
);
}
@@ -872,8 +876,10 @@ const CalendarSlice = createSlice({
state.list[action.payload.calId].color;
state.list[action.payload.calId].events[id].calId =
action.payload.calId;
state.list[action.payload.calId].events[id].timezone =
Intl.DateTimeFormat().resolvedOptions().timeZone;
if (!state.list[action.payload.calId].events[id].timezone) {
state.list[action.payload.calId].events[id].timezone =
Intl.DateTimeFormat().resolvedOptions().timeZone;
}
});
}
)