From b5cad72289fbecfedf1a897507a3fa60ec67aeed Mon Sep 17 00:00:00 2001 From: Matt Warman Date: Thu, 5 Dec 2024 08:23:51 -0500 Subject: [PATCH] 71 Delete Task (#79) * initial Dialog components * disable toggle when processing * docs * TaskDeleteDialog component * docs * tests * tests * tests * tests * tests * docs --- src/common/components/Dialog/Backdrop.tsx | 46 +++++++++ src/common/components/Dialog/Dialog.tsx | 69 +++++++++++++ src/common/components/Dialog/DialogButton.tsx | 45 +++++++++ .../components/Dialog/DialogButtons.tsx | 34 +++++++ .../components/Dialog/DialogContent.tsx | 30 ++++++ .../components/Dialog/DialogHeading.tsx | 30 ++++++ src/common/components/Dialog/Divider.tsx | 25 +++++ .../Dialog/__tests__/Backdrop.test.tsx | 50 ++++++++++ .../Dialog/__tests__/DiaglogButtons.test.tsx | 47 +++++++++ .../Dialog/__tests__/Dialog.test.tsx | 98 +++++++++++++++++++ .../Dialog/__tests__/DialogButton.test.tsx | 53 ++++++++++ .../Dialog/__tests__/DialogContent.test.tsx | 34 +++++++ .../Dialog/__tests__/DialogHeading.test.tsx | 34 +++++++ .../Dialog/__tests__/Divider.test.tsx | 34 +++++++ .../Tasks/api/__tests__/useDeleteTask.test.ts | 59 +++++++++++ .../UsersPage/Tasks/api/useDeleteTask.ts | 50 ++++++++++ .../UsersPage/Tasks/api/useUpdateTask.ts | 2 +- .../Tasks/components/TaskCompleteToggle.tsx | 3 +- .../Tasks/components/TaskDeleteDialog.tsx | 60 ++++++++++++ .../UsersPage/Tasks/components/TaskDetail.tsx | 72 ++++++++++++-- .../__tests__/TaskDeleteDialog.test.tsx | 78 +++++++++++++++ .../components/__tests__/TaskDetail.test.tsx | 81 ++++++++++++++- src/test/mocks/handlers.ts | 9 ++ 23 files changed, 1030 insertions(+), 13 deletions(-) create mode 100644 src/common/components/Dialog/Backdrop.tsx create mode 100644 src/common/components/Dialog/Dialog.tsx create mode 100644 src/common/components/Dialog/DialogButton.tsx create mode 100644 src/common/components/Dialog/DialogButtons.tsx create mode 100644 src/common/components/Dialog/DialogContent.tsx create mode 100644 src/common/components/Dialog/DialogHeading.tsx create mode 100644 src/common/components/Dialog/Divider.tsx create mode 100644 src/common/components/Dialog/__tests__/Backdrop.test.tsx create mode 100644 src/common/components/Dialog/__tests__/DiaglogButtons.test.tsx create mode 100644 src/common/components/Dialog/__tests__/Dialog.test.tsx create mode 100644 src/common/components/Dialog/__tests__/DialogButton.test.tsx create mode 100644 src/common/components/Dialog/__tests__/DialogContent.test.tsx create mode 100644 src/common/components/Dialog/__tests__/DialogHeading.test.tsx create mode 100644 src/common/components/Dialog/__tests__/Divider.test.tsx create mode 100644 src/pages/UsersPage/Tasks/api/__tests__/useDeleteTask.test.ts create mode 100644 src/pages/UsersPage/Tasks/api/useDeleteTask.ts create mode 100644 src/pages/UsersPage/Tasks/components/TaskDeleteDialog.tsx create mode 100644 src/pages/UsersPage/Tasks/components/__tests__/TaskDeleteDialog.test.tsx diff --git a/src/common/components/Dialog/Backdrop.tsx b/src/common/components/Dialog/Backdrop.tsx new file mode 100644 index 0000000..3549bdc --- /dev/null +++ b/src/common/components/Dialog/Backdrop.tsx @@ -0,0 +1,46 @@ +import { PropsWithChildren } from 'react'; +import { BaseComponentProps } from '@leanstacks/react-common'; +import classNames from 'classnames'; + +/** + * Properties for the `Backdrop` component. + * @param {function} [onClick] - Optional. A function called when clicked. + * @see {@link BaseComponentProps} + * @see {@link PropsWithChildren} + */ +interface BackdropProps extends BaseComponentProps, PropsWithChildren { + onClick?: (e: React.MouseEvent) => void | Promise; +} + +/** + * The `Backdrop` component renders a semi-opaque background for another + * component. Usually used to partially mask background content to draw + * attention to content in the foreground such as a `Dialog` or `Menu`. + * @param {BackgroundProps} props - Component properties + * @returns {JSX.Element} JSX + */ +const Backdrop = ({ + children, + className, + onClick, + testId = 'backdrop', +}: BackdropProps): JSX.Element => { + const handleClick = (e: React.MouseEvent) => { + onClick?.(e); + }; + + return ( +
+ {children} +
+ ); +}; + +export default Backdrop; diff --git a/src/common/components/Dialog/Dialog.tsx b/src/common/components/Dialog/Dialog.tsx new file mode 100644 index 0000000..19e9817 --- /dev/null +++ b/src/common/components/Dialog/Dialog.tsx @@ -0,0 +1,69 @@ +import { PropsWithChildren, useEffect, useState } from 'react'; +import { BaseComponentProps } from '@leanstacks/react-common'; +import classNames from 'classnames'; + +import Backdrop from './Backdrop'; + +/** + * Properties for the `Dialog` component. + * @param {boolean} [isOpen] - Indicates if the Dialog should be displayed. + * @param {function} [onClose] - A function called when the Dialog closes. + * @see {@link BaseComponentProps} + * @see {@link PropsWithChildren} + */ +export interface DialogProps extends BaseComponentProps, PropsWithChildren { + isOpen?: boolean; + onClose?: () => void | Promise; +} + +/** + * A `Dialog` is a modal window that displays on top of the main content, + * typically asking the user to take an action or confirm a decision. + * @param {DialogProps} props - Component properties. + * @returns {JSX.Element} JSX + */ +const Dialog = ({ + children, + className, + isOpen = false, + onClose, + testId = 'dialog', +}: DialogProps): JSX.Element => { + const [isDialogOpen, setIsDialogOpen] = useState(false); + + useEffect(() => { + setIsDialogOpen(isOpen); + }, [isOpen]); + + const closeDialog = (): void => { + setIsDialogOpen(false); + onClose?.(); + }; + + const handleBackdropClick = (): void => { + closeDialog(); + }; + + const handleDialogClick = (e: React.MouseEvent): void => { + e.stopPropagation(); + }; + + return ( +
+ +
+ {children} +
+
+
+ ); +}; + +export default Dialog; diff --git a/src/common/components/Dialog/DialogButton.tsx b/src/common/components/Dialog/DialogButton.tsx new file mode 100644 index 0000000..cef0a65 --- /dev/null +++ b/src/common/components/Dialog/DialogButton.tsx @@ -0,0 +1,45 @@ +import { Button, ButtonProps, ButtonVariant } from '@leanstacks/react-common'; +import classNames from 'classnames'; + +/** + * Variations of the `DialogButton`. + */ +type DialogButtonVariant = 'primary' | 'secondary' | 'danger'; + +/** + * Properties for the `DialogButton` component. + * @param {DialogButtonVariant} variant - The variant. + * @see {@link ButtonProps} + */ +interface DialogButtonProps extends Omit { + variant?: DialogButtonVariant; +} + +/** + * The `DialogButton` is a type of `Button` specifically styled for use + * within a `Dialog`. + * @param {DialogButtonProps} props - Component properties. + * @returns {JSX.Element} JSX + */ +const DialogButton = ({ + className, + variant = 'secondary', + testId = 'dialog-button', + ...buttonProps +}: DialogButtonProps): JSX.Element => { + return ( + +