Skip to content

Instantly share code, notes, and snippets.

@Shaunmak1214
Last active September 4, 2022 05:06
Show Gist options
  • Save Shaunmak1214/e0d601995eb9ffac6b0d7379b72ff85e to your computer and use it in GitHub Desktop.
Save Shaunmak1214/e0d601995eb9ffac6b0d7379b72ff85e to your computer and use it in GitHub Desktop.
An alert dialog wrapper that support asynchronous handling of confirmations. Providing a function-like type approach to instantiate your alert dialog
import React, { useRef } from 'react';
import {
AlertDialog,
AlertDialogBody,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogContent,
AlertDialogOverlay,
AlertDialogCloseButton,
useDisclosure,
AlertDialogProps,
Button,
ModalContentProps,
} from '@chakra-ui/react';
interface IProps {
renderButton: boolean;
customButtonComponent?: React.ReactNode;
buttonTitle?: string;
alertDialogProps?: AlertDialogProps;
alertDialogContentProps?: ModalContentProps;
cancelButtonTitle?: string;
confirmButtonTitle?: string;
isConfirmLoading?: boolean;
}
const useAlertDialog = () => {
const { isOpen, onOpen, onClose } = useDisclosure();
const cancelRef = useRef();
const [alertDialogTitle, setAlertDialogTitle] = React.useState<string>('');
const [alertDialogContent, setAlertDialogContent] =
React.useState<React.ReactNode>(null);
const awaitingPromiseRef = React.useRef<{
resolve: () => void;
reject: () => void;
}>();
const onConfirmPromise = React.useCallback(() => {
if (awaitingPromiseRef.current) {
awaitingPromiseRef.current.resolve();
awaitingPromiseRef.current = undefined;
}
onClose();
}, []);
const onCancelPromise = React.useCallback(() => {
if (awaitingPromiseRef.current) {
awaitingPromiseRef.current.reject();
awaitingPromiseRef.current = undefined;
}
onClose();
}, []);
interface IShowDialogProps {
title: string;
content: React.ReactNode;
}
const showDialog = ({ title, content }: IShowDialogProps) => {
setAlertDialogTitle(title);
setAlertDialogContent(content);
return new Promise((resolve, reject) => {
awaitingPromiseRef.current = { resolve, reject };
onOpen();
});
};
const AlertDialogWrapper = ({
renderButton,
customButtonComponent,
buttonTitle,
alertDialogProps,
alertDialogContentProps,
cancelButtonTitle,
confirmButtonTitle,
isConfirmLoading,
}: IProps) => {
return (
<>
{renderButton &&
(customButtonComponent ? (
customButtonComponent
) : (
<Button onClick={onOpen}>
{buttonTitle ? buttonTitle : 'Discard'}
</Button>
))}
<AlertDialog
motionPreset="slideInBottom"
leastDestructiveRef={cancelRef}
onClose={onClose}
isOpen={isOpen}
isCentered
{...alertDialogProps}
>
<AlertDialogOverlay />
<AlertDialogContent {...alertDialogContentProps}>
<AlertDialogHeader>
{alertDialogTitle ? alertDialogTitle : 'Discard Changes'}
</AlertDialogHeader>
<AlertDialogCloseButton
onClick={() => {
onCancelPromise();
}}
/>
<AlertDialogBody>
{alertDialogContent ? alertDialogContent : null}
</AlertDialogBody>
<AlertDialogFooter>
<Button
ref={cancelRef}
onClick={() => {
onCancelPromise();
}}
>
{cancelButtonTitle ? cancelButtonTitle : 'Cancel'}
</Button>
<Button
colorScheme="red"
ml={3}
onClick={() => {
onConfirmPromise();
}}
isLoading={isConfirmLoading}
>
{confirmButtonTitle ? confirmButtonTitle : 'Discard'}
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
);
};
React.memo(AlertDialogWrapper);
return {
AlertDialogWrapper,
isOpen,
onOpen,
onClose,
showDialog,
};
};
export default useAlertDialog;
const { AlertDialogWrapper, showDialog } = useAlertDialog();
return (
<AlertDialogWrapper renderButton={false} />
<button onClick={() => { showDialog() }}>Show Dialog</button>
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment