Files
timeline-frontend/src/hooks/useNotifications.ts
jianghao cd752d97d8
Some checks failed
test/timeline-frontend/pipeline/head There was a failure building this commit
feat: 支持视频上传、预览及移动端适配
1. 功能增强:
- 支持视频文件的上传、存储及缩略图自动生成
- 新增视频播放组件,支持在画廊和时间线中预览视频
- 引入 STOMP 协议支持 WebSocket 实时通知功能
- 增加分享页面(SSR 友好),支持通过 shareId 访问公开内容

2. 移动端优化:
- 新增 BottomNav 底部导航组件,优化移动端交互体验
- 引入 useIsMobile 钩子,实现响应式布局切换
- 优化时间线卡片在小屏幕下的显示效果

3. 架构与组件:
- 新增 ClientOnly 组件解决 SSR 激活不一致问题
- 新增 ResponsiveGrid 响应式网格布局组件
- 完善 Nginx 配置,增加 MinIO 对象存储代理
- 优化图片懒加载组件 TimelineImage,支持低分辨率占位图
2026-02-12 16:55:05 +08:00

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 };
};