-
-
Notifications
You must be signed in to change notification settings - Fork 298
Open
Description
It seems like our beloved Notistack is not maintained for a long time, bug correction-wise it's a problematic but worse yet when I upgraded to react v19 and this package still on the v18. I worked with AI to generate a perfect notification system that works for me, so sharing that with anyone who needs one. Modify to the way you like.
layout.tsx
const notificationOptions = {
maxNotifications: 5, // Show up to 5 notifications
autoHideDuration: 5000, // Auto-hide after 5 seconds
preventDuplicate: true, // Allow duplicate notifications
};
return(
<NotificationProvider settings={notificationOptions}>
<App />
</NotificationProvider>
)
notification-provider.tsx
import React, { createContext, useContext, useState, ReactNode } from "react";
import Notification from "./notification";
// Default configuration for the notification system
const defaultNotificationOptions = {
maxNotifications: 3, // Maximum number of notifications to display at once
autoHideDuration: 5000, // Auto-hide duration in milliseconds
preventDuplicate: true, // Prevent duplicate notifications
};
interface NotificationProviderProps {
children: ReactNode;
settings?: Partial<typeof defaultNotificationOptions>;
}
interface Notification {
id: string;
message: string;
type: "success" | "error" | "info" | "warning";
timer?: NodeJS.Timeout; // Timer reference for auto-hide
}
interface NotificationContextType {
addNotification: (
message: string,
type: "success" | "error" | "info" | "warning"
) => void;
removeNotification: (id: string) => void;
clearAllNotifications: () => void; // Clear all notifications
}
const NotificationContext = createContext<NotificationContextType | null>(null);
export const useNotifications = () => {
const context = useContext(NotificationContext);
if (!context) {
throw new Error(
"useNotifications must be used within a NotificationProvider"
);
}
return context;
};
export const NotificationProvider: React.FC<NotificationProviderProps> = ({
children,
settings = {},
}) => {
const notificationSettings = { ...defaultNotificationOptions, ...settings };
const [notifications, setNotifications] = useState<Notification[]>([]);
const addNotification = (
message: string,
type: "success" | "error" | "info" | "warning"
) => {
setNotifications((prev) => {
// Prevent duplicates if enabled
if (notificationSettings.preventDuplicate) {
const isDuplicate = prev.some(
(n) => n.message === message && n.type === type
);
if (isDuplicate) return prev;
}
const id = Date.now().toString();
// Create a new notification
const newNotification: Notification = { id, message, type };
// Add the notification and limit to maxNotifications
const updated = [...prev, newNotification];
if (updated.length > notificationSettings.maxNotifications) {
const oldest = updated.shift(); // Remove the oldest notification
if (oldest?.timer) clearTimeout(oldest.timer); // Clear its timer
}
// Set a timer to auto-remove the notification after the specified duration
newNotification.timer = setTimeout(() => {
removeNotification(id);
}, notificationSettings.autoHideDuration);
return updated;
});
};
const removeNotification = (id: string) => {
setNotifications((prev) => {
const notificationToRemove = prev.find((n) => n.id === id);
if (notificationToRemove?.timer) clearTimeout(notificationToRemove.timer); // Clear its timer
return prev.filter((n) => n.id !== id);
});
};
const clearAllNotifications = () => {
setNotifications((prev) => {
// Clear timers for all notifications
prev.forEach((n) => {
if (n.timer) clearTimeout(n.timer);
});
return []; // Reset the notifications array
});
};
return (
<NotificationContext.Provider
value={{ addNotification, removeNotification, clearAllNotifications }}
>
{children}
<div className="fixed bottom-5 right-5 flex flex-col items-end space-y-4 z-50">
{notifications.map((notif) => (
<Notification
key={notif.id}
message={notif.message}
type={notif.type}
onClose={() => removeNotification(notif.id)}
/>
))}
</div>
</NotificationContext.Provider>
);
};
notification.tsx
interface NotificationProps {
message: string;
type?: "success" | "error" | "info" | "warning";
onClose: () => void;
}
const Notification: React.FC<NotificationProps> = ({
message,
type = "info",
onClose,
}) => {
useEffect(() => {
// No additional timer logic needed here; it's managed by the provider
return () => {};
}, []);
const typeStyles = {
success: "bg-green-500 text-white",
error: "bg-red-500 text-white",
info: "bg-blue-500 text-white",
warning: "bg-yellow-500 text-black",
};
const icons = {
success: "✔️", // Replace with a checkmark SVG or icon
error: "❌", // Replace with an error SVG or icon
info: "ℹ️", // Replace with an info SVG or icon
warning: "⚠️", // Replace with a warning SVG or icon
};
return (
<div
className={`w-80 px-4 py-2 rounded shadow-lg flex items-center space-x-4 ${typeStyles[type]} z-50`}
>
<span className="text-xl">{icons[type]}</span>
<span>{message}</span>
<button
className="ml-auto text-white focus:outline-none"
onClick={onClose}
>
✕
</button>
</div>
);
};
export default Notification;
lukaselmer, baptwaels and StartikOfficial
Metadata
Metadata
Assignees
Labels
No labels