109 lines
3.9 KiB
JavaScript
109 lines
3.9 KiB
JavaScript
// src/hooks/useFollowingEvents.js
|
||
// 关注事件管理自定义 Hook
|
||
|
||
import { useState, useCallback } from 'react';
|
||
import { useToast } from '@chakra-ui/react';
|
||
import { logger } from '../utils/logger';
|
||
import { getApiBase } from '../utils/apiConfig';
|
||
|
||
const EVENTS_PAGE_SIZE = 8;
|
||
|
||
/**
|
||
* 关注事件管理 Hook
|
||
* 提供事件加载、分页、取消关注等功能
|
||
*
|
||
* @returns {{
|
||
* followingEvents: Array,
|
||
* eventsLoading: boolean,
|
||
* eventsPage: number,
|
||
* setEventsPage: Function,
|
||
* EVENTS_PAGE_SIZE: number,
|
||
* loadFollowingEvents: Function,
|
||
* handleUnfollowEvent: Function
|
||
* }}
|
||
*/
|
||
export const useFollowingEvents = () => {
|
||
const toast = useToast();
|
||
const [followingEvents, setFollowingEvents] = useState([]);
|
||
const [eventsLoading, setEventsLoading] = useState(false);
|
||
const [eventsPage, setEventsPage] = useState(1);
|
||
|
||
// 加载关注的事件
|
||
const loadFollowingEvents = useCallback(async () => {
|
||
try {
|
||
setEventsLoading(true);
|
||
const base = getApiBase();
|
||
const resp = await fetch(base + '/api/account/events/following', {
|
||
credentials: 'include',
|
||
cache: 'no-store'
|
||
});
|
||
if (resp.ok) {
|
||
const data = await resp.json();
|
||
if (data && data.success && Array.isArray(data.data)) {
|
||
// 合并重复的事件(用最新的数据)
|
||
const eventMap = new Map();
|
||
for (const evt of data.data) {
|
||
if (evt && evt.id) {
|
||
eventMap.set(evt.id, evt);
|
||
}
|
||
}
|
||
const merged = Array.from(eventMap.values());
|
||
// 按创建时间降序排列(假设事件有 created_at 或 id)
|
||
if (merged.length > 0 && merged[0].created_at) {
|
||
merged.sort((a, b) => new Date(b.created_at || 0) - new Date(a.created_at || 0));
|
||
} else {
|
||
merged.sort((a, b) => (b.id || 0) - (a.id || 0));
|
||
}
|
||
setFollowingEvents(merged);
|
||
} else {
|
||
setFollowingEvents([]);
|
||
}
|
||
} else {
|
||
setFollowingEvents([]);
|
||
}
|
||
} catch (e) {
|
||
logger.warn('useFollowingEvents', '加载关注事件失败', {
|
||
error: e.message
|
||
});
|
||
setFollowingEvents([]);
|
||
} finally {
|
||
setEventsLoading(false);
|
||
}
|
||
}, []);
|
||
|
||
// 取消关注事件
|
||
const handleUnfollowEvent = useCallback(async (eventId) => {
|
||
try {
|
||
const base = getApiBase();
|
||
const resp = await fetch(base + `/api/events/${eventId}/follow`, {
|
||
method: 'POST',
|
||
credentials: 'include'
|
||
});
|
||
const data = await resp.json().catch(() => ({}));
|
||
if (resp.ok && data && data.success !== false) {
|
||
setFollowingEvents((prev) => {
|
||
const updated = (prev || []).filter((x) => x.id !== eventId);
|
||
const newMaxPage = Math.max(1, Math.ceil((updated.length || 0) / EVENTS_PAGE_SIZE));
|
||
setEventsPage((p) => Math.min(p, newMaxPage));
|
||
return updated;
|
||
});
|
||
toast({ title: '已取消关注该事件', status: 'info', duration: 1500 });
|
||
} else {
|
||
toast({ title: '操作失败', status: 'error', duration: 2000 });
|
||
}
|
||
} catch (e) {
|
||
toast({ title: '网络错误,操作失败', status: 'error', duration: 2000 });
|
||
}
|
||
}, [toast]);
|
||
|
||
return {
|
||
followingEvents,
|
||
eventsLoading,
|
||
eventsPage,
|
||
setEventsPage,
|
||
EVENTS_PAGE_SIZE,
|
||
loadFollowingEvents,
|
||
handleUnfollowEvent
|
||
};
|
||
};
|