import { DialogTrigger } from '@radix-ui/react-dialog'; import clsx from 'clsx'; import type { PropsWithChildren } from 'react'; import { createContext, useCallback, useContext, useState } from 'react'; import type { ButtonProps } from '../button'; import { Button } from '../button'; import type { ModalProps } from './modal'; import { Modal } from './modal'; import * as styles from './styles.css'; export interface ConfirmModalProps extends ModalProps { confirmButtonOptions?: ButtonProps; onConfirm?: (() => void) | (() => Promise); onCancel?: () => void; cancelText?: string; cancelButtonOptions?: ButtonProps; reverseFooter?: boolean; } export const ConfirmModal = ({ children, confirmButtonOptions, // FIXME: we need i18n cancelText = 'Cancel', cancelButtonOptions, reverseFooter, onConfirm, onCancel, width = 480, ...props }: ConfirmModalProps) => { const onConfirmClick = useCallback(() => { Promise.resolve(onConfirm?.()).catch(err => { console.error(err); }); }, [onConfirm]); return ( {children ? (
{children}
) : null}
); }; interface OpenConfirmModalOptions { autoClose?: boolean; onSuccess?: () => void; } interface ConfirmModalContextProps { modalProps: ConfirmModalProps; openConfirmModal: ( props?: ConfirmModalProps, options?: OpenConfirmModalOptions ) => void; closeConfirmModal: () => void; } const ConfirmModalContext = createContext({ modalProps: { open: false }, openConfirmModal: () => {}, closeConfirmModal: () => {}, }); export const ConfirmModalProvider = ({ children }: PropsWithChildren) => { const [modalProps, setModalProps] = useState({ open: false, }); const setLoading = useCallback((value: boolean) => { setModalProps(prev => ({ ...prev, confirmButtonOptions: { ...prev.confirmButtonOptions, loading: value, }, })); }, []); const closeConfirmModal = useCallback(() => { setModalProps({ open: false }); }, []); const openConfirmModal = useCallback( (props?: ConfirmModalProps, options?: OpenConfirmModalOptions) => { const { autoClose = true, onSuccess } = options ?? {}; if (!props) { setModalProps({ open: true }); return; } const { onConfirm: _onConfirm, ...otherProps } = props; const onConfirm = () => { setLoading(true); return Promise.resolve(_onConfirm?.()) .then(() => onSuccess?.()) .catch(console.error) .finally(() => setLoading(false)) .finally(() => autoClose && closeConfirmModal()); }; setModalProps({ ...otherProps, onConfirm, open: true }); }, [closeConfirmModal, setLoading] ); const onOpenChange = useCallback( (open: boolean) => { modalProps.onOpenChange?.(open); setModalProps(props => ({ ...props, open })); }, [modalProps] ); return ( {children} {/* TODO: multi-instance support(unnecessary for now) */} ); }; export const useConfirmModal = () => { const context = useContext(ConfirmModalContext); if (!context) { throw new Error( 'useConfirmModal must be used within a ConfirmModalProvider' ); } return { openConfirmModal: context.openConfirmModal, closeConfirmModal: context.closeConfirmModal, }; };