| import { useRef } from "react"; |
| import { |
| Dialog, |
| DialogPanel, |
| Transition as HeadlessTransition, |
| TransitionChild as HeadlessTransitionChild, |
| } from "@headlessui/react"; |
| import { |
| CheckCircleIcon, |
| ExclamationTriangleIcon, |
| InformationCircleIcon, |
| XCircleIcon, |
| } from "@heroicons/react/24/outline"; |
|
|
| export enum AlertIcon { |
| Warning = "warning", |
| Success = "success", |
| Info = "info", |
| Error = "error", |
| } |
|
|
| export interface IAlertProps { |
| isOpen: boolean; |
| title: string; |
| message: string; |
| okText: string; |
| |
| icon: AlertIcon; |
| onSuccess: () => void; |
| onCancel: () => void; |
| } |
|
|
| export function AlertModal({ |
| isOpen, |
| title, |
| message, |
| okText, |
| icon, |
| onSuccess, |
| onCancel, |
| }: IAlertProps) { |
| const cancelButtonRef = useRef(null); |
|
|
| const getIconComponent = () => { |
| switch (icon) { |
| case AlertIcon.Warning: |
| return <ExclamationTriangleIcon className="h-6 w-6 text-red-600" />; |
| case AlertIcon.Success: |
| return <CheckCircleIcon className="h-6 w-6 text-green-600" />; |
| case AlertIcon.Info: |
| return <InformationCircleIcon className="h-6 w-6 text-blue-600" />; |
| case AlertIcon.Error: |
| default: |
| return <XCircleIcon className="h-6 w-6 text-gray-600" />; |
| } |
| }; |
|
|
| return ( |
| <HeadlessTransition show={isOpen}> |
| <Dialog |
| as="div" |
| className="relative z-10" |
| initialFocus={cancelButtonRef} |
| onClose={onCancel} |
| > |
| <HeadlessTransitionChild |
| enter="ease-out duration-300" |
| enterFrom="opacity-0" |
| enterTo="opacity-100" |
| leave="ease-in duration-200" |
| leaveFrom="opacity-100" |
| leaveTo="opacity-0" |
| > |
| <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" /> |
| </HeadlessTransitionChild> |
| |
| <div className="fixed inset-0 z-10 w-screen overflow-y-auto"> |
| <div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0"> |
| <HeadlessTransitionChild |
| enter="ease-out duration-300" |
| enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" |
| enterTo="opacity-100 translate-y-0 sm:scale-100" |
| leave="ease-in duration-200" |
| leaveFrom="opacity-100 translate-y-0 sm:scale-100" |
| leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" |
| > |
| <DialogPanel className="relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg lg:ml-72"> |
| <div className="bg-white px-4 pb-4 pt-5 sm:p-6 sm:pb-4"> |
| <div className="sm:flex sm:items-start"> |
| <div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10"> |
| {getIconComponent()} |
| </div> |
| <div className="mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left"> |
| <Dialog.Title |
| as="h3" |
| className="text-base font-semibold leading-6 text-gray-900" |
| > |
| {title} |
| </Dialog.Title> |
| <div className="mt-2"> |
| <p className="text-sm text-gray-500">{message}</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6"> |
| <button |
| type="button" |
| className="inline-flex w-full justify-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 sm:ml-3 sm:w-auto" |
| onClick={onSuccess} |
| > |
| {okText} |
| </button> |
| <button |
| type="button" |
| className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:mt-0 sm:w-auto" |
| onClick={onCancel} |
| ref={cancelButtonRef} |
| > |
| Cancel |
| </button> |
| </div> |
| </DialogPanel> |
| </HeadlessTransitionChild> |
| </div> |
| </div> |
| </Dialog> |
| </HeadlessTransition> |
| ); |
| } |
|
|