Skip to content

Commit

Permalink
chore(content-explorer): Migrate deleteConfirmationDialog
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-in-a-box committed Oct 7, 2024
1 parent 1850977 commit f09447c
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 111 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
README.md
flow-typed/*
1 change: 1 addition & 0 deletions flow-typed/npm/react-intl_v2.x.x.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,5 @@ declare module "react-intl" {
> {}
declare type IntlShape = $npm$ReactIntl$IntlShape;
declare type MessageDescriptor = $npm$ReactIntl$MessageDescriptor;
declare function useIntl(): $npm$ReactIntl$IntlShape;
}
2 changes: 2 additions & 0 deletions i18n/en-US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ be.delete = Delete
be.deleteDialogFileText = Are you sure you want to delete {name}?
# Text for delete confirmation dialog for folders
be.deleteDialogFolderText = Are you sure you want to delete {name} and all its contents?
# Header for delete confirmation dialog
be.deleteDialogHeader = Delete Item
# Label for delete confirmation dialog
be.deleteDialogLabel = Confirm Delete
# Label for the description field in the preview sidebar.
Expand Down
5 changes: 5 additions & 0 deletions src/elements/common/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,11 @@ const messages = defineMessages({
description: 'Label for item size attribute.',
defaultMessage: 'Size',
},
deleteDialogHeader: {
id: 'be.deleteDialogHeader',
description: 'Header for delete confirmation dialog',
defaultMessage: 'Delete Item',
},
deleteDialogLabel: {
id: 'be.deleteDialogLabel',
description: 'Label for delete confirmation dialog',
Expand Down
65 changes: 0 additions & 65 deletions src/elements/content-explorer/DeleteConfirmationDialog.js

This file was deleted.

51 changes: 51 additions & 0 deletions src/elements/content-explorer/DeleteConfirmationDialog.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// @flow
import * as React from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import { Modal } from '@box/blueprint-web';
import type { BoxItem } from '../../common/types/core';

import { TYPE_FOLDER } from '../../constants';

import messages from '../common/messages';

type Props = {
isLoading: boolean,
isOpen: boolean,
item: BoxItem,
onCancel: any,
onDelete: any,
parentElement: HTMLElement,
};

const DeleteConfirmationDialog = ({ isOpen, onDelete, onCancel, item, isLoading, parentElement }: Props) => {
const { formatMessage } = useIntl();
const message = item.type === TYPE_FOLDER ? messages.deleteDialogFolderText : messages.deleteDialogFileText;
return (
<Modal onOpenChange={onCancel} open={isOpen}>
<Modal.Content
aria-label={formatMessage(messages.deleteDialogLabel)}
className="bce-DeleteConfirmationDialog"
container={parentElement}
size="small"
>
<Modal.Body>
<FormattedMessage {...message} values={{ name: item.name }} />
</Modal.Body>
<Modal.Footer>
<Modal.Footer.SecondaryButton disabled={isLoading} onClick={onCancel}>
{formatMessage(messages.cancel)}
</Modal.Footer.SecondaryButton>
<Modal.Footer.PrimaryButton
loading={isLoading}
loadingAriaLabel={formatMessage(messages.loading)}
onClick={onDelete}
>
{formatMessage(messages.delete)}
</Modal.Footer.PrimaryButton>
</Modal.Footer>
</Modal.Content>
</Modal>
);
};

export default DeleteConfirmationDialog;
5 changes: 0 additions & 5 deletions src/elements/content-explorer/DeleteConfirmationDialog.scss

This file was deleted.

58 changes: 58 additions & 0 deletions src/elements/content-explorer/DeleteConfirmationDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import { Modal } from '@box/blueprint-web';
import type { BoxItem } from '../../common/types/core';

import { TYPE_FOLDER } from '../../constants';

import messages from '../common/messages';

export interface DeleteConfirmationDialogProps {
isLoading: boolean;
isOpen: boolean;
item: BoxItem;
onCancel: () => void;
onDelete: () => void;
parentElement: HTMLElement;
}

const DeleteConfirmationDialog = ({
isLoading,
isOpen,
item,
onCancel,
onDelete,
parentElement,
}: DeleteConfirmationDialogProps) => {
const { formatMessage } = useIntl();
const message = item.type === TYPE_FOLDER ? messages.deleteDialogFolderText : messages.deleteDialogFileText;
return (
<Modal onOpenChange={onCancel} open={isOpen}>
<Modal.Content
aria-label={formatMessage(messages.deleteDialogLabel)}
container={parentElement}
size="small"
>
<Modal.Header>{formatMessage(messages.deleteDialogHeader)}</Modal.Header>
<Modal.Body>
<FormattedMessage {...message} values={{ name: item.name }} />
</Modal.Body>
<Modal.Footer>
<Modal.Footer.SecondaryButton disabled={isLoading} onClick={onCancel}>
{formatMessage(messages.cancel)}
</Modal.Footer.SecondaryButton>
<Modal.Footer.PrimaryButton
loading={isLoading}
loadingAriaLabel={formatMessage(messages.loading)}
onClick={onDelete}
>
{formatMessage(messages.delete)}
</Modal.Footer.PrimaryButton>
</Modal.Footer>
<Modal.Close aria-label={formatMessage(messages.close)} />
</Modal.Content>
</Modal>
);
};

export default DeleteConfirmationDialog;
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from 'react';
import userEvent from '@testing-library/user-event';
import { render, screen } from '../../../test-utils/testing-library';
import DeleteConfirmationDialog, { DeleteConfirmationDialogProps } from '../DeleteConfirmationDialog';

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { TYPE_FOLDER } from '../../../constants';

const mockItem = { type: 'pdf', name: 'Test File' };
const mockFolderItem = { type: TYPE_FOLDER, name: 'Test Folder' };
const mockOnCancel = jest.fn();
const mockOnDelete = jest.fn();

const defaultProps = {
errorCode: '',
isLoading: false,
isOpen: false,
item: mockItem,
onCancel: jest.fn(),
onDelete: jest.fn(),
parentElement: document.body,
};

const renderComponent = (props: Partial<DeleteConfirmationDialogProps>) =>
render(<DeleteConfirmationDialog {...defaultProps} {...props} />);

describe('elements/content-explorer/DeleteConfirmationDialog', () => {
test('should render the dialog with file message', async () => {
renderComponent({ isOpen: true });

expect(await screen.findByText('Are you sure you want to delete Test File?')).toBeInTheDocument();
});

test('should render the dialog with folder message', async () => {
renderComponent({ isOpen: true, item: mockFolderItem });

expect(
await screen.findByText('Are you sure you want to delete Test Folder and all its contents?'),
).toBeInTheDocument();
});

test('should call onCancel when cancel button is clicked', async () => {
renderComponent({ isOpen: true, onCancel: mockOnCancel });

const cancelButton = screen.getByRole('button', { name: 'Cancel' });
await userEvent.click(cancelButton);
expect(mockOnCancel).toBeCalledTimes(1);
});

test('should call onDelete when delete button is clicked', async () => {
renderComponent({ isOpen: true, onDelete: mockOnDelete });

const deleteButton = screen.getByRole('button', { name: 'Delete' });
await userEvent.click(deleteButton);
expect(mockOnDelete).toBeCalledTimes(1);
});

test('should disable buttons when isLoading is true', () => {
renderComponent({ isOpen: true, isLoading: true });

const cancelButton = screen.getByRole('button', { name: 'Cancel' });
expect(cancelButton).toBeDisabled();
const loadingIndicator = screen.getByRole('status', { name: 'Loading' });
expect(loadingIndicator).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
// @flow
import * as React from 'react';
import { useArgs } from '@storybook/preview-api';

import PrimaryButton from '../../../components/primary-button/PrimaryButton';
import { Button } from '@box/blueprint-web';
import { addRootElement } from '../../../utils/storybook';

import DeleteConfirmationDialog from '../DeleteConfirmationDialog';

// need to import this into the story because it's usually in ContentExplorer
import '../../common/modal.scss';

export const deleteDialog = {
// eslint-disable-next-line react/prop-types
// eslint-disable-next-line @typescript-eslint/no-explicit-any
render: (args: any) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const [, setArgs] = useArgs();
Expand All @@ -22,27 +18,26 @@ export const deleteDialog = {
setArgs({ isOpen: false });
};

const { appElement, rootElement } = addRootElement();
const { rootElement } = addRootElement();

return (
<div>
<DeleteConfirmationDialog
appElement={appElement}
item={{
id: '123456',
name:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eget nulla facilisi etiam dignissim diam quis enim lobortis scelerisque. Aliquam faucibus purus in massa tempor nec. Ut consequat semper viverra nam libero justo laoreet sit amet. Purus gravida quis blandit turpis cursus in hac. Dui ut ornare lectus sit amet est. Nisl condimentum id venenatis a condimentum vitae sapien.',
name: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eget nulla facilisi etiam dignissim diam quis enim lobortis scelerisque. Aliquam faucibus purus in massa tempor nec. Ut consequat semper viverra nam libero justo laoreet sit amet. Purus gravida quis blandit turpis cursus in hac. Dui ut ornare lectus sit amet est. Nisl condimentum id venenatis a condimentum vitae sapien.',
}}
onCancel={handleCloseModal}
parentElement={rootElement}
{...args}
/>

<PrimaryButton onClick={handleOpenModal}>Launch DeleteConfirmationDialog</PrimaryButton>
<Button onClick={handleOpenModal} variant="primary">
Launch DeleteConfirmationDialog
</Button>
</div>
);
},
};
} as const;

export default {
title: 'Elements/ContentExplorer',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const openDeleteConfirmationDialog = {
await userEvent.click(moreOptionsButton);

const dropdown = await screen.findByRole('menu');
const deleteButton = within(dropdown).getByText('Delete');
const deleteButton = within(dropdown).findByText('Delete');
expect(deleteButton).toBeInTheDocument();
await userEvent.click(deleteButton);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,24 @@ import { addRootElement, defaultVisualConfig } from '../../../../utils/storybook

import DeleteConfirmationDialog from '../../DeleteConfirmationDialog';

// need to import this into the story because it's usually in ContentExplorer
import '../../../common/modal.scss';

const item = {
id: '123456',
name:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eget nulla facilisi etiam dignissim diam quis enim lobortis scelerisque. Aliquam faucibus purus in massa tempor nec. Ut consequat semper viverra nam libero justo laoreet sit amet. Purus gravida quis blandit turpis cursus in hac. Dui ut ornare lectus sit amet est. Nisl condimentum id venenatis a condimentum vitae sapien ',
name: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eget nulla facilisi etiam dignissim diam quis enim lobortis scelerisque. Aliquam faucibus purus in massa tempor nec. Ut consequat semper viverra nam libero justo laoreet sit amet. Purus gravida quis blandit turpis cursus in hac. Dui ut ornare lectus sit amet est. Nisl condimentum id venenatis a condimentum vitae sapien ',
};

export const deleteDialogNotLoading = {
render: () => {
const { appElement, rootElement } = addRootElement();

return (
<DeleteConfirmationDialog
appElement={appElement}
isLoading={false}
isOpen
item={item}
parentElement={rootElement}
/>
);
const { rootElement } = addRootElement();

return <DeleteConfirmationDialog isLoading={false} isOpen item={item} parentElement={rootElement} />;
},
};

export const deleteDialogIsLoading = {
render: () => {
const { appElement, rootElement } = addRootElement();

return (
<DeleteConfirmationDialog
appElement={appElement}
isLoading
isOpen
item={item}
parentElement={rootElement}
/>
);
const { rootElement } = addRootElement();

return <DeleteConfirmationDialog isLoading isOpen item={item} parentElement={rootElement} />;
},
};

Expand Down

0 comments on commit f09447c

Please sign in to comment.