[#168] changed temp calendar reload to reload only thoses that are impacted
This commit is contained in:
committed by
Benoit TELLIER
parent
29f984b347
commit
f278caf041
@@ -14,6 +14,8 @@ import {
|
|||||||
stringToColor,
|
stringToColor,
|
||||||
stringAvatar,
|
stringAvatar,
|
||||||
} from "../../../src/components/Event/utils/eventUtils";
|
} from "../../../src/components/Event/utils/eventUtils";
|
||||||
|
import * as appHooks from "../../../src/app/hooks";
|
||||||
|
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||||
|
|
||||||
describe("Event Preview Display", () => {
|
describe("Event Preview Display", () => {
|
||||||
const mockOnClose = jest.fn();
|
const mockOnClose = jest.fn();
|
||||||
@@ -561,6 +563,200 @@ describe("Event Preview Display", () => {
|
|||||||
|
|
||||||
expect(mockOpen).toHaveBeenCalledWith(expectedUrl);
|
expect(mockOpen).toHaveBeenCalledWith(expectedUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Owner Email Permissions", () => {
|
||||||
|
const today = new Date();
|
||||||
|
const start = new Date(today);
|
||||||
|
start.setHours(10, 0, 0, 0);
|
||||||
|
const end = new Date(today);
|
||||||
|
end.setHours(11, 0, 0, 0);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
const dispatch = jest.fn() as ThunkDispatch<any, any, any>;
|
||||||
|
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
|
||||||
|
});
|
||||||
|
|
||||||
|
const createPreloadedState = (
|
||||||
|
userEmail: string,
|
||||||
|
ownerEmails: string[],
|
||||||
|
organizerEmail: string
|
||||||
|
) => ({
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: userEmail,
|
||||||
|
sid: "mockSid",
|
||||||
|
openpaasId: "667037022b752d0026472254",
|
||||||
|
},
|
||||||
|
tokens: {
|
||||||
|
accessToken: "token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
name: "Calendar 1",
|
||||||
|
id: "667037022b752d0026472254/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ownerEmails,
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
organizer: {
|
||||||
|
cn: "Organizer",
|
||||||
|
cal_address: organizerEmail,
|
||||||
|
},
|
||||||
|
attendee: [
|
||||||
|
{
|
||||||
|
cn: "Organizer",
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
rsvp: "TRUE",
|
||||||
|
role: "REQ-PARTICIPANT",
|
||||||
|
cutype: "INDIVIDUAL",
|
||||||
|
cal_address: organizerEmail,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show edit button when user email matches organizer and is in ownerEmails", async () => {
|
||||||
|
const preloadedState = createPreloadedState(
|
||||||
|
"owner@test.com",
|
||||||
|
["owner@test.com"],
|
||||||
|
"owner@test.com"
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
const editButton = screen.queryByTestId("EditIcon");
|
||||||
|
expect(editButton).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should NOT show edit button when user is organizer but not in owner of calendar", async () => {
|
||||||
|
const preloadedState = createPreloadedState(
|
||||||
|
"organizer@test.com",
|
||||||
|
["other@test.com"], // organizer not in list
|
||||||
|
"organizer@test.com"
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
const editButton = screen.queryByTestId("EditIcon");
|
||||||
|
expect(editButton).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should NOT show edit button when user is in ownerEmails but not organizer", async () => {
|
||||||
|
const preloadedState = createPreloadedState(
|
||||||
|
"owner@test.com",
|
||||||
|
["owner@test.com"],
|
||||||
|
"other@test.com" // different organizer
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
const editButton = screen.queryByTestId("EditIcon");
|
||||||
|
expect(editButton).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle calendars without ownerEmails property gracefully", async () => {
|
||||||
|
const preloadedStateWithoutOwnerEmails = {
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: "test@test.com",
|
||||||
|
sid: "mockSid",
|
||||||
|
openpaasId: "667037022b752d0026472254",
|
||||||
|
},
|
||||||
|
tokens: {
|
||||||
|
accessToken: "token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
name: "Calendar 1",
|
||||||
|
id: "667037022b752d0026472254/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
// ownerEmails missing
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
organizer: {
|
||||||
|
cn: "Test",
|
||||||
|
cal_address: "test@test.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
expect(() => {
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedStateWithoutOwnerEmails
|
||||||
|
);
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Event Full Display", () => {
|
describe("Event Full Display", () => {
|
||||||
|
|||||||
@@ -0,0 +1,826 @@
|
|||||||
|
import { jest } from "@jest/globals";
|
||||||
|
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||||
|
import "@testing-library/jest-dom";
|
||||||
|
import { screen, waitFor, fireEvent } from "@testing-library/react";
|
||||||
|
import * as appHooks from "../../../src/app/hooks";
|
||||||
|
import * as eventUtils from "../../../src/components/Event/utils/eventUtils";
|
||||||
|
import * as userApi from "../../../src/features/User/userAPI";
|
||||||
|
import * as calendarUtils from "../../../src/components/Calendar/utils/calendarUtils";
|
||||||
|
import * as eventThunks from "../../../src/features/Calendars/CalendarSlice";
|
||||||
|
import EventPreviewModal from "../../../src/features/Events/EventDisplayPreview";
|
||||||
|
import EventPopover from "../../../src/features/Events/EventModal";
|
||||||
|
import EventUpdateModal from "../../../src/features/Events/EventUpdateModal";
|
||||||
|
import CalendarLayout from "../../../src/components/Calendar/CalendarLayout";
|
||||||
|
import { renderWithProviders } from "../../utils/Renderwithproviders";
|
||||||
|
import { SpiedFunction } from "jest-mock";
|
||||||
|
import { Calendars } from "../../../src/features/Calendars/CalendarTypes";
|
||||||
|
import { CalendarEvent } from "../../../src/features/Events/EventsTypes";
|
||||||
|
import { DateSelectArg } from "@fullcalendar/core";
|
||||||
|
|
||||||
|
describe("Update tempcalendars called with correct params", () => {
|
||||||
|
const today = new Date();
|
||||||
|
const start = new Date(today);
|
||||||
|
start.setHours(10, 0, 0, 0);
|
||||||
|
const end = new Date(today);
|
||||||
|
end.setHours(11, 0, 0, 0);
|
||||||
|
|
||||||
|
let refreshCalendarsSpy: SpiedFunction<
|
||||||
|
(
|
||||||
|
dispatch: ThunkDispatch<any, any, any>,
|
||||||
|
calendars: Calendars[],
|
||||||
|
calendarRange: { start: Date; end: Date },
|
||||||
|
calType?: "temp"
|
||||||
|
) => Promise<void>
|
||||||
|
>;
|
||||||
|
let refreshSingularCalendarSpy: SpiedFunction<
|
||||||
|
(
|
||||||
|
dispatch: ThunkDispatch<any, any, any>,
|
||||||
|
calendar: Calendars,
|
||||||
|
calendarRange: { start: Date; end: Date },
|
||||||
|
calType?: "temp"
|
||||||
|
) => Promise<void>
|
||||||
|
>;
|
||||||
|
let updateTempCalendarSpy: SpiedFunction<
|
||||||
|
(
|
||||||
|
tempcalendars: Record<string, Calendars>,
|
||||||
|
event: CalendarEvent,
|
||||||
|
dispatch: ThunkDispatch<any, any, any>,
|
||||||
|
calendarRange: { start: Date; end: Date }
|
||||||
|
) => Promise<void>
|
||||||
|
>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
const dispatch = jest.fn() as ThunkDispatch<any, any, any>;
|
||||||
|
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
|
||||||
|
refreshCalendarsSpy = jest.spyOn(eventUtils, "refreshCalendars");
|
||||||
|
updateTempCalendarSpy = jest.spyOn(calendarUtils, "updateTempCalendar");
|
||||||
|
refreshSingularCalendarSpy = jest.spyOn(
|
||||||
|
eventUtils,
|
||||||
|
"refreshSingularCalendar"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
refreshCalendarsSpy.mockRestore();
|
||||||
|
updateTempCalendarSpy.mockRestore();
|
||||||
|
refreshSingularCalendarSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
const createPreloadedState = (withTempList = true) => ({
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: "owner@test.com",
|
||||||
|
sid: "mockSid",
|
||||||
|
openpaasId: "667037022b752d0026472254",
|
||||||
|
},
|
||||||
|
organiserData: {
|
||||||
|
cn: "Owner",
|
||||||
|
cal_address: "owner@test.com",
|
||||||
|
},
|
||||||
|
tokens: {
|
||||||
|
accessToken: "token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
name: "Calendar 1",
|
||||||
|
id: "667037022b752d0026472254/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ["owner@test.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
attendee: [{ cal_address: "attendee@test.com" }],
|
||||||
|
organizer: {
|
||||||
|
cn: "Owner",
|
||||||
|
cal_address: "owner@test.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
templist: withTempList
|
||||||
|
? {
|
||||||
|
temp1: {
|
||||||
|
id: "temp1",
|
||||||
|
name: "Temp Calendar",
|
||||||
|
color: "#00FF00",
|
||||||
|
events: {},
|
||||||
|
ownerEmails: ["attendee@test.com"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call updateTempCalendar with correct params after event deletion", async () => {
|
||||||
|
const preloadedState = createPreloadedState(true);
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.click(screen.getByTestId("MoreVertIcon"));
|
||||||
|
expect(screen.getByText("Delete event")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteMenuItem = screen.getByText("Delete event");
|
||||||
|
fireEvent.click(deleteMenuItem);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(updateTempCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
temp1: expect.objectContaining({ id: "temp1" }),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
attendee: [
|
||||||
|
expect.objectContaining({ cal_address: "attendee@test.com" }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(refreshSingularCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({ id: "temp1" }),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
}),
|
||||||
|
"temp"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should NOT call updateTempCalendar when templist is undefined", async () => {
|
||||||
|
const preloadedState = createPreloadedState(false);
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.click(screen.getByTestId("MoreVertIcon"));
|
||||||
|
expect(screen.getByText("Delete event")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteMenuItem = screen.getByText("Delete event");
|
||||||
|
fireEvent.click(deleteMenuItem);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(updateTempCalendarSpy).not.toHaveBeenCalled();
|
||||||
|
expect(refreshSingularCalendarSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call updateTempCalendar with correct params after event creation", async () => {
|
||||||
|
const preloadedState = createPreloadedState(true);
|
||||||
|
const defaultSelectedRange = {
|
||||||
|
startStr: "2025-07-18T09:00Z",
|
||||||
|
endStr: "2025-07-18T10:00Z",
|
||||||
|
start: new Date("2025-07-18T09:00Z"),
|
||||||
|
end: new Date("2025-07-18T10:00Z"),
|
||||||
|
allDay: false,
|
||||||
|
resource: undefined,
|
||||||
|
} as unknown as DateSelectArg;
|
||||||
|
jest.spyOn(userApi, "searchUsers");
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPopover
|
||||||
|
anchorEl={null}
|
||||||
|
open={true}
|
||||||
|
onClose={jest.fn()}
|
||||||
|
selectedRange={defaultSelectedRange}
|
||||||
|
setSelectedRange={jest.fn()}
|
||||||
|
calendarRef={{ current: null }}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const titleInput = screen.getByLabelText(/title/i);
|
||||||
|
fireEvent.change(titleInput, { target: { value: "New Event" } });
|
||||||
|
|
||||||
|
const attendeeInput = screen.getByLabelText(
|
||||||
|
/Start typing a name or email/i
|
||||||
|
);
|
||||||
|
fireEvent.change(attendeeInput, { target: { value: "attendee@test.com" } });
|
||||||
|
fireEvent.keyDown(attendeeInput, { key: "Enter", code: "Enter" });
|
||||||
|
|
||||||
|
const saveButton = screen.getByText(/save/i);
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(updateTempCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
temp1: expect.objectContaining({ id: "temp1" }),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
title: "New Event",
|
||||||
|
}),
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(refreshSingularCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({ id: "temp1" }),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
}),
|
||||||
|
"temp"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call updateTempCalendar with correct params after event update", async () => {
|
||||||
|
const preloadedState = createPreloadedState(true);
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventUpdateModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const saveButton = screen.getByText(/save/i);
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(updateTempCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
temp1: expect.objectContaining({ id: "temp1" }),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
attendee: [
|
||||||
|
expect.objectContaining({ cal_address: "attendee@test.com" }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(refreshSingularCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({ id: "temp1" }),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
}),
|
||||||
|
"temp"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call updateTempCalendar with correct params after recurring event instance update", async () => {
|
||||||
|
const preloadedStateWithRecurring = {
|
||||||
|
...createPreloadedState(true),
|
||||||
|
calendars: {
|
||||||
|
...createPreloadedState(true).calendars,
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
name: "Calendar 1",
|
||||||
|
id: "667037022b752d0026472254/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ["owner@test.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Recurring Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
attendee: [{ cal_address: "attendee@test.com" }],
|
||||||
|
rrule: {
|
||||||
|
freq: "WEEKLY",
|
||||||
|
},
|
||||||
|
organizer: {
|
||||||
|
cn: "Owner",
|
||||||
|
cal_address: "owner@test.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventUpdateModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
typeOfAction="solo"
|
||||||
|
/>,
|
||||||
|
preloadedStateWithRecurring
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const saveButton = screen.getByText(/save/i);
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(updateTempCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
temp1: expect.objectContaining({ id: "temp1" }),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
attendee: [
|
||||||
|
expect.objectContaining({ cal_address: "attendee@test.com" }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(refreshSingularCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({ id: "temp1" }),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
}),
|
||||||
|
"temp"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call updateTempCalendar with correct params after recurring series update", async () => {
|
||||||
|
const preloadedStateWithRecurring = {
|
||||||
|
...createPreloadedState(true),
|
||||||
|
calendars: {
|
||||||
|
...createPreloadedState(true).calendars,
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
name: "Calendar 1",
|
||||||
|
id: "667037022b752d0026472254/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ["owner@test.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Recurring Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
attendee: [{ cal_address: "attendee@test.com" }],
|
||||||
|
rrule: {
|
||||||
|
freq: "DAILY",
|
||||||
|
},
|
||||||
|
organizer: {
|
||||||
|
cn: "Owner",
|
||||||
|
cal_address: "owner@test.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventUpdateModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
typeOfAction="all"
|
||||||
|
/>,
|
||||||
|
preloadedStateWithRecurring
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const saveButton = screen.getByText(/save/i);
|
||||||
|
fireEvent.click(saveButton);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(updateTempCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
temp1: expect.objectContaining({ id: "temp1" }),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
attendee: [
|
||||||
|
expect.objectContaining({ cal_address: "attendee@test.com" }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(refreshSingularCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({ id: "temp1" }),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
}),
|
||||||
|
"temp"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call refreshCalendars with 'temp' param in CalendarLayout handleRefresh", async () => {
|
||||||
|
const preloadedState = createPreloadedState(true);
|
||||||
|
|
||||||
|
renderWithProviders(<CalendarLayout />, preloadedState);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByTestId("RefreshIcon"));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
// Should call refreshCalendars for regular calendars
|
||||||
|
expect(refreshCalendarsSpy).toHaveBeenCalledWith(
|
||||||
|
expect.any(Function),
|
||||||
|
expect.any(Array),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Should also call refreshCalendars with 'temp' for templist
|
||||||
|
expect(refreshCalendarsSpy).toHaveBeenCalledWith(
|
||||||
|
expect.any(Function),
|
||||||
|
expect.arrayContaining([expect.objectContaining({ id: "temp1" })]),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
}),
|
||||||
|
"temp"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should only refresh temp calendars where attendees match ownerEmails", async () => {
|
||||||
|
const preloadedStateMultipleTempCals = {
|
||||||
|
...createPreloadedState(true),
|
||||||
|
calendars: {
|
||||||
|
...createPreloadedState(true).calendars,
|
||||||
|
templist: {
|
||||||
|
temp1: {
|
||||||
|
id: "temp1",
|
||||||
|
name: "Temp Calendar 1",
|
||||||
|
color: "#00FF00",
|
||||||
|
events: {},
|
||||||
|
ownerEmails: ["attendee@test.com"], // matches event attendee
|
||||||
|
},
|
||||||
|
temp2: {
|
||||||
|
id: "temp2",
|
||||||
|
name: "Temp Calendar 2",
|
||||||
|
color: "#0000FF",
|
||||||
|
events: {},
|
||||||
|
ownerEmails: ["other@test.com"], // does NOT match event attendee
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedStateMultipleTempCals
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.click(screen.getByTestId("MoreVertIcon"));
|
||||||
|
expect(screen.getByText("Delete event")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteMenuItem = screen.getByText("Delete event");
|
||||||
|
fireEvent.click(deleteMenuItem);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
// Should only refresh temp1, not temp2
|
||||||
|
const temp1Calls = refreshSingularCalendarSpy.mock.calls.filter(
|
||||||
|
(call) => call[1]?.id === "temp1"
|
||||||
|
);
|
||||||
|
const temp2Calls = refreshSingularCalendarSpy.mock.calls.filter(
|
||||||
|
(call) => call[1]?.id === "temp2"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(temp1Calls.length).toBeGreaterThan(0);
|
||||||
|
expect(temp2Calls.length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call emptyEventsCal with correct params before refreshing", async () => {
|
||||||
|
const emptyEventsCalSpy = jest.spyOn(eventThunks, "emptyEventsCal");
|
||||||
|
|
||||||
|
const preloadedState = createPreloadedState(true);
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.click(screen.getByTestId("MoreVertIcon"));
|
||||||
|
expect(screen.getByText("Delete event")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteMenuItem = screen.getByText("Delete event");
|
||||||
|
fireEvent.click(deleteMenuItem);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
// emptyEventsCal should be called with calType: "temp" for singular calendar refresh
|
||||||
|
expect(emptyEventsCalSpy).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
calId: "temp1",
|
||||||
|
calType: "temp",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
emptyEventsCalSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle temp calendar with multiple ownerEmails where one matches", async () => {
|
||||||
|
const preloadedStateMultipleOwners = {
|
||||||
|
...createPreloadedState(true),
|
||||||
|
calendars: {
|
||||||
|
...createPreloadedState(true).calendars,
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
name: "Calendar 1",
|
||||||
|
id: "667037022b752d0026472254/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ["owner@test.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
attendee: [{ cal_address: "attendee@test.com" }],
|
||||||
|
organizer: {
|
||||||
|
cn: "Owner",
|
||||||
|
cal_address: "owner@test.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
templist: {
|
||||||
|
temp1: {
|
||||||
|
id: "temp1",
|
||||||
|
name: "Shared Calendar",
|
||||||
|
color: "#00FF00",
|
||||||
|
events: {},
|
||||||
|
ownerEmails: [
|
||||||
|
"someoneelse@test.com",
|
||||||
|
"attendee@test.com", // matches
|
||||||
|
"anotherperson@test.com",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedStateMultipleOwners
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.click(screen.getByTestId("MoreVertIcon"));
|
||||||
|
expect(screen.getByText("Delete event")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteMenuItem = screen.getByText("Delete event");
|
||||||
|
fireEvent.click(deleteMenuItem);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
// Should still refresh temp1 because one ownerEmail matches
|
||||||
|
const temp1Calls = refreshSingularCalendarSpy.mock.calls.filter(
|
||||||
|
(call) => call[1]?.id === "temp1"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(temp1Calls.length).toBeGreaterThan(0);
|
||||||
|
expect(temp1Calls[0][3]).toBe("temp");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("should update multiple temp calendars when event has multiple attendees matching different ownerEmails", async () => {
|
||||||
|
const preloadedStateMultipleAttendees = {
|
||||||
|
...createPreloadedState(true),
|
||||||
|
calendars: {
|
||||||
|
...createPreloadedState(true).calendars,
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
name: "Calendar 1",
|
||||||
|
id: "667037022b752d0026472254/cal1",
|
||||||
|
color: "#FF0000",
|
||||||
|
ownerEmails: ["owner@test.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: end.toISOString(),
|
||||||
|
attendee: [
|
||||||
|
{ cal_address: "attendee1@test.com" },
|
||||||
|
{ cal_address: "attendee2@test.com" },
|
||||||
|
{ cal_address: "attendee3@test.com" },
|
||||||
|
],
|
||||||
|
organizer: {
|
||||||
|
cn: "Owner",
|
||||||
|
cal_address: "owner@test.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
templist: {
|
||||||
|
temp1: {
|
||||||
|
id: "temp1",
|
||||||
|
name: "Temp Calendar 1",
|
||||||
|
color: "#00FF00",
|
||||||
|
events: {},
|
||||||
|
ownerEmails: ["attendee1@test.com"],
|
||||||
|
},
|
||||||
|
temp2: {
|
||||||
|
id: "temp2",
|
||||||
|
name: "Temp Calendar 2",
|
||||||
|
color: "#0000FF",
|
||||||
|
events: {},
|
||||||
|
ownerEmails: ["attendee2@test.com"],
|
||||||
|
},
|
||||||
|
temp3: {
|
||||||
|
id: "temp3",
|
||||||
|
name: "Temp Calendar 3",
|
||||||
|
color: "#FF00FF",
|
||||||
|
events: {},
|
||||||
|
ownerEmails: ["attendee3@test.com"],
|
||||||
|
},
|
||||||
|
temp4: {
|
||||||
|
id: "temp4",
|
||||||
|
name: "Temp Calendar 4",
|
||||||
|
color: "#FFFF00",
|
||||||
|
events: {},
|
||||||
|
ownerEmails: ["nonmatching@test.com"], // should NOT be refreshed
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockOnClose = jest.fn();
|
||||||
|
renderWithProviders(
|
||||||
|
<EventPreviewModal
|
||||||
|
eventId="event1"
|
||||||
|
calId="667037022b752d0026472254/cal1"
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
/>,
|
||||||
|
preloadedStateMultipleAttendees
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.click(screen.getByTestId("MoreVertIcon"));
|
||||||
|
expect(screen.getByText("Delete event")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteMenuItem = screen.getByText("Delete event");
|
||||||
|
fireEvent.click(deleteMenuItem);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
// Should be called once with all templist
|
||||||
|
expect(updateTempCalendarSpy).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
temp1: expect.objectContaining({ id: "temp1" }),
|
||||||
|
temp2: expect.objectContaining({ id: "temp2" }),
|
||||||
|
temp3: expect.objectContaining({ id: "temp3" }),
|
||||||
|
temp4: expect.objectContaining({ id: "temp4" }),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
attendee: expect.arrayContaining([
|
||||||
|
expect.objectContaining({ cal_address: "attendee1@test.com" }),
|
||||||
|
expect.objectContaining({ cal_address: "attendee2@test.com" }),
|
||||||
|
expect.objectContaining({ cal_address: "attendee3@test.com" }),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
expect.any(Function),
|
||||||
|
expect.objectContaining({
|
||||||
|
start: expect.any(Date),
|
||||||
|
end: expect.any(Date),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
// Should refresh temp1, temp2, and temp3 (matching attendees)
|
||||||
|
const temp1Calls = refreshSingularCalendarSpy.mock.calls.filter(
|
||||||
|
(call) => call[1]?.id === "temp1"
|
||||||
|
);
|
||||||
|
const temp2Calls = refreshSingularCalendarSpy.mock.calls.filter(
|
||||||
|
(call) => call[1]?.id === "temp2"
|
||||||
|
);
|
||||||
|
const temp3Calls = refreshSingularCalendarSpy.mock.calls.filter(
|
||||||
|
(call) => call[1]?.id === "temp3"
|
||||||
|
);
|
||||||
|
const temp4Calls = refreshSingularCalendarSpy.mock.calls.filter(
|
||||||
|
(call) => call[1]?.id === "temp4"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(temp1Calls.length).toBeGreaterThan(0);
|
||||||
|
expect(temp2Calls.length).toBeGreaterThan(0);
|
||||||
|
expect(temp3Calls.length).toBeGreaterThan(0);
|
||||||
|
expect(temp4Calls.length).toBe(0); // Should NOT be refreshed
|
||||||
|
|
||||||
|
// Verify all matching calendars were refreshed with 'temp' param
|
||||||
|
expect(temp1Calls[0][3]).toBe("temp");
|
||||||
|
expect(temp2Calls[0][3]).toBe("temp");
|
||||||
|
expect(temp3Calls[0][3]).toBe("temp");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { formatDateToYYYYMMDDTHHMMSS } from "../../../utils/dateUtils";
|
import { formatDateToYYYYMMDDTHHMMSS } from "../../../utils/dateUtils";
|
||||||
import { getEvent } from "../../../features/Events/EventApi";
|
import { getEvent } from "../../../features/Events/EventApi";
|
||||||
import { refreshCalendars } from "../../Event/utils/eventUtils";
|
import { refreshCalendars } from "../../Event/utils/eventUtils";
|
||||||
|
import { updateTempCalendar } from "../utils/calendarUtils";
|
||||||
|
|
||||||
export interface EventHandlersProps {
|
export interface EventHandlersProps {
|
||||||
setSelectedRange: (range: DateSelectArg | null) => void;
|
setSelectedRange: (range: DateSelectArg | null) => void;
|
||||||
@@ -159,14 +160,12 @@ export const createEventHandlers = (props: EventHandlersProps) => {
|
|||||||
Object.values(calendars),
|
Object.values(calendars),
|
||||||
calendarRange
|
calendarRange
|
||||||
);
|
);
|
||||||
if (tempcalendars) {
|
await updateTempCalendar(
|
||||||
await refreshCalendars(
|
tempcalendars,
|
||||||
dispatch,
|
event,
|
||||||
Object.values(tempcalendars),
|
dispatch,
|
||||||
calendarRange,
|
calendarRange
|
||||||
"temp"
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -176,14 +175,7 @@ export const createEventHandlers = (props: EventHandlersProps) => {
|
|||||||
putEventAsync({ cal: calendars[newEvent.calId], newEvent })
|
putEventAsync({ cal: calendars[newEvent.calId], newEvent })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (tempcalendars) {
|
await updateTempCalendar(tempcalendars, event, dispatch, calendarRange);
|
||||||
await refreshCalendars(
|
|
||||||
dispatch,
|
|
||||||
Object.values(tempcalendars),
|
|
||||||
calendarRange,
|
|
||||||
"temp"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEventResize = async (arg: any) => {
|
const handleEventResize = async (arg: any) => {
|
||||||
@@ -243,14 +235,12 @@ export const createEventHandlers = (props: EventHandlersProps) => {
|
|||||||
Object.values(calendars),
|
Object.values(calendars),
|
||||||
calendarRange
|
calendarRange
|
||||||
);
|
);
|
||||||
if (tempcalendars) {
|
await updateTempCalendar(
|
||||||
await refreshCalendars(
|
tempcalendars,
|
||||||
dispatch,
|
event,
|
||||||
Object.values(tempcalendars),
|
dispatch,
|
||||||
calendarRange,
|
calendarRange
|
||||||
"temp"
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -259,14 +249,7 @@ export const createEventHandlers = (props: EventHandlersProps) => {
|
|||||||
putEventAsync({ cal: calendars[newEvent.calId], newEvent })
|
putEventAsync({ cal: calendars[newEvent.calId], newEvent })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (tempcalendars) {
|
await updateTempCalendar(tempcalendars, event, dispatch, calendarRange);
|
||||||
await refreshCalendars(
|
|
||||||
dispatch,
|
|
||||||
Object.values(tempcalendars),
|
|
||||||
calendarRange,
|
|
||||||
"temp"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { formatDateToYYYYMMDDTHHMMSS } from "../../../utils/dateUtils";
|
|||||||
import { getCalendarDetailAsync } from "../../../features/Calendars/CalendarSlice";
|
import { getCalendarDetailAsync } from "../../../features/Calendars/CalendarSlice";
|
||||||
import { SlotLabelContentArg } from "@fullcalendar/core";
|
import { SlotLabelContentArg } from "@fullcalendar/core";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
|
import { refreshSingularCalendar } from "../../Event/utils/eventUtils";
|
||||||
|
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||||
|
|
||||||
export const updateSlotLabelVisibility = (
|
export const updateSlotLabelVisibility = (
|
||||||
currentTime: Date,
|
currentTime: Date,
|
||||||
@@ -154,3 +156,35 @@ export function getCalendarVisibility(acl: AclEntry[]): "private" | "public" {
|
|||||||
if (hasRead) return "public";
|
if (hasRead) return "public";
|
||||||
return "private";
|
return "private";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function updateTempCalendar(
|
||||||
|
tempcalendars: Record<string, Calendars>,
|
||||||
|
event: CalendarEvent,
|
||||||
|
dispatch: ThunkDispatch<any, any, any>,
|
||||||
|
calendarRange: { start: Date; end: Date }
|
||||||
|
) {
|
||||||
|
if (tempcalendars && event?.attendee) {
|
||||||
|
const attendeesEmails = event.attendee
|
||||||
|
.map((a) => a.cal_address)
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
const tempCalendarValues = Object.values(tempcalendars);
|
||||||
|
|
||||||
|
for (const tempCalendar of tempCalendarValues) {
|
||||||
|
const ownerEmails = tempCalendar.ownerEmails || [];
|
||||||
|
|
||||||
|
// Check if any of the attendees are owners of this temp calendar
|
||||||
|
const isOwnerAttendee = ownerEmails.some((ownerEmail) =>
|
||||||
|
attendeesEmails.includes(ownerEmail)
|
||||||
|
);
|
||||||
|
if (isOwnerAttendee) {
|
||||||
|
await refreshSingularCalendar(
|
||||||
|
dispatch,
|
||||||
|
tempCalendar,
|
||||||
|
calendarRange,
|
||||||
|
"temp"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Box from "@mui/material/Box";
|
|||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import { ThunkDispatch } from "@reduxjs/toolkit";
|
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||||
import {
|
import {
|
||||||
emptyTempCal,
|
emptyEventsCal,
|
||||||
getCalendarDetailAsync,
|
getCalendarDetailAsync,
|
||||||
getCalendarsListAsync,
|
getCalendarsListAsync,
|
||||||
} from "../../../features/Calendars/CalendarSlice";
|
} from "../../../features/Calendars/CalendarSlice";
|
||||||
@@ -119,7 +119,7 @@ export async function refreshCalendars(
|
|||||||
calType?: "temp"
|
calType?: "temp"
|
||||||
) {
|
) {
|
||||||
!calType && (await dispatch(getCalendarsListAsync()));
|
!calType && (await dispatch(getCalendarsListAsync()));
|
||||||
calType && dispatch(emptyTempCal());
|
calType && dispatch(emptyEventsCal({ calType }));
|
||||||
|
|
||||||
calendars.map(
|
calendars.map(
|
||||||
async (cal) =>
|
async (cal) =>
|
||||||
@@ -135,3 +135,23 @@ export async function refreshCalendars(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function refreshSingularCalendar(
|
||||||
|
dispatch: ThunkDispatch<any, any, any>,
|
||||||
|
calendar: Calendars,
|
||||||
|
calendarRange: { start: Date; end: Date },
|
||||||
|
calType?: "temp"
|
||||||
|
) {
|
||||||
|
dispatch(emptyEventsCal({ calId: calendar.id, calType }));
|
||||||
|
|
||||||
|
await dispatch(
|
||||||
|
getCalendarDetailAsync({
|
||||||
|
calId: calendar.id,
|
||||||
|
match: {
|
||||||
|
start: formatDateToYYYYMMDDTHHMMSS(calendarRange.start),
|
||||||
|
end: formatDateToYYYYMMDDTHHMMSS(calendarRange.end),
|
||||||
|
},
|
||||||
|
calType,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -422,10 +422,19 @@ const CalendarSlice = createSlice({
|
|||||||
removeTempCal: (state, action: PayloadAction<string>) => {
|
removeTempCal: (state, action: PayloadAction<string>) => {
|
||||||
delete state.templist[action.payload];
|
delete state.templist[action.payload];
|
||||||
},
|
},
|
||||||
emptyTempCal: (state) => {
|
emptyEventsCal: (
|
||||||
Object.keys(state.templist).forEach(
|
state,
|
||||||
(calId) => (state.templist[calId].events = {})
|
action: PayloadAction<{ calId?: string; calType?: "temp" }>
|
||||||
);
|
) => {
|
||||||
|
const cals =
|
||||||
|
action.payload.calType === "temp" ? state.templist : state.list;
|
||||||
|
if (action.payload.calId) {
|
||||||
|
cals[action.payload.calId].events = {};
|
||||||
|
} else {
|
||||||
|
Object.keys(state.templist).forEach(
|
||||||
|
(calId) => (cals[calId].events = {})
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
updateEventLocal: (
|
updateEventLocal: (
|
||||||
state,
|
state,
|
||||||
@@ -707,7 +716,7 @@ export const {
|
|||||||
createCalendar,
|
createCalendar,
|
||||||
updateEventLocal,
|
updateEventLocal,
|
||||||
removeTempCal,
|
removeTempCal,
|
||||||
emptyTempCal,
|
emptyEventsCal,
|
||||||
setTimeZone,
|
setTimeZone,
|
||||||
clearFetchCache,
|
clearFetchCache,
|
||||||
} = CalendarSlice.actions;
|
} = CalendarSlice.actions;
|
||||||
|
|||||||
@@ -36,12 +36,10 @@ import {
|
|||||||
handleRSVP,
|
handleRSVP,
|
||||||
} from "../../components/Event/eventHandlers/eventHandlers";
|
} from "../../components/Event/eventHandlers/eventHandlers";
|
||||||
import { InfoRow } from "../../components/Event/InfoRow";
|
import { InfoRow } from "../../components/Event/InfoRow";
|
||||||
import {
|
import { renderAttendeeBadge } from "../../components/Event/utils/eventUtils";
|
||||||
refreshCalendars,
|
|
||||||
renderAttendeeBadge,
|
|
||||||
} from "../../components/Event/utils/eventUtils";
|
|
||||||
import { getTimezoneOffset } from "../../components/Calendar/TimezoneSelector";
|
import { getTimezoneOffset } from "../../components/Calendar/TimezoneSelector";
|
||||||
import { getCalendarRange } from "../../utils/dateUtils";
|
import { getCalendarRange } from "../../utils/dateUtils";
|
||||||
|
import { updateTempCalendar } from "../../components/Calendar/utils/calendarUtils";
|
||||||
export default function EventPreviewModal({
|
export default function EventPreviewModal({
|
||||||
eventId,
|
eventId,
|
||||||
calId,
|
calId,
|
||||||
@@ -114,14 +112,14 @@ export default function EventPreviewModal({
|
|||||||
(a) => a.cal_address === event.organizer?.cal_address
|
(a) => a.cal_address === event.organizer?.cal_address
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateTempList = () => {
|
const updateTempList = async () => {
|
||||||
if (calendars.templist) {
|
if (calendars.templist) {
|
||||||
const calendarRange = getCalendarRange(new Date(event.start));
|
const calendarRange = getCalendarRange(new Date(event.start));
|
||||||
refreshCalendars(
|
await updateTempCalendar(
|
||||||
|
calendars.templist,
|
||||||
|
event,
|
||||||
dispatch,
|
dispatch,
|
||||||
Object.values(calendars.templist),
|
calendarRange
|
||||||
calendarRange,
|
|
||||||
"temp"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import {
|
|||||||
resolveTimezone,
|
resolveTimezone,
|
||||||
} from "../../components/Calendar/TimezoneSelector";
|
} from "../../components/Calendar/TimezoneSelector";
|
||||||
import { getCalendarRange } from "../../utils/dateUtils";
|
import { getCalendarRange } from "../../utils/dateUtils";
|
||||||
import { refreshCalendars } from "../../components/Event/utils/eventUtils";
|
import { updateTempCalendar } from "../../components/Calendar/utils/calendarUtils";
|
||||||
|
|
||||||
// Helper component for field with label
|
// Helper component for field with label
|
||||||
const FieldWithLabel = React.memo(
|
const FieldWithLabel = React.memo(
|
||||||
@@ -409,12 +409,7 @@ function EventPopover({
|
|||||||
);
|
);
|
||||||
if (tempList) {
|
if (tempList) {
|
||||||
const calendarRange = getCalendarRange(new Date(start));
|
const calendarRange = getCalendarRange(new Date(start));
|
||||||
refreshCalendars(
|
await updateTempCalendar(tempList, newEvent, dispatch, calendarRange);
|
||||||
dispatch,
|
|
||||||
Object.values(tempList),
|
|
||||||
calendarRange,
|
|
||||||
"temp"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
combineMasterDateWithFormTime,
|
combineMasterDateWithFormTime,
|
||||||
detectRecurringEventChanges,
|
detectRecurringEventChanges,
|
||||||
} from "./eventUtils";
|
} from "./eventUtils";
|
||||||
|
import { updateTempCalendar } from "../../components/Calendar/utils/calendarUtils";
|
||||||
|
|
||||||
const showErrorNotification = (message: string) => {
|
const showErrorNotification = (message: string) => {
|
||||||
console.error(`[ERROR] ${message}`);
|
console.error(`[ERROR] ${message}`);
|
||||||
@@ -478,12 +479,7 @@ function EventUpdateModal({
|
|||||||
}
|
}
|
||||||
if (tempList) {
|
if (tempList) {
|
||||||
const calendarRange = getCalendarRange(new Date(start));
|
const calendarRange = getCalendarRange(new Date(start));
|
||||||
refreshCalendars(
|
await updateTempCalendar(tempList, event, dispatch, calendarRange);
|
||||||
dispatch,
|
|
||||||
Object.values(tempList),
|
|
||||||
calendarRange,
|
|
||||||
"temp"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -658,12 +654,7 @@ function EventUpdateModal({
|
|||||||
}
|
}
|
||||||
if (tempList) {
|
if (tempList) {
|
||||||
const calendarRange = getCalendarRange(new Date(start));
|
const calendarRange = getCalendarRange(new Date(start));
|
||||||
refreshCalendars(
|
await updateTempCalendar(tempList, event, dispatch, calendarRange);
|
||||||
dispatch,
|
|
||||||
Object.values(tempList),
|
|
||||||
calendarRange,
|
|
||||||
"temp"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user