[Update] Change the notification UI.
(Change the base notification library from MUI to React-Toastify.)
This commit is contained in:
@@ -1,46 +1,114 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { ToastContainer, toast, Bounce } from "react-toastify";
|
||||
import clsx from "clsx";
|
||||
import Snackbar from "@mui/material/Snackbar";
|
||||
import Slide from "@mui/material/Slide";
|
||||
|
||||
import "./ReactToastifyOverrideClass.scss";
|
||||
import styles from "./SnackbarController.module.scss";
|
||||
|
||||
import XMarkSvg from "@images/cancel.svg?react";
|
||||
import WarningSvg from "@images/warning.svg?react";
|
||||
import MegaphoneSvg from "@images/megaphone.svg?react";
|
||||
import CheckMarkSvg from "@images/check_mark.svg?react";
|
||||
import ErrorSvg from "@images/error.svg?react";
|
||||
|
||||
import { useNotificationStatus } from "@logics_common";
|
||||
|
||||
export const SnackbarController = () => {
|
||||
const { currentNotificationStatus, closeNotification } = useNotificationStatus();
|
||||
|
||||
const handleClose = (event, reason) => {
|
||||
closeNotification(event, reason);
|
||||
};
|
||||
|
||||
const snackbar_classname = clsx(styles.snackbar_content, {
|
||||
[styles.is_success]: currentNotificationStatus.data.status === "success",
|
||||
[styles.is_warning]: currentNotificationStatus.data.status === "warning",
|
||||
[styles.is_error]: currentNotificationStatus.data.status === "error",
|
||||
});
|
||||
const [containerKey, setContainerKey] = useState(0);
|
||||
|
||||
const settings = currentNotificationStatus.data;
|
||||
|
||||
let hide_duration = 5000;
|
||||
if (settings.options?.hide_duration === null) hide_duration = null;
|
||||
if (Number(settings.options?.hide_duration)) hide_duration = settings.options.hide_duration;
|
||||
const snackbar_classname = clsx(
|
||||
styles.snackbar_content,
|
||||
{
|
||||
[styles.is_success]: settings.status === "success",
|
||||
[styles.is_warning]: settings.status === "warning",
|
||||
[styles.is_error]: settings.status === "error",
|
||||
}
|
||||
);
|
||||
|
||||
let hideDuration = 5000;
|
||||
if (settings.options?.hide_duration === null) {
|
||||
hideDuration = false;
|
||||
} else if (Number(settings.options?.hide_duration)) {
|
||||
hideDuration = Number(settings.options?.hide_duration);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!settings.is_open) return;
|
||||
|
||||
const message_text = settings.message;
|
||||
|
||||
if (toast.isActive(message_text)) {
|
||||
setContainerKey(prevKey => prevKey + 1);
|
||||
|
||||
setTimeout(() => {
|
||||
toast(message_text, {
|
||||
toastId: message_text,
|
||||
type: settings.status,
|
||||
autoClose: hideDuration,
|
||||
transition: Bounce,
|
||||
toastClassName: snackbar_classname,
|
||||
progressClassName: styles.toast_progress,
|
||||
closeButton: <CloseButtonContainer />,
|
||||
onClose: () => {
|
||||
closeNotification();
|
||||
},
|
||||
});
|
||||
}, 50);
|
||||
} else {
|
||||
toast(message_text, {
|
||||
toastId: message_text,
|
||||
type: settings.status,
|
||||
autoClose: hideDuration,
|
||||
transition: Bounce,
|
||||
toastClassName: snackbar_classname,
|
||||
progressClassName: styles.toast_progress,
|
||||
closeButton: <CloseButtonContainer />,
|
||||
onClose: () => {
|
||||
closeNotification();
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [settings, hideDuration, closeNotification, snackbar_classname]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Snackbar
|
||||
open={settings.is_open}
|
||||
onClose={handleClose}
|
||||
TransitionComponent={SlideTransition}
|
||||
key={settings.key}
|
||||
autoHideDuration={hide_duration}
|
||||
>
|
||||
<div className={snackbar_classname}>
|
||||
<p className={styles.snackbar_message}>{settings.message}</p>
|
||||
</div>
|
||||
</Snackbar>
|
||||
</div>
|
||||
<ToastContainer
|
||||
key={containerKey}
|
||||
position="bottom-left"
|
||||
transition={Bounce}
|
||||
hideProgressBar={false}
|
||||
newestOnTop={false}
|
||||
closeOnClick={false}
|
||||
pauseOnFocusLoss={false}
|
||||
draggable={false}
|
||||
pauseOnHover={true}
|
||||
theme="dark"
|
||||
icon={({ type }) => {
|
||||
switch (type) {
|
||||
case "info":
|
||||
return <MegaphoneSvg className={styles.megaphone_svg} />;
|
||||
case "error":
|
||||
return <ErrorSvg className={styles.error_svg} />;
|
||||
case "success":
|
||||
return <CheckMarkSvg className={styles.check_mark_svg} />;
|
||||
case "warning":
|
||||
return <WarningSvg className={styles.warning_svg} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const SlideTransition = (props) => {
|
||||
return <Slide {...props} direction="up" />;
|
||||
};
|
||||
const CloseButtonContainer = ({ closeToast }) => {
|
||||
return (
|
||||
<button className={styles.close_button_wrapper} onClick={closeToast}>
|
||||
<div className={styles.close_button}>
|
||||
<XMarkSvg className={styles.x_mark_svg} />
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user