diff --git a/__test__/components/DuplicateEvent.test.tsx b/__test__/components/DuplicateEvent.test.tsx
new file mode 100644
index 0000000..32fff1a
--- /dev/null
+++ b/__test__/components/DuplicateEvent.test.tsx
@@ -0,0 +1,176 @@
+import { fireEvent, screen } from "@testing-library/react";
+import EventDuplication from "../../src/components/Event/EventDuplicate";
+import EventDisplayModal from "../../src/features/Events/EventDisplay";
+import EventPopover from "../../src/features/Events/EventModal";
+import { renderWithProviders } from "../utils/Renderwithproviders";
+import EventPreviewModal from "../../src/features/Events/EventDisplayPreview";
+
+const day = new Date();
+const preloadedState = {
+ user: {
+ userData: {
+ sub: "test",
+ email: "test@test.com",
+ sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
+ openpaasId: "667037022b752d0026472254",
+ },
+ organiserData: {
+ cn: "test",
+ cal_address: "mailto:test@test.com",
+ },
+ },
+ calendars: {
+ list: {
+ "667037022b752d0026472254/cal1": {
+ id: "667037022b752d0026472254/cal1",
+ name: "Calendar",
+ color: "#FF0000",
+ events: {
+ event1: {
+ uid: "event1",
+ URL: "calendars/667037022b752d0026472254/cal1/event1.ics",
+ title: "Test Event",
+ calId: "667037022b752d0026472254/cal1",
+ start: day,
+ end: day,
+ timezone: "UTC",
+ organizer: { cn: "test", cal_address: "test@test.com" },
+ attendee: [
+ {
+ cn: "test",
+ cal_address: "test@test.com",
+ partstat: "NEEDS-ACTION",
+ rsvp: "TRUE",
+ role: "REQ-PARTICIPANT",
+ cutype: "INDIVIDUAL",
+ },
+ {
+ cn: "John",
+ cal_address: "john@test.com",
+ partstat: "NEEDS-ACTION",
+ rsvp: "TRUE",
+ role: "REQ-PARTICIPANT",
+ cutype: "INDIVIDUAL",
+ },
+ ],
+ },
+ },
+ },
+ },
+ pending: false,
+ },
+};
+
+describe("EventDuplication", () => {
+ it("opens EventPopover when button clicked", () => {
+ const handleClose = jest.fn();
+ renderWithProviders(
+ ,
+ preloadedState
+ );
+
+ const button = screen.getByRole("button");
+ fireEvent.click(button);
+
+ expect(screen.getByText(/Duplicate Event/i)).toBeInTheDocument();
+ });
+
+ it("calls onClose when closing the popover", () => {
+ const handleClose = jest.fn();
+ renderWithProviders(
+ ,
+ preloadedState
+ );
+
+ fireEvent.click(screen.getByRole("button"));
+
+ fireEvent.click(screen.getByRole("button", { name: /Cancel/i }));
+
+ expect(handleClose).toHaveBeenCalled();
+ });
+});
+
+describe("EventPopover", () => {
+ it("renders with event data", () => {
+ renderWithProviders(
+ ,
+ preloadedState
+ );
+
+ expect(screen.getByDisplayValue(/Test Event/i)).toBeInTheDocument();
+ });
+
+ it("saves duplicated event when Save is clicked", () => {
+ const onClose = jest.fn();
+
+ renderWithProviders(
+ ,
+ preloadedState
+ );
+
+ fireEvent.change(screen.getByLabelText(/Title/i), {
+ target: { value: "Duplicated Event" },
+ });
+ fireEvent.click(screen.getByRole("button", { name: /Save/i }));
+
+ expect(onClose).toHaveBeenCalled();
+ });
+});
+
+describe("EventDisplayModal", () => {
+ it("shows duplication button and opens duplication form", () => {
+ renderWithProviders(
+ ,
+ preloadedState
+ );
+
+ fireEvent.click(screen.getByTestId("AddToPhotosIcon"));
+ expect(screen.getByText(/Duplicate Event/i)).toBeInTheDocument();
+ expect(
+ screen.getByDisplayValue(
+ preloadedState.calendars.list["667037022b752d0026472254/cal1"].events
+ .event1.title
+ )
+ ).toBeInTheDocument();
+ });
+});
diff --git a/__test__/features/Events/EventDisplay.test.tsx b/__test__/features/Events/EventDisplay.test.tsx
index 28ded30..0fee032 100644
--- a/__test__/features/Events/EventDisplay.test.tsx
+++ b/__test__/features/Events/EventDisplay.test.tsx
@@ -1137,13 +1137,7 @@ describe("Event Full Display", () => {
const day = new Date();
const preloadedTwoCals = {
- user: {
- userData: {
- sub: "test",
- email: "test@test.com",
- openpaasId: "667037022b752d0026472254",
- },
- },
+ ...preloadedState,
calendars: {
list: {
"667037022b752d0026472254/cal1": {
@@ -1210,13 +1204,7 @@ describe("Event Full Display", () => {
const day = new Date();
const preloadedRecurrence = {
- user: {
- userData: {
- sub: "test",
- email: "test@test.com",
- openpaasId: "667037022b752d0026472254",
- },
- },
+ ...preloadedState,
calendars: {
list: {
"667037022b752d0026472254/cal1": {
diff --git a/src/components/Event/EventDuplicate.tsx b/src/components/Event/EventDuplicate.tsx
new file mode 100644
index 0000000..9e5d453
--- /dev/null
+++ b/src/components/Event/EventDuplicate.tsx
@@ -0,0 +1,52 @@
+import { IconButton } from "@mui/material";
+import { CalendarEvent } from "../../features/Events/EventsTypes";
+import AddToPhotosIcon from "@mui/icons-material/AddToPhotos";
+import { useRef, useState } from "react";
+import EventPopover from "../../features/Events/EventModal";
+import { CalendarApi, DateSelectArg } from "@fullcalendar/core";
+
+export default function EventDuplication({
+ onClose,
+ event,
+}: {
+ onClose: Function;
+ event: CalendarEvent;
+}) {
+ const [openModal, setOpenModal] = useState(false);
+ const [selectedRange, setSelectedRange] = useState({
+ start: new Date(event.start),
+ startStr: new Date(event.start).toISOString(),
+ end: new Date(event.end ?? ""),
+ endStr: new Date(event.end ?? "").toISOString(),
+ allDay: event.allday ?? false,
+ } as DateSelectArg);
+ const calendarRef = useRef(null);
+
+ const handleClosePopover = () => {
+ calendarRef.current?.unselect();
+ setSelectedRange(null);
+ setOpenModal(!openModal);
+ onClose({}, "backdropClick");
+ };
+ return (
+ <>
+ {
+ setOpenModal(true);
+ }}
+ >
+
+
+
+ >
+ );
+}
diff --git a/src/features/Events/EventDisplayPreview.tsx b/src/features/Events/EventDisplayPreview.tsx
index a37e48c..7a58bb0 100644
--- a/src/features/Events/EventDisplayPreview.tsx
+++ b/src/features/Events/EventDisplayPreview.tsx
@@ -39,6 +39,7 @@ import EventDisplayModal, {
} from "./EventDisplay";
import { getEvent } from "./EventApi";
import { CalendarEvent } from "./EventsTypes";
+import EventDuplication from "../../components/Event/EventDuplicate";
export default function EventPreviewModal({
eventId,
@@ -122,6 +123,7 @@ export default function EventPreviewModal({
gap: 1,
}}
>
+
{mailSpaUrl && attendees.length > 0 && (
;
+ event?: CalendarEvent;
}) {
const dispatch = useAppDispatch();
@@ -63,20 +65,32 @@ function EventPopover({
const timezones = TIMEZONES.aliases;
const [showMore, setShowMore] = useState(false);
- const [title, setTitle] = useState("");
- const [description, setDescription] = useState("");
- const [location, setLocation] = useState("");
- const [start, setStart] = useState("");
- const [end, setEnd] = useState("");
- const [calendarid, setCalendarid] = useState(0);
- const [allday, setAllDay] = useState(false);
- const [repetition, setRepetition] = useState(
- {} as RepetitionObject
+ const [title, setTitle] = useState(event?.title ?? "");
+ const [description, setDescription] = useState(event?.description ?? "");
+ const [location, setLocation] = useState(event?.location ?? "");
+ const [start, setStart] = useState(
+ event?.start ? new Date(event.start).toISOString() : ""
);
- const [attendees, setAttendees] = useState([]);
- const [alarm, setAlarm] = useState("");
- const [eventClass, setEventClass] = useState("PUBLIC");
- const [busy, setBusy] = useState("OPAQUE");
+ const [end, setEnd] = useState(
+ event?.end ? new Date(event.end)?.toISOString() : ""
+ );
+ const [calendarid, setCalendarid] = useState(
+ event?.calId
+ ? userPersonnalCalendars.findIndex((e) => e.id === event?.calId)
+ : 0
+ );
+ const [allday, setAllDay] = useState(event?.allday ?? false);
+ const [repetition, setRepetition] = useState(
+ event?.repetition ?? ({} as RepetitionObject)
+ );
+ const [attendees, setAttendees] = useState(
+ event?.attendee
+ ? event.attendee.filter((a) => a.cal_address !== organizer.cal_address)
+ : []
+ );
+ const [alarm, setAlarm] = useState(event?.alarm?.trigger ?? "");
+ const [eventClass, setEventClass] = useState(event?.class ?? "PUBLIC");
+ const [busy, setBusy] = useState(event?.transp ?? "OPAQUE");
const [timezone, setTimezone] = useState(
Intl.DateTimeFormat().resolvedOptions().timeZone
@@ -157,7 +171,7 @@ function EventPopover({
}}
>
-
+
diff --git a/src/features/Events/EventsTypes.ts b/src/features/Events/EventsTypes.ts
index 93df014..94d1ee8 100644
--- a/src/features/Events/EventsTypes.ts
+++ b/src/features/Events/EventsTypes.ts
@@ -22,7 +22,7 @@ export interface CalendarEvent {
status?: string;
timezone: string;
repetition?: RepetitionObject;
- alarm: AlarmObject;
+ alarm?: AlarmObject;
}
export interface RepetitionObject {