NeahNew/hooks/use-notifications.ts
2025-05-04 11:01:30 +02:00

194 lines
5.4 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react';
import { useSession } from 'next-auth/react';
import { Notification, NotificationCount } from '@/lib/types/notification';
// Default empty notification count
const defaultNotificationCount: NotificationCount = {
total: 0,
unread: 0,
sources: {}
};
export function useNotifications() {
const { data: session, status } = useSession();
const [notifications, setNotifications] = useState<Notification[]>([]);
const [notificationCount, setNotificationCount] = useState<NotificationCount>(defaultNotificationCount);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [pollingInterval, setPollingInterval] = useState<NodeJS.Timeout | null>(null);
// Fetch notification count
const fetchNotificationCount = useCallback(async () => {
if (!session?.user) return;
try {
setError(null);
const response = await fetch('/api/notifications/count');
if (!response.ok) {
const errorData = await response.json();
console.error('Failed to fetch notification count:', errorData);
setError(errorData.error || 'Failed to fetch notification count');
return;
}
const data = await response.json();
setNotificationCount(data);
} catch (err) {
console.error('Error fetching notification count:', err);
setError('Failed to fetch notification count');
}
}, [session?.user]);
// Fetch notifications
const fetchNotifications = useCallback(async (page = 1, limit = 20) => {
if (!session?.user) return;
setLoading(true);
setError(null);
try {
const response = await fetch(`/api/notifications?page=${page}&limit=${limit}`);
if (!response.ok) {
const errorData = await response.json();
console.error('Failed to fetch notifications:', errorData);
setError(errorData.error || 'Failed to fetch notifications');
return;
}
const data = await response.json();
setNotifications(data.notifications);
} catch (err) {
console.error('Error fetching notifications:', err);
setError('Failed to fetch notifications');
} finally {
setLoading(false);
}
}, [session?.user]);
// Mark notification as read
const markAsRead = useCallback(async (notificationId: string) => {
if (!session?.user) return;
try {
const response = await fetch(`/api/notifications/${notificationId}/read`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
const errorData = await response.json();
console.error('Failed to mark notification as read:', errorData);
return false;
}
// Update local state
setNotifications(prev =>
prev.map(notification =>
notification.id === notificationId
? { ...notification, isRead: true }
: notification
)
);
// Refresh notification count
fetchNotificationCount();
return true;
} catch (err) {
console.error('Error marking notification as read:', err);
return false;
}
}, [session?.user, fetchNotificationCount]);
// Mark all notifications as read
const markAllAsRead = useCallback(async () => {
if (!session?.user) return;
try {
const response = await fetch('/api/notifications/read-all', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
const errorData = await response.json();
console.error('Failed to mark all notifications as read:', errorData);
return false;
}
// Update local state
setNotifications(prev =>
prev.map(notification => ({ ...notification, isRead: true }))
);
// Refresh notification count
fetchNotificationCount();
return true;
} catch (err) {
console.error('Error marking all notifications as read:', err);
return false;
}
}, [session?.user, fetchNotificationCount]);
// Start polling for notification count
const startPolling = useCallback((interval = 30000) => {
if (pollingInterval) {
clearInterval(pollingInterval);
}
const id = setInterval(() => {
fetchNotificationCount();
}, interval);
setPollingInterval(id);
return () => {
clearInterval(id);
setPollingInterval(null);
};
}, [fetchNotificationCount, pollingInterval]);
// Stop polling
const stopPolling = useCallback(() => {
if (pollingInterval) {
clearInterval(pollingInterval);
setPollingInterval(null);
}
}, [pollingInterval]);
// Initialize fetching on component mount
useEffect(() => {
if (status === 'authenticated' && session?.user) {
fetchNotificationCount();
fetchNotifications();
// Start polling
const cleanup = startPolling();
return () => {
cleanup();
};
}
}, [status, session?.user, fetchNotificationCount, fetchNotifications, startPolling]);
return {
notifications,
notificationCount,
loading,
error,
fetchNotifications,
fetchNotificationCount,
markAsRead,
markAllAsRead,
startPolling,
stopPolling
};
}