86 lines
3.1 KiB
TypeScript
86 lines
3.1 KiB
TypeScript
|
|
|
||
|
|
import { useEffect, useState, useCallback } from 'react';
|
||
|
|
import { useModel, request } from '@umijs/max';
|
||
|
|
import { notification as antdNotification } from 'antd';
|
||
|
|
import { Notification, NotificationType } from '@/types';
|
||
|
|
|
||
|
|
export const useNotifications = () => {
|
||
|
|
const { initialState } = useModel('@@initialState');
|
||
|
|
const { stompClient } = useModel('stomp');
|
||
|
|
const [notifications, setNotifications] = useState<Notification[]>([]);
|
||
|
|
const [unreadCount, setUnreadCount] = useState(0);
|
||
|
|
|
||
|
|
const fetchUnreadNotifications = useCallback(async () => {
|
||
|
|
if (!initialState?.currentUser) return;
|
||
|
|
try {
|
||
|
|
const res = await request<Notification[]>('/user-api/message/unread');
|
||
|
|
setNotifications(res);
|
||
|
|
setUnreadCount(res.length);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to fetch unread notifications', error);
|
||
|
|
}
|
||
|
|
}, [initialState?.currentUser]);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
fetchUnreadNotifications();
|
||
|
|
}, [fetchUnreadNotifications]);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (initialState?.currentUser && stompClient?.connected) {
|
||
|
|
const subscription = stompClient.subscribe(
|
||
|
|
'/user/queue/notification',
|
||
|
|
(message) => {
|
||
|
|
try {
|
||
|
|
const newNotification: Notification = JSON.parse(message.body);
|
||
|
|
setNotifications((prev) => [newNotification, ...prev]);
|
||
|
|
setUnreadCount((prev) => prev + 1);
|
||
|
|
|
||
|
|
antdNotification.open({
|
||
|
|
message: getNotificationTitle(newNotification.type),
|
||
|
|
description: newNotification.content,
|
||
|
|
});
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to parse notification', error);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
return () => {
|
||
|
|
subscription.unsubscribe();
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}, [initialState?.currentUser, stompClient]);
|
||
|
|
|
||
|
|
const markAsRead = useCallback(async (ids: number[]) => {
|
||
|
|
try {
|
||
|
|
await request('/api/user/notifications/read', {
|
||
|
|
method: 'POST',
|
||
|
|
data: ids,
|
||
|
|
});
|
||
|
|
setNotifications((prev) =>
|
||
|
|
prev.map((n) => (ids.includes(n.id) ? { ...n, read: true } : n))
|
||
|
|
);
|
||
|
|
setUnreadCount((prev) => prev - ids.length);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to mark notifications as read', error);
|
||
|
|
}
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const getNotificationTitle = (type: NotificationType) => {
|
||
|
|
switch (type) {
|
||
|
|
case NotificationType.FRIEND_REQUEST:
|
||
|
|
return '好友请求';
|
||
|
|
case NotificationType.FRIEND_ACCEPTED:
|
||
|
|
return '好友请求已接受';
|
||
|
|
case NotificationType.NEW_COMMENT:
|
||
|
|
return '有新的评论';
|
||
|
|
case NotificationType.NEW_LIKE:
|
||
|
|
return '有新的点赞';
|
||
|
|
default:
|
||
|
|
return '系统通知';
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return { notifications, unreadCount, markAsRead };
|
||
|
|
};
|