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
@@ -9,6 +9,17 @@ import {
EventHandlersProps,
} from "../../../src/components/Calendar/handlers/eventHandlers";
import EventPreviewModal from "../../../src/features/Events/EventDisplayPreview";
jest.mock("../../../src/components/Event/utils/eventUtils", () => {
const actual = jest.requireActual(
"../../../src/components/Event/utils/eventUtils"
);
return {
...actual,
refreshCalendars: jest.fn(() => Promise.resolve()),
refreshSingularCalendar: jest.fn(() => Promise.resolve()),
};
});
import preview from "jest-preview";
const mockOnClose = jest.fn();
const day = new Date("2025-03-15T10:00:00Z");
@@ -476,7 +487,9 @@ describe("RSVP to Recurring Event", () => {
const spy = jest
.spyOn(eventThunks, "updateEventInstanceAsync")
.mockImplementation((payload) => {
return () => Promise.resolve(payload) as any;
const promise = Promise.resolve(payload);
(promise as any).unwrap = () => promise;
return () => promise as any;
});
await act(async () =>
@@ -936,7 +949,9 @@ describe("handleRSVP function", () => {
} = require("../../../src/components/Event/eventHandlers/eventHandlers");
jest.spyOn(eventThunks, "putEventAsync").mockImplementation((payload) => {
return () => Promise.resolve(payload) as any;
const promise = Promise.resolve(payload);
(promise as any).unwrap = () => promise;
return () => promise as any;
});
const nonRecurringEvent = {
@@ -1116,8 +1131,10 @@ describe("Event URL handling for recurring events", () => {
const moveEventSpy = jest
.spyOn(eventThunks, "moveEventAsync")
.mockImplementation((payload) => {
return () =>
Promise.resolve({ calId: payload.cal.id, events: [] }) as any;
const result = { calId: payload.cal.id, events: [] };
const promise = Promise.resolve(result);
(promise as any).unwrap = () => promise;
return () => promise as any;
});
const twoCalState = {