Skip to content

Instantly share code, notes, and snippets.

@fadi-george
Created July 1, 2020 06:25
Show Gist options
  • Save fadi-george/f92059bd1ec552a86530416942422cb6 to your computer and use it in GitHub Desktop.
Save fadi-george/f92059bd1ec552a86530416942422cb6 to your computer and use it in GitHub Desktop.
Generic Dialog to handle most situation
import React from 'react';
// types
import type { ButtonProps, DialogProps } from '@material-ui/core';
// mui
import {
Box,
Button,
Dialog as MUIDialog,
DialogActions,
DialogContent,
DialogTitle,
IconButton,
Typography,
} from '@material-ui/core';
// icons
import CloseIcon from '@material-ui/icons/Close';
// components
import ErrorButton from 'components/buttons/ErrorButton';
interface Props extends Omit<DialogProps, 'title'> {
actions?: React.ReactNode;
cancelLabel?: string;
children?: React.ReactNode;
confirmLabel?: string;
disableConfirm?: boolean;
form?: string;
header?: React.ReactNode;
isFetching?: boolean;
onCancel?: (data?: any) => void;
onClose?: () => void;
onConfirm?: (event?: any) => void;
showConfirm?: boolean;
size: 'small' | 'medium' | 'large';
subtitle?: React.ReactNode;
title: string | React.ReactNode;
variant?: 'constructive' | 'destructive';
}
const sizeMap: { [key: string]: string } = {
small: 'xs',
medium: 'sm',
large: 'md',
};
const Dialog: React.FC<Props> = ({
cancelLabel = 'Cancel',
confirmLabel = 'Confirm',
children = null,
disableConfirm = false,
form,
header,
subtitle,
isFetching,
onClose = null,
onCancel = onClose || (() => {}),
onConfirm,
showConfirm = true,
size,
title,
variant = 'constructive',
actions = (
<>
<Button
data-testid="actions-default-cancel-button"
disabled={isFetching}
onClick={onCancel}
variant="outlined"
>
{cancelLabel}
</Button>
{showConfirm &&
(() => {
const props: ButtonProps = {
// @ts-ignore
'data-testid': 'dialog-actions-confirm-button',
disabled: isFetching || disableConfirm,
form: form,
onClick: onConfirm,
type: form ? 'submit' : 'button',
variant: 'contained',
};
return variant === 'destructive' ? (
<ErrorButton {...props}>{confirmLabel}</ErrorButton>
) : (
<Button color="primary" {...props}>
{confirmLabel}
</Button>
);
})()}
</>
),
...rest
}) => {
const isSmall = size === 'small';
return (
<MUIDialog
fullWidth
maxWidth={sizeMap[size] as DialogProps['maxWidth']}
transitionDuration={{ enter: 225, exit: 0 }}
{...rest}
>
<DialogTitle>
<Box
alignItems="center"
data-testid="dialog-title-box"
display="flex"
fontSize="h4.fontSize"
fontWeight="h4.fontWeight"
justifyContent={size === 'small' ? 'center' : 'space-between'}
minHeight={!isSmall ? '40px' : ''}
paddingTop={isSmall ? 4 : ''}
style={{ width: '100%' }}
textAlign={isSmall ? 'center' : ''}
>
<>
{title}
{onClose && !isSmall && (
<IconButton
aria-label="Close modal"
data-testid="dialog-close-button"
disabled={isFetching}
onClick={onClose}
>
<CloseIcon />
</IconButton>
)}
</>
</Box>
{subtitle && (
<Box
data-testid="dialog-subtitle-box"
marginTop={isSmall ? 3 : 0}
textAlign={isSmall ? 'center' : ''}
>
<Typography
className="three-line-text-overflow"
data-testid="dialog-subtitle"
variant={isSmall ? 'body1' : 'caption'}
>
{subtitle}
</Typography>
</Box>
)}
</DialogTitle>
{header}
{children && (
<Box
clone
data-testid="dialog-content-box"
overflow={isSmall ? 'unset' : ''}
paddingBottom={isSmall ? 4 : ''}
paddingTop={isSmall ? 1 : ''}
>
<DialogContent
data-testid="dialog-content"
dividers={size !== 'small'}
style={{ height: 'inherit', position: 'relative' }}
>
{children}
</DialogContent>
</Box>
)}
{actions && (
<Box
clone
data-testid="dialog-actions-box"
justifyContent={isSmall ? 'center' : ''}
paddingBottom={isSmall ? 7 : ''}
paddingTop={isSmall ? 1 : ''}
>
<DialogActions>{actions}</DialogActions>
</Box>
)}
</MUIDialog>
);
};
export default Dialog;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment