From 4c18bf3a526ea0958009383a78577667ce81d424 Mon Sep 17 00:00:00 2001 From: lenhanphung Date: Mon, 13 Oct 2025 14:02:31 +0700 Subject: [PATCH] feat: Update event modal UI with header icons and improved actions layout - Add expand and close icons to ResponsiveDialog header in normal mode - Change 'Show More' button to 'More options' with Add icon - Hide Cancel button in normal mode, show only in extended mode - Add showHeaderActions prop to ResponsiveDialog for UI control - Preserve EventDisplayPreview modal with old UI (no header icons) - Update all affected test cases to match new UI behavior --- __test__/components/DuplicateEvent.test.tsx | 3 + __test__/components/RepeatEvent.test.tsx | 4 +- __test__/components/ResponsiveDialog.test.tsx | 76 +++++++++++++++++++ .../features/Calendars/CalendarModal.test.tsx | 9 ++- __test__/features/Events/EventModal.test.tsx | 7 +- src/components/Dialog/ResponsiveDialog.tsx | 29 +++++++ src/features/Events/EventDisplayPreview.tsx | 1 + src/features/Events/EventModal.tsx | 16 ++-- src/features/Events/EventUpdateModal.tsx | 13 +++- 9 files changed, 141 insertions(+), 17 deletions(-) diff --git a/__test__/components/DuplicateEvent.test.tsx b/__test__/components/DuplicateEvent.test.tsx index 92dbfe8..b612964 100644 --- a/__test__/components/DuplicateEvent.test.tsx +++ b/__test__/components/DuplicateEvent.test.tsx @@ -95,6 +95,9 @@ describe("EventDuplication", () => { fireEvent.click(screen.getByText("Duplicate event")); + // Cancel button only appears in expanded mode + fireEvent.click(screen.getByText("More options")); + fireEvent.click(screen.getByRole("button", { name: /Cancel/i })); expect(handleClose).toHaveBeenCalled(); diff --git a/__test__/components/RepeatEvent.test.tsx b/__test__/components/RepeatEvent.test.tsx index 66e03b1..99c97d4 100644 --- a/__test__/components/RepeatEvent.test.tsx +++ b/__test__/components/RepeatEvent.test.tsx @@ -102,8 +102,8 @@ async function setupEventPopover( const titleInput = screen.getByLabelText("Title"); fireEvent.change(titleInput, { target: { value: "Meeting" } }); - // Click Show More to expand the dialog - const showMoreButton = screen.getByText("Show More"); + // Click More options to expand the dialog + const showMoreButton = screen.getByText("More options"); fireEvent.click(showMoreButton); // Check Repeat checkbox to show repeat options diff --git a/__test__/components/ResponsiveDialog.test.tsx b/__test__/components/ResponsiveDialog.test.tsx index a78fd4c..54d2b37 100644 --- a/__test__/components/ResponsiveDialog.test.tsx +++ b/__test__/components/ResponsiveDialog.test.tsx @@ -295,4 +295,80 @@ describe("ResponsiveDialog", () => { expect(screen.getByText("Extended Content")).toBeInTheDocument(); expect(screen.getByLabelText("show less")).toBeInTheDocument(); }); + + it("renders expand and close icons in normal mode when showHeaderActions is true", () => { + render( + +
Content
+
+ ); + + expect(screen.getByLabelText("expand")).toBeInTheDocument(); + expect(screen.getByLabelText("close")).toBeInTheDocument(); + }); + + it("does not render header icons when showHeaderActions is false", () => { + render( + +
Content
+
+ ); + + expect(screen.queryByLabelText("expand")).not.toBeInTheDocument(); + expect(screen.queryByLabelText("close")).not.toBeInTheDocument(); + expect(screen.getByText("Test Title")).toBeInTheDocument(); + }); + + it("calls onClose when close icon is clicked", () => { + render( + +
Content
+
+ ); + + const closeButton = screen.getByLabelText("close"); + fireEvent.click(closeButton); + + expect(mockOnClose).toHaveBeenCalledTimes(1); + }); + + it("calls onExpandToggle when expand icon is clicked", () => { + render( + +
Content
+
+ ); + + const expandButton = screen.getByLabelText("expand"); + fireEvent.click(expandButton); + + expect(mockOnExpandToggle).toHaveBeenCalledTimes(1); + }); }); diff --git a/__test__/features/Calendars/CalendarModal.test.tsx b/__test__/features/Calendars/CalendarModal.test.tsx index 1783dcd..61527f0 100644 --- a/__test__/features/Calendars/CalendarModal.test.tsx +++ b/__test__/features/Calendars/CalendarModal.test.tsx @@ -325,9 +325,12 @@ describe("CalendarPopover - Tabs Scenarios", () => { const input = screen.getByLabelText(/CalDAV access/i); expect(input).toHaveValue("https://cal.example.org/calendars/user1/cal1"); - // Click copy button - const copyButton = screen.getAllByRole("button")[0]; - fireEvent.click(copyButton); + // Click copy button (find button containing ContentCopyIcon) + const copyIcon = screen.getByTestId("ContentCopyIcon"); + const copyButton = copyIcon.closest("button"); + if (copyButton) { + fireEvent.click(copyButton); + } expect(navigator.clipboard.writeText).toHaveBeenCalledWith( "https://cal.example.org/calendars/user1/cal1" diff --git a/__test__/features/Events/EventModal.test.tsx b/__test__/features/Events/EventModal.test.tsx index 03275b8..6b44658 100644 --- a/__test__/features/Events/EventModal.test.tsx +++ b/__test__/features/Events/EventModal.test.tsx @@ -124,10 +124,10 @@ describe("EventPopover", () => { expect(calendarSelect).toBeInTheDocument(); // Check button - expect(screen.getByText("Show More")).toBeInTheDocument(); + expect(screen.getByText("More options")).toBeInTheDocument(); // Extended mode - fireEvent.click(screen.getByText("Show More")); + fireEvent.click(screen.getByText("More options")); // Back button appears expect(screen.getByLabelText("show less")).toBeInTheDocument(); @@ -330,6 +330,9 @@ describe("EventPopover", () => { it("calls onClose when Cancel clicked", () => { renderPopover(); + // Cancel button only appears in expanded mode + fireEvent.click(screen.getByText("More options")); + fireEvent.click(screen.getByText("Cancel")); expect(mockOnClose).toHaveBeenCalledWith({}, "backdropClick"); diff --git a/src/components/Dialog/ResponsiveDialog.tsx b/src/components/Dialog/ResponsiveDialog.tsx index fe9bcb6..c1477d9 100644 --- a/src/components/Dialog/ResponsiveDialog.tsx +++ b/src/components/Dialog/ResponsiveDialog.tsx @@ -10,8 +10,11 @@ import { Stack, SxProps, Theme, + Box, } from "@mui/material"; import ArrowBackIcon from "@mui/icons-material/ArrowBack"; +import CloseIcon from "@mui/icons-material/Close"; +import OpenInFullIcon from "@mui/icons-material/OpenInFull"; import React, { ReactNode } from "react"; /** @@ -73,6 +76,8 @@ interface ResponsiveDialogProps dialogTitleProps?: Omit; /** Whether to display dividers between title/content/actions */ dividers?: boolean; + /** Whether to show header action icons (expand/close) in normal mode (default: true) */ + showHeaderActions?: boolean; } function ResponsiveDialog({ @@ -93,6 +98,7 @@ function ResponsiveDialog({ dialogContentProps, dialogTitleProps, dividers = false, + showHeaderActions = true, sx, ...otherDialogProps }: ResponsiveDialogProps) { @@ -150,6 +156,29 @@ function ResponsiveDialog({ > + ) : showHeaderActions ? ( + + {title} + + {onExpandToggle && ( + + + + )} + + + + + ) : ( title )} diff --git a/src/features/Events/EventDisplayPreview.tsx b/src/features/Events/EventDisplayPreview.tsx index 72eaf12..6066574 100644 --- a/src/features/Events/EventDisplayPreview.tsx +++ b/src/features/Events/EventDisplayPreview.tsx @@ -115,6 +115,7 @@ export default function EventPreviewModal({ onClose({}, "backdropClick")} + showHeaderActions={false} style={{ overflow: "auto" }} title={ event.title && ( diff --git a/src/features/Events/EventModal.tsx b/src/features/Events/EventModal.tsx index 2cb1458..307be39 100644 --- a/src/features/Events/EventModal.tsx +++ b/src/features/Events/EventModal.tsx @@ -1,7 +1,5 @@ import { CalendarApi, DateSelectArg } from "@fullcalendar/core"; import { - Box, - Button, Checkbox, FormControl, FormControlLabel, @@ -23,6 +21,8 @@ import { ContentCopy as CopyIcon, Close as DeleteIcon, } from "@mui/icons-material"; +import { Box, Button } from "@mui/material"; +import AddIcon from "@mui/icons-material/Add"; import React, { useEffect, useState, @@ -409,12 +409,16 @@ function EventPopover({ const dialogActions = ( {!showMore && ( - + )} - + {showMore && ( + + )} diff --git a/src/features/Events/EventUpdateModal.tsx b/src/features/Events/EventUpdateModal.tsx index 31bb817..ad85c46 100644 --- a/src/features/Events/EventUpdateModal.tsx +++ b/src/features/Events/EventUpdateModal.tsx @@ -1,4 +1,5 @@ import { Box, Button } from "@mui/material"; +import AddIcon from "@mui/icons-material/Add"; import React, { useEffect, useState, @@ -658,12 +659,16 @@ function EventUpdateModal({ const dialogActions = ( {!showMore && ( - + )} - + {showMore && ( + + )}