- 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.
101 lines
2.8 KiB
TypeScript
101 lines
2.8 KiB
TypeScript
import { Button, Card, Statistic, Typography } from "antd";
|
|
import type { IEventInfo } from "../types";
|
|
import dayjs from "dayjs";
|
|
import utc from 'dayjs/plugin/utc';
|
|
import timezone from 'dayjs/plugin/timezone';
|
|
import { EyeOutlined } from "@ant-design/icons";
|
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
import { useNavigate } from "react-router";
|
|
import type { TimerType } from "antd/lib/statistic/Timer";
|
|
|
|
dayjs.extend(utc);
|
|
dayjs.extend(timezone);
|
|
|
|
interface EventCardProps {
|
|
eventInfo: IEventInfo;
|
|
}
|
|
|
|
export function EventCard(props: EventCardProps) {
|
|
const { eventInfo: e } = props;
|
|
const day = useMemo(() => dayjs.tz(e.startDate, 'Asia/Tokyo'), [e]);
|
|
const navigate = useNavigate();
|
|
const handleView = useCallback(() => {
|
|
navigate(`/event/${e.matchId}`);
|
|
}, [e]);
|
|
const [messageFormat, setMessageFormat] = useState('');
|
|
const getStatisticProps = useCallback((): {
|
|
format: string;
|
|
type: TimerType;
|
|
} => {
|
|
if (e.isFinished) {
|
|
if (dayjs().diff(day, 'days') < 1) return {
|
|
type: 'countdown',
|
|
format: `已结束`,
|
|
};
|
|
return {
|
|
type: 'countup',
|
|
format: `已结束 DD 天`,
|
|
};
|
|
}
|
|
if (e.isProcessing) {
|
|
return {
|
|
type: 'countup',
|
|
format: '比赛进行中 HH:mm:ss',
|
|
}
|
|
}
|
|
if (dayjs().diff(day, 'days') === 0) {
|
|
return {
|
|
type: 'countdown',
|
|
format: `距离比赛开始还有 HH:mm:ss`,
|
|
};
|
|
}
|
|
return {
|
|
type: 'countdown',
|
|
format: `距离比赛开始还有 DD 天 HH:mm:ss`,
|
|
};
|
|
}, [e, day]);
|
|
const [statisticType, setStatisticType] = useState<TimerType>('countdown');
|
|
const updateMessageFormat = useCallback(() => {
|
|
const statistic = getStatisticProps();
|
|
setMessageFormat(statistic.format);
|
|
setStatisticType(statistic.type);
|
|
console.debug('format: %s', day.format(statistic.format), statistic);
|
|
}, [getStatisticProps])
|
|
useEffect(() => {
|
|
const timeout = day.toDate().getTime() - Date.now();
|
|
updateMessageFormat();
|
|
const id = setTimeout(() => {
|
|
updateMessageFormat();
|
|
}, timeout);
|
|
return () => clearTimeout(id);
|
|
}, [updateMessageFormat]);
|
|
return (
|
|
<Card
|
|
key={e.matchId}
|
|
title={e.title}
|
|
style={{ width: '100%' }}
|
|
actions={[
|
|
<Button
|
|
type="link"
|
|
onClick={handleView}
|
|
icon={<EyeOutlined />}
|
|
>
|
|
查看
|
|
</Button>,
|
|
]}
|
|
>
|
|
<Typography.Text type={e.isFinished ? 'secondary' : 'success'}>{e.title}</Typography.Text>
|
|
<Statistic.Timer
|
|
type={statisticType}
|
|
value={day.toDate().getTime()}
|
|
format={messageFormat}
|
|
styles={{ content: e.isFinished ? { color: 'gray' } : {} }}
|
|
/>
|
|
{e.info.map(e => (
|
|
<div key={e}>
|
|
<Typography.Text type='secondary'>{e}</Typography.Text>
|
|
</div>
|
|
))}
|
|
</Card>
|
|
)
|
|
} |