coder/site/src/components/Dialogs/ConfirmDialog/ConfirmDialog.tsx

146 lines
3.4 KiB
TypeScript

import type { Interpolation, Theme } from "@emotion/react";
import DialogActions from "@mui/material/DialogActions";
import type { FC, ReactNode } from "react";
import {
Dialog,
DialogActionButtons,
type DialogActionButtonsProps,
} from "../Dialog";
import type { ConfirmDialogType } from "../types";
interface ConfirmDialogTypeConfig {
confirmText: ReactNode;
hideCancel: boolean;
}
const CONFIRM_DIALOG_DEFAULTS: Record<
ConfirmDialogType,
ConfirmDialogTypeConfig
> = {
delete: {
confirmText: "Delete",
hideCancel: false,
},
info: {
confirmText: "OK",
hideCancel: true,
},
success: {
confirmText: "OK",
hideCancel: true,
},
};
export interface ConfirmDialogProps
extends Omit<DialogActionButtonsProps, "color" | "onCancel"> {
readonly description?: ReactNode;
/**
* hideCancel hides the cancel button when set true, and shows the cancel
* button when set to false. When undefined:
* - cancel is not displayed for "info" dialogs
* - cancel is displayed for "delete" dialogs
*/
readonly hideCancel?: boolean;
/**
* onClose is called when canceling (if cancel is showing).
*
* Additionally, if onConfirm is not defined onClose will be used in its place
* when confirming.
*/
readonly onClose: () => void;
readonly open: boolean;
readonly title: string;
}
const styles = {
dialogWrapper: (theme) => ({
"& .MuiPaper-root": {
background: theme.palette.background.paper,
border: `1px solid ${theme.palette.divider}`,
width: "100%",
maxWidth: 440,
},
"& .MuiDialogActions-spacing": {
padding: "0 40px 40px",
},
}),
dialogContent: (theme) => ({
color: theme.palette.text.secondary,
padding: "40px 40px 20px",
}),
dialogTitle: (theme) => ({
margin: 0,
marginBottom: 16,
color: theme.palette.text.primary,
fontWeight: 400,
fontSize: 20,
}),
dialogDescription: (theme) => ({
color: theme.palette.text.secondary,
lineHeight: "160%",
fontSize: 16,
"& strong": {
color: theme.palette.text.primary,
},
"& p:not(.MuiFormHelperText-root)": {
margin: 0,
},
"& > p": {
margin: "8px 0",
},
}),
} satisfies Record<string, Interpolation<Theme>>;
/**
* Quick-use version of the Dialog component with slightly alternative styles,
* great to use for dialogs that don't have any interaction beyond yes / no.
*/
export const ConfirmDialog: FC<ConfirmDialogProps> = ({
cancelText,
confirmLoading,
confirmText,
description,
disabled = false,
hideCancel,
onClose,
onConfirm,
open = false,
title,
type = "info",
}) => {
const defaults = CONFIRM_DIALOG_DEFAULTS[type];
if (typeof hideCancel === "undefined") {
hideCancel = defaults.hideCancel;
}
return (
<Dialog
css={styles.dialogWrapper}
onClose={onClose}
open={open}
data-testid="dialog"
>
<div css={styles.dialogContent}>
<h3 css={styles.dialogTitle}>{title}</h3>
{description && <div css={styles.dialogDescription}>{description}</div>}
</div>
<DialogActions>
<DialogActionButtons
cancelText={cancelText}
confirmLoading={confirmLoading}
confirmText={confirmText || defaults.confirmText}
disabled={disabled}
onCancel={!hideCancel ? onClose : undefined}
onConfirm={onConfirm || onClose}
type={type}
/>
</DialogActions>
</Dialog>
);
};