import React, { useState, useEffect, useRef, useCallback } from 'react';
import {
FaTimes,
FaCheckCircle,
FaExclamationCircle,
FaInfoCircle,
FaExclamationTriangle
} from 'react-icons/fa';
import './Notification.css';
const Notification = ({
notifications = [],
position = 'top-right',
animation = 'slide',
stackDirection = 'down',
maxNotifications = 5,
spacing = 10,
offset = { x: 20, y: 20 },
onDismiss,
onAction,
autoStackCollapse = false,
theme = 'light'
}) => {
const [internalNotifications, setInternalNotifications] = useState([]);
const [collapsed, setCollapsed] = useState(false);
const timersRef = useRef({});
const handleDismiss = useCallback((id) => {
if (timersRef.current[id]) {
clearTimeout(timersRef.current[id]);
delete timersRef.current[id];
}
onDismiss?.(id);
}, [onDismiss]);
useEffect(() => {
// Update internal notifications
const processedNotifications = notifications.slice(
stackDirection === 'up' ? -maxNotifications : 0,
stackDirection === 'up' ? undefined : maxNotifications
);
setInternalNotifications(processedNotifications);
// Keep track of current timer IDs for this effect
const currentTimerIds = [];
// Set up auto-dismiss timers
processedNotifications.forEach(notification => {
if (notification.autoDismiss && notification.duration && !timersRef.current[notification.id]) {
const timerId = setTimeout(() => {
handleDismiss(notification.id);
}, notification.duration);
timersRef.current[notification.id] = timerId;
currentTimerIds.push(notification.id);
}
});
// Cleanup function
return () => {
// Use the captured timer IDs and current ref
const timers = timersRef.current;
// Clear timers for notifications that were removed
Object.keys(timers).forEach(id => {
if (!processedNotifications.find(n => n.id === id)) {
clearTimeout(timers[id]);
delete timers[id];
}
});
};
}, [notifications, maxNotifications, stackDirection, handleDismiss]);
const handleAction = (notificationId, actionId, actionData) => {
onAction?.(notificationId, actionId, actionData);
};
const getIcon = (type, customIcon) => {
if (customIcon) return customIcon;
switch (type) {
case 'success':
return