Add alerts ssytems to the frontend

This commit is contained in:
Urtzi Alfaro
2025-09-21 17:35:36 +02:00
parent 57fd2f22f0
commit f08667150d
17 changed files with 2086 additions and 786 deletions

View File

@@ -0,0 +1,172 @@
import { useState, useEffect } from 'react';
import { useSSE } from '../contexts/SSEContext';
export interface NotificationData {
id: string;
item_type: 'alert' | 'recommendation';
severity: 'urgent' | 'high' | 'medium' | 'low';
title: string;
message: string;
timestamp: string;
read: boolean;
}
const STORAGE_KEY = 'bakery-notifications';
const loadNotificationsFromStorage = (): NotificationData[] => {
try {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored) {
const parsed = JSON.parse(stored);
return Array.isArray(parsed) ? parsed : [];
}
} catch (error) {
console.warn('Failed to load notifications from localStorage:', error);
}
return [];
};
const saveNotificationsToStorage = (notifications: NotificationData[]) => {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(notifications));
} catch (error) {
console.warn('Failed to save notifications to localStorage:', error);
}
};
export const useNotifications = () => {
const [notifications, setNotifications] = useState<NotificationData[]>(() => loadNotificationsFromStorage());
const [unreadCount, setUnreadCount] = useState(() => {
const stored = loadNotificationsFromStorage();
return stored.filter(n => !n.read).length;
});
const { addEventListener, isConnected } = useSSE();
// Save to localStorage whenever notifications change
useEffect(() => {
saveNotificationsToStorage(notifications);
}, [notifications]);
useEffect(() => {
// Listen for initial_items event (existing notifications)
const removeInitialListener = addEventListener('initial_items', (data: any[]) => {
if (Array.isArray(data) && data.length > 0) {
const initialNotifications: NotificationData[] = data.map(item => ({
id: item.id,
item_type: item.item_type,
severity: item.severity,
title: item.title,
message: item.message,
timestamp: item.timestamp || new Date().toISOString(),
read: false, // Assume all initial items are unread
}));
setNotifications(prev => {
// Merge initial items with existing notifications, avoiding duplicates
const existingIds = new Set(prev.map(n => n.id));
const newNotifications = initialNotifications.filter(n => !existingIds.has(n.id));
const combined = [...newNotifications, ...prev].slice(0, 50);
return combined;
});
setUnreadCount(prev => {
const newUnreadCount = initialNotifications.filter(n => !n.read).length;
return prev + newUnreadCount;
});
}
});
// Listen for alert events
const removeAlertListener = addEventListener('alert', (data: any) => {
const notification: NotificationData = {
id: data.id,
item_type: 'alert',
severity: data.severity,
title: data.title,
message: data.message,
timestamp: data.timestamp || new Date().toISOString(),
read: false,
};
setNotifications(prev => {
// Check if notification already exists
const exists = prev.some(n => n.id === notification.id);
if (exists) return prev;
return [notification, ...prev].slice(0, 50); // Keep last 50 notifications
});
setUnreadCount(prev => prev + 1);
});
// Listen for recommendation events
const removeRecommendationListener = addEventListener('recommendation', (data: any) => {
const notification: NotificationData = {
id: data.id,
item_type: 'recommendation',
severity: data.severity,
title: data.title,
message: data.message,
timestamp: data.timestamp || new Date().toISOString(),
read: false,
};
setNotifications(prev => {
// Check if notification already exists
const exists = prev.some(n => n.id === notification.id);
if (exists) return prev;
return [notification, ...prev].slice(0, 50); // Keep last 50 notifications
});
setUnreadCount(prev => prev + 1);
});
return () => {
removeInitialListener();
removeAlertListener();
removeRecommendationListener();
};
}, [addEventListener]);
const markAsRead = (notificationId: string) => {
setNotifications(prev =>
prev.map(notification =>
notification.id === notificationId
? { ...notification, read: true }
: notification
)
);
setUnreadCount(prev => Math.max(0, prev - 1));
};
const markAllAsRead = () => {
setNotifications(prev =>
prev.map(notification => ({ ...notification, read: true }))
);
setUnreadCount(0);
};
const removeNotification = (notificationId: string) => {
const notification = notifications.find(n => n.id === notificationId);
setNotifications(prev => prev.filter(n => n.id !== notificationId));
if (notification && !notification.read) {
setUnreadCount(prev => Math.max(0, prev - 1));
}
};
const clearAllNotifications = () => {
setNotifications([]);
setUnreadCount(0);
};
return {
notifications,
unreadCount,
isConnected,
markAsRead,
markAllAsRead,
removeNotification,
clearAll: clearAllNotifications,
};
};