diff --git a/apps/calendar/src/components/popup/eventDetailPopup.spec.tsx b/apps/calendar/src/components/popup/eventDetailPopup.spec.tsx
index 46836999a..7667024bd 100644
--- a/apps/calendar/src/components/popup/eventDetailPopup.spec.tsx
+++ b/apps/calendar/src/components/popup/eventDetailPopup.spec.tsx
@@ -5,11 +5,12 @@ import { initCalendarStore, StoreProvider, useDispatch } from '@src/contexts/cal
import { EventBusProvider } from '@src/contexts/eventBus';
import { FloatingLayerProvider } from '@src/contexts/floatingLayer';
import EventModel from '@src/model/eventModel';
-import { render, screen } from '@src/test/utils';
+import { render, screen, userEvent } from '@src/test/utils';
import TZDate from '@src/time/date';
import { EventBusImpl } from '@src/utils/eventBus';
import type { PropsWithChildren } from '@t/components/common';
+import type { Options } from '@t/options';
describe('event detail popup', () => {
const mockCalendarId = 'calendarId';
@@ -48,7 +49,7 @@ describe('event detail popup', () => {
return {children};
};
- beforeEach(() => {
+ function setup(options: Options = {}) {
const eventBus = new EventBusImpl();
const store = initCalendarStore({
calendars: [
@@ -57,9 +58,14 @@ describe('event detail popup', () => {
name: mockCalendarName,
},
],
+ ...options,
});
- render(
+ // Spy should be set before rendering
+ const showFormPopupSpy = jest.fn();
+ store.getState().dispatch.popup.showFormPopup = showFormPopupSpy;
+
+ const renderResult = render(
@@ -68,9 +74,17 @@ describe('event detail popup', () => {
);
- });
+
+ return {
+ eventBus,
+ store,
+ renderResult,
+ showFormPopupSpy,
+ };
+ }
it('should display location when `event.location` is exists', () => {
+ setup();
const { location } = event;
const locationText = screen.getByText(location).textContent;
@@ -78,6 +92,7 @@ describe('event detail popup', () => {
});
it('should display recurrence rule when `event.recurrenceRule` is exists', () => {
+ setup();
const { recurrenceRule } = event;
const recurrenceRuleText = screen.getByText(recurrenceRule).textContent;
@@ -85,6 +100,7 @@ describe('event detail popup', () => {
});
it('should display attendees when `event.attendees` is exists', () => {
+ setup();
const { attendees } = event;
const text = attendees.join(', ');
const attendeesText = screen.getByText(text).textContent;
@@ -93,6 +109,7 @@ describe('event detail popup', () => {
});
it('should display state when `event.state` is exists', () => {
+ setup();
const { state } = event;
const stateText = screen.getByText(state).textContent;
@@ -100,12 +117,14 @@ describe('event detail popup', () => {
});
it('should display calendar name when `event.calendarId` and corresponding calendar is exists', () => {
+ setup();
const calendarName = screen.getByText(mockCalendarName);
expect(calendarName).toBeInTheDocument();
});
it('should display body when `event.body` is exists', () => {
+ setup();
const { body } = event;
const bodyText = screen.getByText(body).textContent;
@@ -113,10 +132,42 @@ describe('event detail popup', () => {
});
it('should display edit and delete buttons when event is not read only', () => {
+ setup();
const editButton = screen.getByText('Edit');
const deleteButton = screen.getByText('Delete');
expect(editButton).not.toBeNull();
expect(deleteButton).not.toBeNull();
});
+
+ it('should open the form popup when edit button is clicked, while the `useFormPopup` option is enabled', async () => {
+ // Given
+ const { showFormPopupSpy } = setup({ useFormPopup: true });
+ const user = userEvent.setup();
+ const editButton = screen.getByText('Edit');
+
+ // When
+ await user.click(editButton);
+
+ // Then
+ expect(showFormPopupSpy).toHaveBeenCalledWith(expect.objectContaining({ event }));
+ });
+
+ it('should only fire the `beforeUpdateEvent` event when edit button is clicked, while the `useFormPopup` option is disabled', async () => {
+ // Given
+ const { eventBus } = setup({ useFormPopup: false });
+ const mockEventHandler = jest.fn();
+ eventBus.on('beforeUpdateEvent', mockEventHandler);
+
+ const user = userEvent.setup();
+ const editButton = screen.getByText('Edit');
+
+ // When
+ await user.click(editButton);
+
+ // Then
+ expect(mockEventHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ event: event.toEventObject() })
+ );
+ });
});
diff --git a/apps/calendar/src/components/popup/eventDetailPopup.tsx b/apps/calendar/src/components/popup/eventDetailPopup.tsx
index abf67e211..34633e3e1 100644
--- a/apps/calendar/src/components/popup/eventDetailPopup.tsx
+++ b/apps/calendar/src/components/popup/eventDetailPopup.tsx
@@ -13,6 +13,7 @@ import { useLayoutContainer } from '@src/contexts/layoutContainer';
import { cls } from '@src/helpers/css';
import { isLeftOutOfLayout, isTopOutOfLayout } from '@src/helpers/popup';
import { useCalendarColor } from '@src/hooks/calendar/useCalendarColor';
+import { optionsSelector } from '@src/selectors';
import { eventDetailPopupParamSelector } from '@src/selectors/popup';
import TZDate from '@src/time/date';
import { isNil } from '@src/utils/type';
@@ -66,6 +67,7 @@ function calculatePopupArrowPosition(eventRect: Rect, layoutRect: Rect, popupRec
}
export function EventDetailPopup() {
+ const { useFormPopup } = useStore(optionsSelector);
const popupParams = useStore(eventDetailPopupParamSelector);
const { event, eventRect } = popupParams ?? {};
@@ -128,19 +130,24 @@ export function EventDetailPopup() {
left: eventRect.left + eventRect.width / 2,
};
- const onClickEditButton = () =>
- showFormPopup({
- isCreationPopup: false,
- event,
- title,
- location,
- start,
- end,
- isAllday,
- isPrivate,
- eventState: state,
- popupArrowPointPosition,
- });
+ const onClickEditButton = () => {
+ if (useFormPopup) {
+ showFormPopup({
+ isCreationPopup: false,
+ event,
+ title,
+ location,
+ start,
+ end,
+ isAllday,
+ isPrivate,
+ eventState: state,
+ popupArrowPointPosition,
+ });
+ } else {
+ eventBus.fire('beforeUpdateEvent', { event: event.toEventObject(), changes: {} });
+ }
+ };
const onClickDeleteButton = () => {
eventBus.fire('beforeDeleteEvent', event.toEventObject());
diff --git a/docs/en/apis/calendar.md b/docs/en/apis/calendar.md
index e2628eec2..629b2d336 100644
--- a/docs/en/apis/calendar.md
+++ b/docs/en/apis/calendar.md
@@ -809,8 +809,9 @@ The `event` property is information of the existing event, and the `changes` pro
In the following cases, `beforeUpdateEvent` is executed.
-- `When useFormPopup` and `useDetailPopup` of the calendar instance options are both `true` and the ‘Update’ button is pressed after modifying the event through the event details popup
+- When `useFormPopup` and `useDetailPopup` of the calendar instance options are both `true` and the ‘Update’ button is pressed after modifying the event through the event details popup
- ![Event execution through popup](../../assets/before-update-event-1.gif)
+- When the `useDetailPopup` option is `true` and the `useFormPopup` is `false`, the 'Edit' button inside the event details popup is pressed.
- When moving or resizing events by drag and drop, while `isReadOnly` is not `true` among calendar instance options and also `isReadOnly` is not `true` in the properties of individual events.
- ![Event execution via drag and drop](../../assets/before-update-event-2.gif)
diff --git a/docs/ko/apis/calendar.md b/docs/ko/apis/calendar.md
index 4714bcf8b..572577b19 100644
--- a/docs/ko/apis/calendar.md
+++ b/docs/ko/apis/calendar.md
@@ -815,8 +815,9 @@ interface UpdatedEventInfo {
다음의 경우 `beforeUpdateEvent` 가 실행된다.
-- 캘린더 인스턴스 옵션 중 `useFormPopup` 와 `useDetailPopup` 가 모두 `true` 이고, 이벤트 상세 팝업을 통해 이벤트를 수정 후 Update 버튼을 누를 때
+- 캘린더 인스턴스 옵션 중 `useFormPopup` 와 `useDetailPopup` 가 모두 `true` 이고, 이벤트 상세 팝업에서 Edit 버튼을 누른 후 표시되는 이벤트 폼 팝업에서 Update 버튼을 누를 때
- ![팝업을 통한 이벤트 실행](../../assets/before-update-event-1.gif)
+- 캘린더의 인스턴스 옵션 중 `useDetailPopup` 이 `true` 이고, `useFormPopup` 이 `false` 일 때, 이벤트 상세 팝업에서 Edit 버튼을 누른 경우
- 캘린더 인스턴스 옵션 중 `isReadOnly` 가 `true` 가 아니며, 개별 이벤트의 속성에 `isReadOnly` 가 `true` 가 아닌 상태에서 드래그 앤 드랍으로 일정을 이동하거나 리사이징할 때
- ![드래그 앤 드랍을 통한 이벤트 실행](../../assets/before-update-event-2.gif)