124 lines
3.9 KiB
TypeScript
124 lines
3.9 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import { io, Socket } from 'socket.io-client';
|
|
import { AdminNotification } from '@/types/admin.types';
|
|
import { SOCKET_URL } from '@/config/backend';
|
|
import { getAccessToken } from '@/components/apis/authApiClients';
|
|
|
|
interface NotificationCounts {
|
|
total: number;
|
|
unread: number;
|
|
read: number;
|
|
}
|
|
|
|
interface UseNotificationSocketReturn {
|
|
socket: Socket | null;
|
|
isConnected: boolean;
|
|
notificationCounts: NotificationCounts;
|
|
onNewNotification: (callback: (notification: AdminNotification) => void) => void;
|
|
onNotificationRead: (callback: (data: { id: string }) => void) => void;
|
|
onAllNotificationsRead: (callback: () => void) => void;
|
|
}
|
|
|
|
export function useNotificationSocket(): UseNotificationSocketReturn {
|
|
const [socket, setSocket] = useState<Socket | null>(null);
|
|
const [isConnected, setIsConnected] = useState(false);
|
|
const [notificationCounts, setNotificationCounts] = useState<NotificationCounts>({
|
|
total: 0,
|
|
unread: 0,
|
|
read: 0
|
|
});
|
|
|
|
const newNotificationCallbackRef = useRef<((notification: AdminNotification) => void) | null>(null);
|
|
const notificationReadCallbackRef = useRef<((data: { id: string }) => void) | null>(null);
|
|
const allNotificationsReadCallbackRef = useRef<(() => void) | null>(null);
|
|
|
|
useEffect(() => {
|
|
// Initialize socket connection
|
|
const templateManagerUrl = SOCKET_URL; // connect directly to template-manager socket server
|
|
const token = getAccessToken();
|
|
console.log('[useNotificationSocket] Initializing socket', {
|
|
url: templateManagerUrl,
|
|
hasToken: !!token,
|
|
tokenPreview: token ? token.substring(0, 12) + '...' : null
|
|
});
|
|
const newSocket = io(templateManagerUrl, {
|
|
transports: ['websocket', 'polling'],
|
|
timeout: 20000,
|
|
path: '/socket.io/',
|
|
auth: token ? { token } : undefined,
|
|
});
|
|
|
|
newSocket.on('connect', () => {
|
|
console.log('🔌 Connected to notification socket');
|
|
setIsConnected(true);
|
|
});
|
|
|
|
newSocket.on('disconnect', () => {
|
|
console.log('🔌 Disconnected from notification socket');
|
|
setIsConnected(false);
|
|
});
|
|
|
|
newSocket.on('notification-count', (counts: NotificationCounts) => {
|
|
console.log('📊 Notification counts updated:', counts);
|
|
setNotificationCounts(counts);
|
|
});
|
|
|
|
newSocket.on('new-notification', (notification: AdminNotification) => {
|
|
console.log('🔔 New notification received:', notification);
|
|
if (newNotificationCallbackRef.current) {
|
|
newNotificationCallbackRef.current(notification);
|
|
}
|
|
});
|
|
|
|
newSocket.on('notification-read', (data: { id: string }) => {
|
|
console.log('✅ Notification marked as read:', data.id);
|
|
if (notificationReadCallbackRef.current) {
|
|
notificationReadCallbackRef.current(data);
|
|
}
|
|
});
|
|
|
|
newSocket.on('all-notifications-read', () => {
|
|
console.log('✅ All notifications marked as read');
|
|
if (allNotificationsReadCallbackRef.current) {
|
|
allNotificationsReadCallbackRef.current();
|
|
}
|
|
});
|
|
|
|
newSocket.on('connect_error', (error: any) => {
|
|
console.error('🔌 Socket connection error:', {
|
|
message: error?.message,
|
|
name: error?.name,
|
|
data: error?.data
|
|
});
|
|
setIsConnected(false);
|
|
});
|
|
|
|
setSocket(newSocket);
|
|
|
|
return () => {
|
|
newSocket.close();
|
|
};
|
|
}, []);
|
|
|
|
const onNewNotification = (callback: (notification: AdminNotification) => void) => {
|
|
newNotificationCallbackRef.current = callback;
|
|
};
|
|
|
|
const onNotificationRead = (callback: (data: { id: string }) => void) => {
|
|
notificationReadCallbackRef.current = callback;
|
|
};
|
|
|
|
const onAllNotificationsRead = (callback: () => void) => {
|
|
allNotificationsReadCallbackRef.current = callback;
|
|
};
|
|
|
|
return {
|
|
socket,
|
|
isConnected,
|
|
notificationCounts,
|
|
onNewNotification,
|
|
onNotificationRead,
|
|
onAllNotificationsRead,
|
|
};
|
|
}
|