From 8a7d2f742abc89959ed2a5f7f8d825ec5c616087 Mon Sep 17 00:00:00 2001 From: Camille Moussu <66134347+Eriikah@users.noreply.github.com> Date: Thu, 18 Sep 2025 18:01:08 +0200 Subject: [PATCH] calendar list display improvments (#115) * [#60] added collapsible groups * [#60] factorized code and fixed tests * fixup! [#60] added collapsible groups * fixup! [#60] added collapsible groups --------- Co-authored-by: Camille Moussu --- __test__/components/Calendar.test.tsx | 23 ++- .../components/CalendarSelection.test.tsx | 4 +- src/components/Calendar/CalendarSelection.tsx | 170 ++++++++++++------ 3 files changed, 136 insertions(+), 61 deletions(-) diff --git a/__test__/components/Calendar.test.tsx b/__test__/components/Calendar.test.tsx index 3872439..9fa2866 100644 --- a/__test__/components/Calendar.test.tsx +++ b/__test__/components/Calendar.test.tsx @@ -123,7 +123,7 @@ describe("CalendarSelection", () => { renderWithProviders(, preloadedState); expect(screen.getByText("Personnal Calendars")).toBeInTheDocument(); expect(screen.getByText("Delegated Calendars")).toBeInTheDocument(); - expect(screen.getByText("Shared Calendars")).toBeInTheDocument(); + expect(screen.getByText("Other Calendars")).toBeInTheDocument(); expect(screen.getByLabelText("Calendar personnal")).toBeInTheDocument(); expect(screen.getByLabelText("Calendar delegated")).toBeInTheDocument(); @@ -147,4 +147,25 @@ describe("CalendarSelection", () => { expect(spy).toHaveBeenCalled(); }); }); + it("open accordeon when clicking on button only", () => { + renderWithProviders(, preloadedState); + expect(screen.getByText("Personnal Calendars")).toBeInTheDocument(); + expect(screen.getByText("Delegated Calendars")).toBeInTheDocument(); + expect(screen.getByText("Other Calendars")).toBeInTheDocument(); + + expect(screen.getByLabelText("Calendar personnal")).toBeInTheDocument(); + expect(screen.getByLabelText("Calendar delegated")).toBeInTheDocument(); + expect(screen.getByLabelText("Calendar shared")).toBeInTheDocument(); + + const delegatedAccordionSummary = screen + .getByText("Delegated Calendars") + .closest(".MuiAccordionSummary-root"); + + const addButton = screen.getAllByTestId("AddIcon")[1]; + fireEvent.click(addButton); + expect(delegatedAccordionSummary).toHaveAttribute("aria-expanded", "true"); + + fireEvent.click(addButton); + expect(delegatedAccordionSummary).toHaveAttribute("aria-expanded", "true"); + }); }); diff --git a/__test__/components/CalendarSelection.test.tsx b/__test__/components/CalendarSelection.test.tsx index e3ad35f..15fbe44 100644 --- a/__test__/components/CalendarSelection.test.tsx +++ b/__test__/components/CalendarSelection.test.tsx @@ -50,7 +50,7 @@ describe("CalendarSelection", () => { expect(screen.getByText("Personnal Calendars")).toBeInTheDocument(); expect(screen.getByText("Delegated Calendars")).toBeInTheDocument(); - expect(screen.getByText("Shared Calendars")).toBeInTheDocument(); + expect(screen.getByText("Other Calendars")).toBeInTheDocument(); expect(screen.getByLabelText("Calendar personnal")).toBeChecked(); expect(screen.getByLabelText("Calendar delegated")).not.toBeChecked(); @@ -113,7 +113,7 @@ describe("CalendarSelection", () => { } ); - const addButton = screen.getByTestId("AddIcon"); + const addButton = screen.getAllByTestId("AddIcon")[0]; fireEvent.click(addButton); expect(screen.getByRole("presentation")).toBeInTheDocument(); diff --git a/src/components/Calendar/CalendarSelection.tsx b/src/components/Calendar/CalendarSelection.tsx index c6167e7..d526ed1 100644 --- a/src/components/Calendar/CalendarSelection.tsx +++ b/src/components/Calendar/CalendarSelection.tsx @@ -1,12 +1,78 @@ -import { useAppDispatch, useAppSelector } from "../../app/hooks"; +import Accordion from "@mui/material/Accordion"; +import AccordionDetails from "@mui/material/AccordionDetails"; +import AccordionSummary from "@mui/material/AccordionSummary"; +import Typography from "@mui/material/Typography"; +import { useAppSelector } from "../../app/hooks"; import AddIcon from "@mui/icons-material/Add"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import CalendarPopover from "../../features/Calendars/CalendarModal"; import { Calendars } from "../../features/Calendars/CalendarTypes"; import MoreVertIcon from "@mui/icons-material/MoreVert"; import IconButton from "@mui/material/IconButton"; import Checkbox from "@mui/material/Checkbox"; import Button from "@mui/material/Button"; +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; + +function CalendarAccordion({ + title, + calendars, + selectedCalendars, + handleToggle, + showAddButton = false, + onAddClick, + defaultExpanded = false, + setOpen, +}: { + title: string; + calendars: string[]; + selectedCalendars: string[]; + handleToggle: (id: string) => void; + showAddButton?: boolean; + onAddClick?: Function; + defaultExpanded?: boolean; + setOpen: Function; +}) { + const allCalendars = useAppSelector((state) => state.calendars.list); + + if (calendars.length === 0) return null; + const [expended, setExpended] = useState(defaultExpanded); + + return ( + + } + aria-controls={`${title}-content`} + id={`${title}-header`} + className="calendarListHeader" + onClick={() => setExpended(!expended)} + > + {title} + {showAddButton && ( + { + expended && e.stopPropagation(); + onAddClick && onAddClick(); + }} + > + + + )} + + + {calendars.map((id) => + CalendarSelector( + allCalendars, + id, + selectedCalendars, + handleToggle, + () => setOpen(id) + ) + )} + + + ); +} export default function CalendarSelection({ selectedCalendars, @@ -17,6 +83,7 @@ export default function CalendarSelection({ }) { const userId = useAppSelector((state) => state.user.userData.openpaasId); const calendars = useAppSelector((state) => state.calendars.list); + const personnalCalendars = Object.keys(calendars).filter( (id) => id.split("/")[0] === userId ); @@ -26,6 +93,7 @@ export default function CalendarSelection({ const sharedCalendars = Object.keys(calendars).filter( (id) => id.split("/")[0] !== userId && !calendars[id].delegated ); + const handleCalendarToggle = (name: string) => { setSelectedCalendars((prev: string[]) => prev.includes(name) ? prev.filter((n) => n !== name) : [...prev, name] @@ -37,67 +105,53 @@ export default function CalendarSelection({ return ( <>
-
-

Personnal Calendars

- -
- {personnalCalendars.map((id) => - CalendarSelector( - calendars, - id, - selectedCalendars, - handleCalendarToggle, - () => { - setAnchorElCal(document.body); - setSelectedCalId(id); - } - ) - )} - {delegatedCalendars.length > 0 && ( - <> - -

Delegated Calendars

-
- {delegatedCalendars.map((id) => - CalendarSelector( - calendars, - id, - selectedCalendars, - handleCalendarToggle, - () => { - setAnchorElCal(document.body); - setSelectedCalId(id); - } - ) - )} - - )} - {sharedCalendars.length > 0 && ( - <> - -

Shared Calendars

-
- {sharedCalendars.map((id) => - CalendarSelector( - calendars, - id, - selectedCalendars, - handleCalendarToggle, - () => { - setAnchorElCal(document.body); - setSelectedCalId(id); - } - ) - )} - - )} + setAnchorElCal(document.body)} + setOpen={(id: string) => { + setAnchorElCal(document.body); + setSelectedCalId(id); + }} + defaultExpanded + /> + + { + setAnchorElCal(document.body); + setSelectedCalId(id); + }} + /> + + { + setAnchorElCal(document.body); + }} + handleToggle={handleCalendarToggle} + setOpen={(id: string) => { + setAnchorElCal(document.body); + setSelectedCalId(id); + }} + />
+ { + setSelectedCalId(""); setAnchorElCal(null); }} calendar={calendars[selectedCalId] ?? undefined}