Merge pull request #2625 from bluewave-labs/feat/toast-refactor

feat: toast refactor
This commit is contained in:
Alexander Holliday
2025-07-18 11:22:32 -07:00
committed by GitHub
3 changed files with 136 additions and 4 deletions
+34
View File
@@ -0,0 +1,34 @@
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { useTheme } from "@emotion/react";
import PropTypes from "prop-types";
const ToastBody = ({ body }) => {
const theme = useTheme();
if (Array.isArray(body)) {
return (
<Stack gap={theme.spacing(2)}>
{body.map((item, idx) => (
<Typography
key={`item-${idx}`}
color={theme.palette.secondary.contrastText}
>
{item}
</Typography>
))}
</Stack>
);
} else if (typeof body === "string") {
return <Typography color={theme.palette.secondary.contrastText}>{body}</Typography>;
}
return null;
};
ToastBody.propTypes = {
body: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
};
export default ToastBody;
+96
View File
@@ -0,0 +1,96 @@
import Stack from "@mui/material/Stack";
import IconButton from "@mui/material/IconButton";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import ToastBody from "./body";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
import ErrorOutlineOutlinedIcon from "@mui/icons-material/ErrorOutlineOutlined";
import WarningAmberOutlinedIcon from "@mui/icons-material/WarningAmberOutlined";
import CloseIcon from "@mui/icons-material/Close";
// Utils
import { useTheme } from "@emotion/react";
import PropTypes from "prop-types";
const icons = {
info: <InfoOutlinedIcon />,
error: <ErrorOutlineOutlinedIcon />,
warning: <WarningAmberOutlinedIcon />,
};
const Toast = ({ variant, title, body, onClick, hasDismiss, hasIcon }) => {
const theme = useTheme();
const icon = icons[variant];
return (
<Stack
gap={theme.spacing(2)}
paddingTop={theme.spacing(4)}
paddingRight={theme.spacing(8)}
paddingBottom={theme.spacing(4)}
paddingLeft={theme.spacing(8)}
backgroundColor={theme.palette.alert.main}
border={`solid 1px ${theme.palette.alert.contrastText}`}
borderRadius={theme.shape.borderRadius}
>
<Stack
direction="row"
gap={theme.spacing(8)}
justifyContent="space-between"
alignItems="center"
>
{hasIcon && icon}
{title && (
<Typography
fontWeight="700"
color={theme.palette.secondary.contrastText}
>
{title}
</Typography>
)}
{title && (
<IconButton onClick={onClick}>
<CloseIcon />
</IconButton>
)}
</Stack>
<Stack
direction="row"
gap={theme.spacing(2)}
alignItems="center"
>
<ToastBody body={body} />
{!title && (
<IconButton onClick={onClick}>
<CloseIcon />
</IconButton>
)}
</Stack>
{hasDismiss && (
<Button
variant="text"
color="info"
onClick={onClick}
sx={{
fontWeight: "600",
width: "fit-content",
}}
>
Dismiss
</Button>
)}
</Stack>
);
};
export default Toast;
Toast.propTypes = {
variant: PropTypes.string.isRequired,
title: PropTypes.string,
body: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
hasDismiss: PropTypes.bool,
hasIcon: PropTypes.bool,
onClick: PropTypes.func,
};
+6 -4
View File
@@ -1,7 +1,6 @@
import PropTypes from "prop-types";
import { toast, Slide } from "react-toastify";
import Alert from "../Components/Alert";
import Toast from "../Components/Toast";
/**
* @param {object} props
* @param {'info' | 'error' | 'warning'} - The variant of the alert (e.g., "info", "error").
@@ -15,6 +14,7 @@ export const createToast = ({
variant = "info",
title,
body,
hasDismiss = false,
hasIcon = false,
config = {},
}) => {
@@ -29,13 +29,14 @@ export const createToast = ({
toast(
({ closeToast }) => (
<Alert
<Toast
variant={variant}
title={title}
body={body}
isToast={true}
hasIcon={hasIcon}
onClick={closeToast}
hasDismiss={hasDismiss}
hasIcon={hasIcon}
/>
),
toastConfig
@@ -47,5 +48,6 @@ createToast.propTypes = {
title: PropTypes.string,
body: PropTypes.string.isRequired,
hasIcon: PropTypes.bool,
hasDismiss: PropTypes.bool,
config: PropTypes.object,
};