diff --git a/client/cms/src/components/events/event-grid.container.tsx b/client/cms/src/components/events/event-grid.container.tsx index 888a1c5..0f78db6 100644 --- a/client/cms/src/components/events/event-grid.container.tsx +++ b/client/cms/src/components/events/event-grid.container.tsx @@ -5,8 +5,15 @@ import { Button } from '../ui/button'; import { DialogTrigger } from '../ui/dialog'; import { EventGridSkeleton } from './event-grid.skeleton'; import { EventGridView } from './event-grid.view'; +import { EventJoinContainer } from './event-join.dialog.container'; import { KycDialogContainer } from './kyc/kyc.dialog.container'; +function JoinButton() { + return ( + + ); +} + export function EventGridContainer() { const { data, isLoading } = useGetEvents(); @@ -29,11 +36,21 @@ export function EventGridContainer() { footer={eventInfo => (eventInfo.isJoined ? : ( - - - - - + eventInfo.requireKyc + ? ( + + + + + + ) + : ( + + + + + + ) ) )} /> diff --git a/client/cms/src/components/events/event-join.dialog.container.tsx b/client/cms/src/components/events/event-join.dialog.container.tsx new file mode 100644 index 0000000..bbfc38f --- /dev/null +++ b/client/cms/src/components/events/event-join.dialog.container.tsx @@ -0,0 +1,25 @@ +import type { EventInfo } from './types'; +import { useCallback } from 'react'; +import { toast } from 'sonner'; +import { useJoinEvent } from '@/hooks/data/useJoinEvent'; +import { Dialog } from '../ui/dialog'; +import { EventJoinDialogView } from './event-join.dialog.view'; + +export function EventJoinContainer({ event, children }: { event: EventInfo; children: React.ReactNode }) { + const { mutateAsync } = useJoinEvent(); + const join = useCallback(() => { + mutateAsync({ body: { event_id: event.eventId } }).then(() => { + toast('加入活动成功'); + }).catch((error) => { + console.error(error); + toast.error('加入活动失败'); + }); + }, [event.eventId, mutateAsync]); + + return ( + + {children} + + + ); +} diff --git a/client/cms/src/components/events/event-join.dialog.view.tsx b/client/cms/src/components/events/event-join.dialog.view.tsx new file mode 100644 index 0000000..3a90d1f --- /dev/null +++ b/client/cms/src/components/events/event-join.dialog.view.tsx @@ -0,0 +1,25 @@ +import type { EventInfo } from './types'; +import { Button } from '../ui/button'; +import { DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '../ui/dialog'; + +export function EventJoinDialogView({ event, onJoinEvent }: { event: EventInfo; onJoinEvent: () => void }) { + return ( + + + 加入活动 + + 是否确认要加入活动 + {' '} + {event.eventName} + ? + + + + + + + + + + ); +} diff --git a/client/cms/src/components/events/kyc/kyc.dialog.container.tsx b/client/cms/src/components/events/kyc/kyc.dialog.container.tsx index 0ab3c8b..1e043ee 100644 --- a/client/cms/src/components/events/kyc/kyc.dialog.container.tsx +++ b/client/cms/src/components/events/kyc/kyc.dialog.container.tsx @@ -1,3 +1,4 @@ +import type { EventInfo } from '../types'; import type { KycSubmission } from './kyc.types'; import { Dialog } from '@radix-ui/react-dialog'; import { useQueryClient } from '@tanstack/react-query'; @@ -13,8 +14,8 @@ import { KycPromptDialogView } from './kyc-prompt.dialog.view'; import { KycSuccessDialogView } from './kyc-success.dialog.view'; import { createKycStore } from './kyc.state'; -export function KycDialogContainer({ eventIdToJoin, children }: { eventIdToJoin: string; children: React.ReactNode }) { - const [store] = useState(() => createKycStore(eventIdToJoin)); +export function KycDialogContainer({ event, children }: { event: EventInfo; children: React.ReactNode }) { + const [store] = useState(() => createKycStore(event.eventId)); const isDialogOpen = useStore(store, s => s.isDialogOpen); const setIsDialogOpen = useStore(store, s => s.setIsDialogOpen); const stage = useStore(store, s => s.stage); @@ -43,7 +44,7 @@ export function KycDialogContainer({ eventIdToJoin, children }: { eventIdToJoin: const { data } = await mutateAsync(submission); setKycId(data!.kyc_id!); if (data!.status === 'success') { - await joinEvent(eventIdToJoin, data!.kyc_id!, undefined); + await joinEvent(event.eventId, data!.kyc_id!, undefined); } else if (data!.status === 'processing') { window.open(data!.redirect_uri, '_blank'); @@ -54,7 +55,7 @@ export function KycDialogContainer({ eventIdToJoin, children }: { eventIdToJoin: console.error(e); setStage('failed'); } - }, [eventIdToJoin, joinEvent, mutateAsync, setKycId, setStage]); + }, [event.eventId, joinEvent, mutateAsync, setKycId, setStage]); useEffect(() => { if (stage !== 'pending' || !isDialogOpen) { @@ -74,7 +75,7 @@ export function KycDialogContainer({ eventIdToJoin, children }: { eventIdToJoin: const status = data?.data?.status; if (status === 'success') { - void joinEvent(eventIdToJoin, store.getState().kycId!, controller.signal); + void joinEvent(event.eventId, store.getState().kycId!, controller.signal); } else if (status === 'failed') { setStage('failed'); @@ -101,7 +102,7 @@ export function KycDialogContainer({ eventIdToJoin, children }: { eventIdToJoin: controller.abort(); clearTimeout(timer); }; - }, [stage, store, setStage, isDialogOpen, joinEvent, eventIdToJoin]); + }, [stage, store, setStage, isDialogOpen, joinEvent, event.eventId]); return ( ; export const Primary: Story = { args: { - eventInfo: { - eventId: '1', - type: 'official', - requireKyc: true, - isJoined: false, - coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-watersplash.png?raw=true', - eventName: 'Nix CN Conference 26.05', - description: 'Event Description', - startTime: new Date('2026-06-13T04:00:00.000Z'), - endTime: new Date('2026-06-14T04:00:00.000Z'), - }, + eventInfo: exampleEvent, actionFooter: , }, }; diff --git a/client/cms/src/stories/events/event.example.ts b/client/cms/src/stories/events/event.example.ts new file mode 100644 index 0000000..1dc8ec5 --- /dev/null +++ b/client/cms/src/stories/events/event.example.ts @@ -0,0 +1,13 @@ +import type { EventInfo } from '@/components/events/types'; + +export const exampleEvent: EventInfo = { + eventId: '1', + type: 'official', + requireKyc: true, + isJoined: false, + coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-watersplash.png?raw=true', + eventName: 'Nix CN Conference 26.05', + description: 'Event Description', + startTime: new Date('2026-06-13T04:00:00.000Z'), + endTime: new Date('2026-06-14T04:00:00.000Z'), +}; diff --git a/client/cms/src/stories/events/join-dialog.stories.tsx b/client/cms/src/stories/events/join-dialog.stories.tsx new file mode 100644 index 0000000..5b53c14 --- /dev/null +++ b/client/cms/src/stories/events/join-dialog.stories.tsx @@ -0,0 +1,26 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { EventJoinDialogView } from '@/components/events/event-join.dialog.view'; +import { Dialog } from '@/components/ui/dialog'; +import { exampleEvent } from './event.example'; + +const meta = { + title: 'Events/JoinDialog', + component: EventJoinDialogView, + decorators: [ + Story => ( + + + + ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Confirm: Story = { + args: { + event: exampleEvent, + onJoinEvent: () => { }, + }, +};