import { Box, Dialog as MUIDialog, SxProps, Theme } from '@mui/material'; import { ButtonHTMLAttributes, ElementType, FormEventHandler, forwardRef, MouseEventHandler, useImperativeHandle, useMemo, useState, } from 'react'; import { BLUE, RED, TEXT } from '../lib/consts/DEFAULT_THEME'; import ContainedButton from './ContainedButton'; import FlexBox from './FlexBox'; import { Panel, PanelHeader } from './Panels'; import Spinner from './Spinner'; import { BodyText, HeaderText } from './Text'; const MAP_TO_COLOUR: Record< Exclude, string > = { blue: BLUE, red: RED, }; const ConfirmDialog = forwardRef< ConfirmDialogForwardedRefContent, ConfirmDialogProps >( ( { actionCancelText = 'Cancel', actionProceedText, contentContainerProps = {}, closeOnProceed: isCloseOnProceed = false, content, dialogProps: { open: baseOpen = false, PaperProps: paperProps = {}, ...restDialogProps } = {}, disableProceed: isDisableProceed, formContent: isFormContent, loading: isLoading = false, loadingAction: isLoadingAction = false, onActionAppend, onCancelAppend, onProceedAppend, onSubmitAppend, openInitially = false, preActionArea, proceedButtonProps = {}, proceedColour: proceedColourKey = 'blue', scrollContent: isScrollContent = false, scrollBoxProps: { sx: scrollBoxSx, ...restScrollBoxProps } = {}, titleText, }, ref, ) => { const { sx: paperSx, ...restPaperProps } = paperProps; const { disabled: proceedButtonDisabled = isDisableProceed, sx: proceedButtonSx, ...restProceedButtonProps } = proceedButtonProps; const [isOpen, setIsOpen] = useState(openInitially); // TODO: using base open is depreciated; use internal state once all // dependent components finish the migrate. const open = useMemo( () => (ref ? isOpen : baseOpen), [baseOpen, isOpen, ref], ); const proceedColour = useMemo( () => MAP_TO_COLOUR[proceedColourKey], [proceedColourKey], ); const { contentContainerComponent, contentContainerSubmitEventHandler, proceedButtonClickEventHandler, proceedButtonType, } = useMemo(() => { let ccComponent: ElementType | undefined; let ccSubmitEventHandler: FormEventHandler | undefined; let pbClickEventHandler: | MouseEventHandler | undefined = (...args) => { if (isCloseOnProceed) { setIsOpen(false); } onActionAppend?.call(null, ...args); onProceedAppend?.call(null, ...args); }; let pbType: ButtonHTMLAttributes['type'] | undefined; if (isFormContent) { ccComponent = 'form'; ccSubmitEventHandler = (event, ...restArgs) => { event.preventDefault(); if (isCloseOnProceed) { setIsOpen(false); } onSubmitAppend?.call(null, event, ...restArgs); }; pbClickEventHandler = undefined; pbType = 'submit'; } return { contentContainerComponent: ccComponent, contentContainerSubmitEventHandler: ccSubmitEventHandler, proceedButtonClickEventHandler: pbClickEventHandler, proceedButtonType: pbType, }; }, [ isCloseOnProceed, isFormContent, onActionAppend, onProceedAppend, onSubmitAppend, ]); const cancelButtonElement = useMemo( () => ( { setIsOpen(false); onActionAppend?.call(null, ...args); onCancelAppend?.call(null, ...args); }} > {actionCancelText} ), [actionCancelText, onActionAppend, onCancelAppend], ); const proceedButtonElement = useMemo( () => ( {actionProceedText} ), [ actionProceedText, proceedButtonClickEventHandler, proceedButtonDisabled, proceedButtonSx, proceedButtonType, proceedColour, restProceedButtonProps, ], ); const actionAreaElement = useMemo( () => isLoadingAction ? ( ) : ( {cancelButtonElement} {proceedButtonElement} ), [cancelButtonElement, isLoadingAction, proceedButtonElement], ); const contentElement = useMemo( () => typeof content === 'string' ? : content, [content], ); const headerElement = useMemo( () => typeof titleText === 'string' ? ( {titleText} ) : ( titleText ), [titleText], ); const combinedScrollBoxSx = useMemo(() => { let result: SxProps | undefined; if (isScrollContent) { let overflowX: 'hidden' | undefined; let paddingTop: string | undefined; if (isFormContent) { overflowX = 'hidden'; paddingTop = '.6em'; } result = { maxHeight: '60vh', overflowX, overflowY: 'scroll', paddingRight: '.4em', paddingTop, ...scrollBoxSx, }; } return result; }, [isFormContent, isScrollContent, scrollBoxSx]); const contentAreaElement = useMemo( () => isLoading ? ( ) : ( <> {contentElement} {preActionArea} {actionAreaElement} ), [ actionAreaElement, combinedScrollBoxSx, contentElement, isLoading, preActionArea, restScrollBoxProps, ], ); useImperativeHandle( ref, () => ({ setOpen: (value) => setIsOpen(value), }), [], ); return ( {headerElement} {contentAreaElement} ); }, ); ConfirmDialog.displayName = 'ConfirmDialog'; export default ConfirmDialog;