resolve issues with new features
This commit is contained in:
@@ -21,9 +21,10 @@ import {
|
||||
} from '@mui/icons-material';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { notificationsApi } from '../../services/notifications';
|
||||
import { useNotification } from '../../contexts/NotificationContext';
|
||||
import type { Notification, NotificationSchwere } from '../../types/notification.types';
|
||||
|
||||
const POLL_INTERVAL_MS = 60_000; // 60 seconds
|
||||
const POLL_INTERVAL_MS = 15_000; // 15 seconds
|
||||
|
||||
/**
|
||||
* Only allow window.open for URLs whose origin matches the current app origin.
|
||||
@@ -58,29 +59,50 @@ function formatRelative(iso: string): string {
|
||||
|
||||
const NotificationBell: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { showNotificationToast } = useNotification();
|
||||
const [unreadCount, setUnreadCount] = useState(0);
|
||||
const [notifications, setNotifications] = useState<Notification[]>([]);
|
||||
const [loadingList, setLoadingList] = useState(false);
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
const pollTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
// Track known notification IDs to detect new ones; null = not yet initialized
|
||||
const knownIdsRef = useRef<Set<string> | null>(null);
|
||||
|
||||
const fetchUnreadCount = useCallback(async () => {
|
||||
const fetchAndToastNew = useCallback(async () => {
|
||||
try {
|
||||
const count = await notificationsApi.getUnreadCount();
|
||||
const data = await notificationsApi.getNotifications();
|
||||
const unread = data.filter((n) => !n.gelesen);
|
||||
const count = unread.length;
|
||||
setUnreadCount(count);
|
||||
|
||||
if (knownIdsRef.current === null) {
|
||||
// First load — initialize without toasting
|
||||
knownIdsRef.current = new Set(data.map((n) => n.id));
|
||||
return;
|
||||
}
|
||||
|
||||
// Find notifications we haven't seen before
|
||||
const newOnes = unread.filter((n) => !knownIdsRef.current!.has(n.id));
|
||||
newOnes.forEach((n) => {
|
||||
knownIdsRef.current!.add(n.id);
|
||||
const severity = n.schwere === 'fehler' ? 'error' : n.schwere === 'warnung' ? 'warning' : 'info';
|
||||
showNotificationToast(n.titel, severity);
|
||||
});
|
||||
// Also add all known IDs to avoid re-toasting on re-fetch
|
||||
data.forEach((n) => knownIdsRef.current!.add(n.id));
|
||||
} catch {
|
||||
// non-critical
|
||||
}
|
||||
}, []);
|
||||
}, [showNotificationToast]);
|
||||
|
||||
// Poll unread count every 60 seconds
|
||||
// Poll for new notifications every 15 seconds
|
||||
useEffect(() => {
|
||||
fetchUnreadCount();
|
||||
pollTimerRef.current = setInterval(fetchUnreadCount, POLL_INTERVAL_MS);
|
||||
fetchAndToastNew();
|
||||
pollTimerRef.current = setInterval(fetchAndToastNew, POLL_INTERVAL_MS);
|
||||
return () => {
|
||||
if (pollTimerRef.current) clearInterval(pollTimerRef.current);
|
||||
};
|
||||
}, [fetchUnreadCount]);
|
||||
}, [fetchAndToastNew]);
|
||||
|
||||
const handleOpen = async (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
@@ -88,6 +110,12 @@ const NotificationBell: React.FC = () => {
|
||||
try {
|
||||
const data = await notificationsApi.getNotifications();
|
||||
setNotifications(data);
|
||||
// Mark all as known so we don't toast them again
|
||||
if (knownIdsRef.current === null) {
|
||||
knownIdsRef.current = new Set(data.map((n) => n.id));
|
||||
} else {
|
||||
data.forEach((n) => knownIdsRef.current!.add(n.id));
|
||||
}
|
||||
// Refresh count after loading full list
|
||||
const count = await notificationsApi.getUnreadCount();
|
||||
setUnreadCount(count);
|
||||
|
||||
Reference in New Issue
Block a user