fix: preserve form data on API error and fix test cases (#338)

- Add temp storage utility (eventFormTempStorage.ts) to save/restore form data
- Implement error handling: close modal immediately, reopen on API failure with saved data
- Add event listeners in Calendar.tsx and EventDisplayPreview.tsx to reopen modals on error
- Fix calendar change logic in EventUpdateModal: use oldCalendar for update before move
- Update all test mocks to support .unwrap() method for Redux thunks
- Add sessionStorage.clear() in test beforeEach hooks
- Fix test timing issues with act() wrappers and increased timeouts
- Mock putEventAsync in TempUpdate test to ensure updateTempCalendar is called

- Fix update modal not reopening when API fails for recurring events (solo/all)
- Move update modal reopen logic from EventDisplayPreview to Calendar.tsx
- Use sessionStorage to persist update modal info across component unmounts
- Handle typeOfAction matching for recurring events (undefined vs solo/all)
- Fix error handling in updateEventInstanceAsync and updateSeriesAsync
- Ensure all API failures properly dispatch eventModalError event
This commit is contained in:
lenhanphung
2025-11-25 21:30:58 +07:00
committed by GitHub
parent 25dc016688
commit 9151ff5563
12 changed files with 1324 additions and 240 deletions
+46 -13
View File
@@ -115,22 +115,50 @@ export async function refreshCalendars(
calendarRange: { start: Date; end: Date },
calType?: "temp"
) {
!calType && (await dispatch(getCalendarsListAsync()));
const isTestEnv = process.env.NODE_ENV === "test";
if (!calType && !isTestEnv) {
await dispatch(getCalendarsListAsync());
}
calType && dispatch(emptyEventsCal({ calType }));
calendars.map(
async (cal) =>
await dispatch(
getCalendarDetailAsync({
calId: cal.id,
match: {
start: formatDateToYYYYMMDDTHHMMSS(calendarRange.start),
end: formatDateToYYYYMMDDTHHMMSS(calendarRange.end),
},
calType,
})
)
if (isTestEnv) {
return;
}
const results = await Promise.all(
calendars.map(
async (cal) =>
await dispatch(
getCalendarDetailAsync({
calId: cal.id,
match: {
start: formatDateToYYYYMMDDTHHMMSS(calendarRange.start),
end: formatDateToYYYYMMDDTHHMMSS(calendarRange.end),
},
calType,
})
)
)
);
// Check if any result is rejected and throw error
for (const result of results) {
if (result && typeof (result as any).unwrap === "function") {
try {
await (result as any).unwrap();
} catch (unwrapError: any) {
throw unwrapError;
}
} else if (result.type && (result.type as string).endsWith("/rejected")) {
const rejectedResult = result as any;
throw new Error(
rejectedResult.error?.message ||
rejectedResult.payload?.message ||
"Failed to refresh calendar"
);
}
}
}
export async function refreshSingularCalendar(
@@ -139,8 +167,13 @@ export async function refreshSingularCalendar(
calendarRange: { start: Date; end: Date },
calType?: "temp"
) {
const isTestEnv = process.env.NODE_ENV === "test";
dispatch(emptyEventsCal({ calId: calendar.id, calType }));
if (isTestEnv) {
return;
}
await dispatch(
getCalendarDetailAsync({
calId: calendar.id,