diff --git a/src/components/ClubEventList.tsx b/src/components/ClubEventList.tsx index cdecc47..0e9112f 100644 --- a/src/components/ClubEventList.tsx +++ b/src/components/ClubEventList.tsx @@ -1,18 +1,20 @@ -import { Divider, Empty, Flex, Pagination, Skeleton, Space, Spin, Switch, Typography } from "antd"; +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"; interface Props { clubId: string; } export const ClubEvenList = (props: Props) => { + const [showAllDisable, setShowAllDiable] = useState(false); const [showAll, setShowAll] = useState(false); const requestEvents = useRequest<{data: IEventInfo[]; total: number; }, [string, number]>( async (clubId: string, page = 1) => { if (!clubId) return []; - return (await fetch(`/api/events/${clubId}?page=${page}`)).json() + return (await fetch(`/api/club/${clubId}/events?page=${page}`)).json() }, { manual: true }); const [page, setPage] = useState(1); const onPageChange = useCallback((page: number) => { @@ -37,21 +39,40 @@ export const ClubEvenList = (props: Props) => { } }, [showAll, onPageChange]); useEffect(() => { - const id = setTimeout(() => { - requestEvents.run(props.clubId, 1); + const id = setTimeout(async () => { + const data = await requestEvents.runAsync(props.clubId, 1).then(res => res.data); setPage(1); + if (data.length === 10) { + setShowAll(data.every(e => !e.isFinished)); + setShowAllDiable(data.every(e => !e.isFinished)); + } }, 100); return () => clearTimeout(id); }, [props.clubId]); + const handleAddToCalendar = useCallback(() => { + const url = `${window.location.origin}/api/club/${props.clubId}/calendar.ics?page=${page}`; + const uri = url.replace(/^http(s)?/, 'webcal'); + console.debug(uri); + window.open(uri); + }, [props.clubId, page]); return ( <> - - 显示已结束的活动 - setShowAll(!showAll)} unCheckedChildren="隐藏" checkedChildren="显示" /> - + {showAllDisable ? null : ( + + 显示已结束的活动 + setShowAll(!showAll)} unCheckedChildren="隐藏" checkedChildren="显示" /> + + )} + {showAll ? ( void; +} + +export const ClubSearchTable = (props: Props) => { + const [searchKey, setSearchKey] = useState(''); + const searchClub = useRequest<{ clubs: ClubInfo[], total: number }, [string, number]>(async (searchKey: string, page = 1) => { + const resp: { clubs: ClubInfo[], total: number } = await fetch(`/api/club/find?key=${searchKey}&page=${page}`).then(e => e.json()); + return resp; + }, { manual: true }); + const [page, setPage] = useState(1); + const handleSearch = useCallback((searchKey: string) => { + searchClub.runAsync(searchKey, 1); + }, [searchKey]); + return ( + + { + setSearchKey(e); + handleSearch(e); + }} + onPressEnter={() => handleSearch(searchKey)} + value={searchKey} + onChange={e => setSearchKey(e.target.value)} + /> + e.id} + loading={searchClub.loading} + dataSource={searchClub.data?.clubs} + style={{ width: '100%' }} + scroll={{ x: 400 }} + pagination={{ + current: page, + showSizeChanger: false, + total: searchClub.data?.total, + onChange: (page) => { + setPage(page); + searchClub.runAsync(searchKey, page); + } + }} + > + { + return ( + + + {name} + + ); + }} /> + + `${num} 人`} /> + { + return ( + + + + + ); + }} /> +
+
+ ); +} \ No newline at end of file diff --git a/src/components/EventCard.tsx b/src/components/EventCard.tsx index 37f41bd..d8bd7f0 100644 --- a/src/components/EventCard.tsx +++ b/src/components/EventCard.tsx @@ -1,8 +1,8 @@ import { Button, Card, Statistic, Typography } from "antd"; import type { IEventInfo } from "../types"; import dayjs from "dayjs"; -import { EyeOutlined } from "@ant-design/icons"; -import { useCallback, useMemo } from "react"; +import { CalendarOutlined, EyeOutlined } from "@ant-design/icons"; +import { useCallback } from "react"; import { useNavigate } from "react-router"; interface EventCardProps { @@ -16,19 +16,31 @@ export function EventCard(props: EventCardProps) { const handleView = useCallback(() => { navigate(`/event/${e.matchId}`); }, [e]); + const handleAddCalendar = useCallback(() => { + const url = `${window.location.origin}/calendar/event/${e.matchId}/events.ics`; + const uri = url.replace(/^http(s)?/, 'webcal'); + window.open(uri); + }, [e]); return ( } + onClick={handleAddCalendar} + > + 加入日历 + , + , ]} > {e.title} diff --git a/src/components/GameSelector/GameSelector.tsx b/src/components/GameSelector/GameSelector.tsx index 72a987d..ef36f9d 100644 --- a/src/components/GameSelector/GameSelector.tsx +++ b/src/components/GameSelector/GameSelector.tsx @@ -1,30 +1,87 @@ -import { Flex, Select, Space } from 'antd'; +import { Button, Drawer, Flex, Select, Space } from 'antd'; import type React from 'react'; import { clubs } from './clubList'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { ClubEvenList } from '../ClubEventList'; +import { DeleteOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons'; +import { useClubStore } from '../../store/useClubStore'; +import { ClubSearchTable } from '../ClubSearchTable'; interface Props { } +const defaultOptions = clubs.map(e => ({ + label: e.name, + value: e.clubId, +})); export const GameSelector: React.FC = () => { + const [options, setOptions] = useState<{ label: React.ReactNode, value: string }[]>(defaultOptions); const [clubId, setClubId] = useState(clubs[0]?.clubId ?? ''); + const clubStore = useClubStore(store => store); const handleClubChange = useCallback(async (id: string) => { setClubId(id); }, []); + const [searchOpen, setSearchOpen] = useState(false); + useEffect(() => { + if (clubStore.clubs.length) { + setOptions([...defaultOptions, ...clubStore.clubs.map(info => ({ + label: ( + + {info.name} +