import Snackbar from '@mui/material/Snackbar'; import { Alert } from '../alert'; import { Modal } from '../modal'; import type { ModalProps } from '../modal'; import { useEffect, useState } from 'react'; import type { Dispatch, SetStateAction } from 'react'; import type { NotificationProps, ShowNotifAction, ShowNotifOptions, HandleNotificationClose } from './notification.types'; import uniqueId from 'lodash/uniqueId'; const defaultNotifOptions: ShowNotifOptions = { method: 'wait' }; type Modals = ModalProps[]; let notificationHandler: Dispatch> | null = null; let modalHandler: Dispatch> | null = null; function subscribe( notifFn: Dispatch>, modalFn: Dispatch> ) { notificationHandler = notifFn; modalHandler = modalFn; return () => { notificationHandler = null; modalHandler = null; }; } export function hideNotif() { if (notificationHandler) { notificationHandler(prev => prev.slice(1)); } } export const showNotif: ShowNotifAction = (message, opt = defaultNotifOptions) => { if (notificationHandler) { const { method, ...rest } = opt; const key = uniqueId('notif'); if (method === 'replace') { notificationHandler(prev => [{ message, key, ...rest }, ...prev.slice(1)]); } else { notificationHandler(prev => [...prev, { message, key, ...rest }]); } } }; export const closeModal = (id?: string) => { if (modalHandler) { modalHandler(modals => (id ? modals.filter(modal => modal.id !== id) : [])); } }; export const openModal = ( modal: Omit, onModalOpened?: () => void ): string | void => { if (modalHandler) { const id = Date.now().toString(); modalHandler(modals => modals.concat({ ...modal, id, open: true, onClose: () => { closeModal(id); } }) ); onModalOpened?.(); return id; } }; const Notification = () => { const [notifications, setNotifications] = useState([]); const [modals, setModals] = useState([]); useEffect(() => { subscribe(setNotifications, setModals); }, []); if (modals.length) return ( <> {modals.map(modal => ( ))} ); const currNotif = notifications[0]; if (!currNotif) return null; const { message, ms = 6000, alertProps, onAfterClose, onBeforeClose, withCloseButton = true, snackbarProps, disableDismissMethod, key } = currNotif; const handleClose: HandleNotificationClose = (_event, reason) => { if (!disableDismissMethod?.[reason] || (withCloseButton && reason === 'userclick')) { const notif = currNotif; if (onBeforeClose) onBeforeClose(currNotif); hideNotif(); if (onAfterClose) onAfterClose(notif); } }; return currNotif ? ( handleClose(e, 'userclick') : undefined} > {message} ) : null; }; export default Notification;