Generateurv2/frontend/components/Notifications.jsx
Kilton937342 035af2a3b7 modifs
2022-06-11 23:39:03 +02:00

165 lines
4.6 KiB
JavaScript

import { useRouter } from "next/router";
import { memo, useCallback, useEffect, useRef, useState } from "react";
import {
notificationService,
NotificationType,
} from "../services/notification.service.js";
import styles from "../styles/exos/Notifications.module.scss";
import { MdDone } from "react-icons/md";
function NotificationComp({ notification, classes, removeAlert, mount, fadeIn }) {
const notifIcon = {
[NotificationType.Success]: <MdDone />,
[NotificationType.Warning]: <MdDone />,
[NotificationType.Info]: <MdDone />,
[NotificationType.Error]: <MdDone />,
};
return (
<div
className={classes + ' ' + (mount && styles['fadeOut'])}
onClick={() => {
removeAlert(notification);
}}
>
<div className={styles["notif-title"]}>
{notifIcon[notification.type]} {notification.title}
</div>
<div className={styles["notif-msg"]}>
{notification.message}
</div>
</div>
);
}
const Notification = memo(NotificationComp)
export default function Notifications({ id = "default-notif", fade = true }) {
const mounted = useRef(false);
const router = useRouter();
const [notification, setNotif] = useState([]);
useEffect(() => {
mounted.current = true;
// subscribe to new alert notifications
const subscription = notificationService.onAlert(id).subscribe((notif) => {
// clear alerts when an empty alert is received
if (!notif.message) {
setNotif((alerts) => {
// filter out alerts without 'keepAfterRouteChange' flag
const filteredAlerts = alerts.filter((x) => x.keepAfterRouteChange);
// remove 'keepAfterRouteChange' flag on the rest
return omit(filteredAlerts, "keepAfterRouteChange");
});
} else {
// add alert to array with unique id
notif.itemId = Math.random();
addNotif(notif)
// auto close alert if required
if (notif.autoClose) {
setTimeout(() => removeAlert(notif), 3000);
}
}
});
// clear alerts on location change
const clearAlerts = () => notificationService.clear(id);
router.events.on("routeChangeStart", clearAlerts);
// clean up function that runs when the component unmounts
return () => {
mounted.current = false;
// unsubscribe to avoid memory leaks
subscription.unsubscribe();
router.events.off("routeChangeStart", clearAlerts);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
function omit(arr, key) {
return arr.map((obj) => {
const { [key]: omitted, ...rest } = obj;
return rest;
});
}
function addNotif(notif) {
if (notification.length > 5) {
removeAlert(notification[0]);
}
setNotif((alerts) => [...alerts, notif]);
}
function removeAlertFunc(notif) {
if (!mounted.current) return;
if (fade) {
// fade out alert
setNotif((alerts) =>
alerts.map((x) =>
x.itemId === notif.itemId ? { ...x, fade: true } : x
)
);
// remove alert after faded out
setTimeout(() => {
setNotif((alerts) => alerts.filter((x) => x.itemId !== notif.itemId));
}, 500);
} else {
// remove alert
setNotif((alerts) => alerts.filter((x) => x.itemId !== notif.itemId));
}
}
const removeAlert = useCallback(removeAlertFunc, [fade])
function cssClasses(notif) {
if (!notif) return;
const classes = [styles["notif"], styles["notif-dismissable"]];
const notifTypeClass = {
[NotificationType.Success]: styles["notif-success"],
[NotificationType.Error]: styles["notif-danger"],
[NotificationType.Info]: styles["notif-info"],
[NotificationType.Warning]: styles["notif-warning"],
};
classes.push(notifTypeClass[notif.type]);
if (notif.fade) {
classes.push("fade");
}
return classes.join(" ");
}
useEffect(() => {
if (!mounted.current) return;
if (notification.length > 5) {
removeAlert(notification[0]);
}
}, [notification, removeAlert]);
const notifIcon = {
[NotificationType.Success]: <MdDone />,
[NotificationType.Warning]: <MdDone />,
[NotificationType.Info]: <MdDone />,
[NotificationType.Error]: <MdDone />,
};
if (!notification.length) return null;
return (
<div className={styles["notifications-container"]}>
{notification.map((notification, index) => {
return (
<Notification removeAlert={removeAlert} notification={notification} classes={cssClasses(notification)} key={index} mount={notification.fade}/>
);
})}
</div>
);
}