feat(customHomePage): add remove module confirmation (#14363)

Co-authored-by: Chris Collins <chriscollins3456@gmail.com>
This commit is contained in:
v-tarasevich-blitz-brain 2025-08-11 20:40:17 +03:00 committed by GitHub
parent 519fc3fd24
commit acc7785e88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 99 additions and 46 deletions

View File

@ -1,11 +1,13 @@
import { Icon, Text, Tooltip, colors } from '@components';
import { Dropdown } from 'antd';
import React, { useCallback } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import styled from 'styled-components';
import { usePageTemplateContext } from '@app/homeV3/context/PageTemplateContext';
import { DEFAULT_GLOBAL_MODULE_TYPES } from '@app/homeV3/modules/constants';
import { getCustomGlobalModules } from '@app/homeV3/template/components/addModuleMenu/utils';
import { ModulePositionInput } from '@app/homeV3/template/types';
import { ConfirmationModal } from '@app/sharedV2/modals/ConfirmationModal';
import { PageModuleFragment } from '@graphql/template.generated';
@ -32,9 +34,16 @@ interface Props {
}
export default function ModuleMenu({ module, position }: Props) {
const [showRemoveModuleConfirmation, setShowRemoveModuleConfirmation] = useState<boolean>(false);
const { type } = module.properties;
const canEdit = !DEFAULT_GLOBAL_MODULE_TYPES.includes(type);
const { globalTemplate } = usePageTemplateContext();
const isAdminCreatedModule = useMemo(() => {
const adminCreatedModules = getCustomGlobalModules(globalTemplate);
return adminCreatedModules.some((adminCreatedModule) => adminCreatedModule.urn === module.urn);
}, [globalTemplate, module.urn]);
const {
removeModule,
moduleModalState: { openToEdit },
@ -58,6 +67,7 @@ export default function ModuleMenu({ module, position }: Props) {
const menuItemStyle = { fontSize: '14px', padding: '5px 16px' };
return (
<>
<DropdownWrapper onClick={handleMenuClick}>
<Dropdown
trigger={['click']}
@ -97,7 +107,7 @@ export default function ModuleMenu({ module, position }: Props) {
...menuItemStyle,
color: colors.red[500],
},
onClick: handleRemove,
onClick: () => setShowRemoveModuleConfirmation(true),
},
],
}}
@ -105,5 +115,20 @@ export default function ModuleMenu({ module, position }: Props) {
<StyledIcon icon="DotsThreeVertical" source="phosphor" size="lg" />
</Dropdown>
</DropdownWrapper>
<ConfirmationModal
isOpen={!!showRemoveModuleConfirmation}
handleConfirm={handleRemove}
handleClose={() => setShowRemoveModuleConfirmation(false)}
modalTitle="Remove Module?"
modalText={
isAdminCreatedModule
? 'Are you sure you want to remove this module? You can re-add it later from the Home Defaults section when adding a new module.'
: 'Are you sure you want to remove this module? You can always create a new one later if needed.'
}
closeButtonText="Cancel"
confirmButtonText="Confirm"
/>
</>
);
}

View File

@ -27,6 +27,13 @@ vi.mock('@components', () => ({
)),
Tooltip: (props: any) => <span {...props} />,
Text: (props: any) => <p {...props} />,
Button: (props: any) => <button type="button" data-testid="confirm" {...props} />,
Heading: (props: any) => <p {...props} />,
typography: {
fonts: {
body: '#eeeeee',
},
},
colors: {
gray: {
600: '#4B5563',
@ -81,6 +88,9 @@ describe('ModuleMenu', () => {
// Click the remove option
const removeButton = screen.getByText('Remove');
fireEvent.click(removeButton);
// Confirm removing
const confirm = screen.getByTestId('modal-confirm-button');
fireEvent.click(confirm);
// Verify that removeModule was called with correct parameters
expect(mockRemoveModule).toHaveBeenCalledWith({
@ -115,6 +125,9 @@ describe('ModuleMenu', () => {
// Click the remove option
const removeButton = screen.getByText('Remove');
fireEvent.click(removeButton);
// Confirm removing
const confirm = screen.getByTestId('modal-confirm-button');
fireEvent.click(confirm);
// Verify that removeModule was called with correct parameters
expect(mockRemoveModule).toHaveBeenCalledWith({
@ -152,6 +165,9 @@ describe('ModuleMenu', () => {
// Click the remove option
const removeButton = screen.getByText('Remove');
fireEvent.click(removeButton);
// Confirm removing
const confirm = screen.getByTestId('modal-confirm-button');
fireEvent.click(confirm);
// Verify that removeModule was called with moduleIndex
expect(mockRemoveModule).toHaveBeenCalledWith({
@ -181,6 +197,9 @@ describe('ModuleMenu', () => {
// Click the remove option
const removeButton = screen.getByText('Remove');
fireEvent.click(removeButton);
// Confirm removing
const confirm = screen.getByTestId('modal-confirm-button');
fireEvent.click(confirm);
// Verify that removeModule was called with correct URN
expect(mockRemoveModule).toHaveBeenCalledWith({
@ -204,6 +223,9 @@ describe('ModuleMenu', () => {
// Click the remove option
const removeButton = screen.getByText('Remove');
fireEvent.click(removeButton);
// Confirm removing
const confirm = screen.getByTestId('modal-confirm-button');
fireEvent.click(confirm);
// Verify that removeModule was called with minimal position
expect(mockRemoveModule).toHaveBeenCalledWith({
@ -233,6 +255,9 @@ describe('ModuleMenu', () => {
// Click the remove option
const removeButton = screen.getByText('Remove');
fireEvent.click(removeButton);
// Confirm removing
const confirm = screen.getByTestId('modal-confirm-button');
fireEvent.click(confirm);
// Verify that removeModule was called with special character URN
expect(mockRemoveModule).toHaveBeenCalledWith({
@ -270,11 +295,14 @@ describe('ModuleMenu', () => {
const menuButton = screen.getByTestId('icon');
fireEvent.click(menuButton);
// Click the remove option multiple times rapidly
// Click the remove option
const removeButton = screen.getByText('Remove');
fireEvent.click(removeButton);
fireEvent.click(removeButton);
fireEvent.click(removeButton);
// Click confirm multiple times rapidly
const confirm = screen.getByTestId('modal-confirm-button');
fireEvent.click(confirm);
fireEvent.click(confirm);
fireEvent.click(confirm);
// Verify that removeModule was called multiple times (as expected)
expect(mockRemoveModule).toHaveBeenCalledTimes(3);