- Deleted the custom `useRunOnce` hook as its functionality is no longer needed. - Refactored `EventCard` to determine `type` (countup/countdown) dynamically based on the event state and current time. - Updated `EventCard` to pass `type` and `format` separately to the `Statistic.Timer` component, removing the need for string formatting logic inside the component. - Modified `ClubEventList` to add a 300ms delay on page initialization, ensuring the component is fully mounted before triggering the initial fetch logic.
124 lines
4.8 KiB
TypeScript
124 lines
4.8 KiB
TypeScript
import { Button, Divider, Empty, Flex, Pagination, Skeleton, Space, Switch, Typography } from "antd";
|
|
import type { IEventInfo } from "../types";
|
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
import { EventCard } from "./EventCard";
|
|
import { useRequest } from "ahooks";
|
|
import { CalendarOutlined } from "@ant-design/icons";
|
|
import { STORE_PAGE_LIST_KEY } from "../utils/constants";
|
|
|
|
interface Props {
|
|
clubId: string;
|
|
}
|
|
|
|
const getStorageKey = (clubId: string) => `events-page-${clubId}`;
|
|
|
|
export const ClubEvenList = (props: Props) => {
|
|
const [paginationControlVisible, setPaginationControlVisible] = useState(true);
|
|
const [showFinishedEvents, setShowFinishedEvents] = useState(false);
|
|
const requestEvents = useRequest<{data: IEventInfo[]; total: number; }, [string, number]>(
|
|
async (clubId: string, page = 1) => {
|
|
if (!clubId) return { data: [], total: 0 };
|
|
return fetch(`/api/club/${clubId}/events?page=${page}`).then(e => e.json());
|
|
}, { manual: true, refreshDeps: [] });
|
|
const [page, setPageState] = useState(1);
|
|
const setPage = useCallback((page: number) => {
|
|
const key = getStorageKey(props.clubId);
|
|
sessionStorage.setItem(key, page.toString());
|
|
setPageState(page);
|
|
}, [props.clubId])
|
|
const onPageChange = useCallback((page: number) => {
|
|
setPage(page);
|
|
requestEvents.runAsync(props.clubId, page);
|
|
}, [props.clubId, setPage]);
|
|
const pagination = useMemo(() => {
|
|
return {
|
|
page,
|
|
onPageChange,
|
|
total: requestEvents.data?.total ?? 0,
|
|
}
|
|
}, [requestEvents.data?.total, page]);
|
|
const visibleEvents = useMemo(() => {
|
|
const events = requestEvents.data?.data || [];
|
|
if (showFinishedEvents) return events;
|
|
return events.filter(e => !e.isFinished);
|
|
}, [showFinishedEvents, requestEvents.data?.data]);
|
|
const onPageInit = useCallback(async () => {
|
|
const storePageKey = getStorageKey(props.clubId);
|
|
const keys: string[] = JSON.parse(localStorage.getItem(STORE_PAGE_LIST_KEY) ?? '[]');
|
|
if (!keys.includes(storePageKey)) {
|
|
keys.push(storePageKey);
|
|
localStorage.setItem(STORE_PAGE_LIST_KEY, JSON.stringify(keys));
|
|
}
|
|
const prePage = Number(sessionStorage.getItem(storePageKey)) || 1;
|
|
const data = await requestEvents.runAsync(props.clubId, prePage).then(res => res.data);
|
|
setPage(prePage);
|
|
if (data.length) {
|
|
const isAllFinishedOrAllNotFinished = data.every(e => e.isFinished) || data.every(e => !e.isFinished);
|
|
setShowFinishedEvents(prePage !== 1 || isAllFinishedOrAllNotFinished);
|
|
setPaginationControlVisible(prePage === 1 ? !isAllFinishedOrAllNotFinished : false);
|
|
}
|
|
}, [props.clubId]);
|
|
useEffect(() => {
|
|
const id = setTimeout(() => {
|
|
onPageInit();
|
|
}, 300);
|
|
return () => clearTimeout(id);
|
|
}, [onPageInit]);
|
|
const handleAddToCalendar = useCallback(() => {
|
|
const url = `${window.location.origin}/api/club/${props.clubId}/calendar.ics`;
|
|
const uri = url.replace(/^http(s)?/, 'webcal');
|
|
console.debug(uri);
|
|
window.open(uri);
|
|
}, [props.clubId, page]);
|
|
return (
|
|
<>
|
|
<Divider>
|
|
{paginationControlVisible ? (
|
|
<Space>
|
|
<Typography.Text type="secondary">显示已结束的活动</Typography.Text>
|
|
<Switch checked={showFinishedEvents} onChange={() => setShowFinishedEvents(!showFinishedEvents)} unCheckedChildren="隐藏" checkedChildren="显示" />
|
|
</Space>
|
|
) : null}
|
|
</Divider>
|
|
<Flex wrap vertical gap={12} justify="center" align="center">
|
|
<Button
|
|
type="link"
|
|
icon={<CalendarOutlined />}
|
|
onClick={handleAddToCalendar}
|
|
>
|
|
订阅该俱乐部比赛
|
|
</Button>
|
|
{showFinishedEvents ? (
|
|
<Pagination
|
|
showQuickJumper
|
|
total={pagination.total}
|
|
current={pagination.page}
|
|
onChange={pagination.onPageChange}
|
|
showSizeChanger={false}
|
|
/>) : null}
|
|
{requestEvents.loading ? (
|
|
<Flex vertical gap={12} style={{ width: '100%', maxWidth: 600 }}>
|
|
<Skeleton.Button active style={{ height: 200 }} block size="large" />
|
|
<Skeleton.Button active style={{ height: 200 }} block size="large" />
|
|
<Skeleton.Button active style={{ height: 200 }} block size="large" />
|
|
</Flex>
|
|
) : (<>{visibleEvents.length ? visibleEvents.map(e => {
|
|
return (
|
|
<div key={e.matchId} style={{ width: '100%', maxWidth: 600 }}>
|
|
<EventCard eventInfo={e} />
|
|
</div>
|
|
);
|
|
}) : <Empty description="暂无活动" />}</>)}
|
|
|
|
{showFinishedEvents ? (
|
|
<Pagination
|
|
showQuickJumper
|
|
total={pagination.total}
|
|
current={pagination.page}
|
|
onChange={pagination.onPageChange}
|
|
showSizeChanger={false}
|
|
/>) : null}
|
|
</Flex>
|
|
</>
|
|
);
|
|
} |