2024-07-06 14:44:04 -04:00
import PropTypes from "prop-types" ;
2024-07-06 14:33:36 -04:00
import { useTheme } from "@emotion/react" ;
2024-08-31 17:37:55 -04:00
import { Box , Button , IconButton , Stack , Typography } from "@mui/material" ;
2024-07-06 14:33:36 -04:00
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined" ;
import ErrorOutlineOutlinedIcon from "@mui/icons-material/ErrorOutlineOutlined" ;
import WarningAmberOutlinedIcon from "@mui/icons-material/WarningAmberOutlined" ;
2024-07-11 16:45:29 -04:00
import CloseIcon from "@mui/icons-material/Close" ;
2024-07-06 14:33:36 -04:00
import "./index.css" ;
2024-07-06 14:44:04 -04:00
/**
* Icons mapping for different alert variants.
* @type {Object<string, JSX.Element>}
*/
2024-07-06 14:33:36 -04:00
const icons = {
2024-10-17 12:05:06 +08:00
info : < InfoOutlinedIcon />,
error : < ErrorOutlineOutlinedIcon />,
warning : < WarningAmberOutlinedIcon />,
2024-07-06 14:33:36 -04:00
};
2024-07-06 14:44:04 -04:00
/**
* @param {Object} props
* @param {'info' | 'error' | 'warning'} props.variant - The type of alert.
* @param {string} [props.title] - The title of the alert.
* @param {string} [props.body] - The body text of the alert.
2024-07-11 20:30:11 -04:00
* @param {boolean} [props.isToast] - Indicates if the alert is used as a toast notification.
* @param {boolean} [props.hasIcon] - Whether to display an icon in the alert.
* @param {function} props.onClick - Toast dismiss function.
2024-07-06 14:44:04 -04:00
* @returns {JSX.Element}
*/
2024-07-11 16:54:25 -04:00
const Alert = ({ variant , title , body , isToast , hasIcon = true , onClick }) => {
2024-10-17 12:05:06 +08:00
const theme = useTheme ();
2024-11-10 17:00:13 -05:00
/* TODO check if this still works. text bg and border not necessarilly exist. Text becomes contrastText. border becomes contrastText. bg becomes dark */
2024-10-17 12:05:06 +08:00
const { text , bg , border } = theme . palette [ variant ];
const icon = icons [ variant ];
2024-07-06 14:33:36 -04:00
2024-10-17 12:05:06 +08:00
return (
< Stack
direction = "row"
justifyContent = "flex-start"
alignItems = { hasIcon ? "" : "center" }
className = "alert row-stack"
gap = { theme . spacing ( 8 )}
sx = {{
padding : hasIcon ? theme . spacing ( 8 ) : ` ${ theme . spacing ( 4 ) } ${ theme . spacing ( 8 ) } ` ,
backgroundColor : bg ,
border : `solid 1px ${ border } ` ,
borderRadius : theme . shape . borderRadius ,
}}
>
{ hasIcon && < Box sx = {{ color : text }}>{ icon }</ Box >}
< Stack
direction = "column"
gap = "2px"
sx = {{ flex : 1 }}
>
{ title && (
< Typography sx = {{ fontWeight : "700" , color : ` ${ text } ` }}>{ title }</ Typography >
)}
{ body && (
< Typography sx = {{ fontWeight : "400" , color : ` ${ text } ` }}>{ body }</ Typography >
)}
{ hasIcon && isToast && (
< Button
variant = "text"
color = "info"
onClick = { onClick }
sx = {{
fontWeight : "600" ,
width : "fit-content" ,
mt : theme . spacing ( 4 ),
padding : 0 ,
minWidth : 0 ,
}}
>
Dismiss
</ Button >
)}
</ Stack >
{ isToast && (
< IconButton
onClick = { onClick }
sx = {{
alignSelf : "flex-start" ,
ml : "auto" ,
mr : "-5px" ,
mt : hasIcon ? "-5px" : 0 ,
padding : "5px" ,
"&:focus" : {
outline : "none" ,
},
}}
>
< CloseIcon
sx = {{
fontSize : "20px" ,
}}
/>
</ IconButton >
)}
</ Stack >
);
2024-07-06 14:33:36 -04:00
};
2024-07-06 14:44:04 -04:00
Alert . propTypes = {
2024-10-17 12:05:06 +08:00
variant : PropTypes . oneOf ([ "info" , "error" , "warning" ]). isRequired ,
title : PropTypes . string ,
body : PropTypes . string ,
isToast : PropTypes . bool ,
hasIcon : PropTypes . bool ,
onClick : function ( props , propName , componentName ) {
if ( props . isToast && ! props [ propName ]) {
return new Error (
`Prop ' ${ propName } ' is required when 'isToast' is true in ' ${ componentName } '.`
);
}
return null ;
},
2024-07-06 14:44:04 -04:00
};
2024-07-06 14:33:36 -04:00
export default Alert ;