import type { EventInfo } from '../types'; import type { KycSubmission } from './kyc.types'; import { Dialog } from '@radix-ui/react-dialog'; import { useCallback, useEffect, useState } from 'react'; import { useStore } from 'zustand'; import { postKycQuery } from '@/client'; import { useCreateKycSession } from '@/hooks/data/useCreateKycSession'; import { useJoinEvent } from '@/hooks/data/useJoinEvent'; import { KycFailedDialogView } from './kyc-failed.dialog.view'; import { KycMethodSelectionDialogView } from './kyc-method-selection.dialog.view'; import { KycPendingDialogView } from './kyc-pending.dialog.view'; import { KycPromptDialogView } from './kyc-prompt.dialog.view'; import { KycSuccessDialogView } from './kyc-success.dialog.view'; import { createKycStore } from './kyc.state'; 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); const setStage = useStore(store, s => s.setStage); const setKycId = useStore(store, s => s.setKycId); const { mutateAsync: createKycSessionAsync } = useCreateKycSession(); const { mutateAsync: joinEventAsync } = useJoinEvent(); const joinEvent = useCallback(async (eventId: string, kycId: string, abortSignal?: AbortSignal) => { try { await joinEventAsync({ signal: abortSignal, body: { event_id: eventId, kyc_id: kycId }, }); setStage('success'); } catch (e) { console.error('Error joining event:', e); setStage('failed'); } }, [joinEventAsync, setStage]); const onKycSessionCreate = useCallback(async (submission: KycSubmission) => { try { const { data } = await createKycSessionAsync(submission); setKycId(data!.kyc_id!); if (data!.status === 'success') { await joinEvent(event.eventId, data!.kyc_id!, undefined); } else if (data!.status === 'processing') { window.open(data!.redirect_uri, '_blank'); setStage('pending'); } } catch (e) { console.error(e); setStage('failed'); } }, [event.eventId, joinEvent, createKycSessionAsync, setKycId, setStage]); useEffect(() => { if (stage !== 'pending' || !isDialogOpen) { return; } const controller = new AbortController(); let timer: NodeJS.Timeout; const poll = async () => { try { const { data } = await postKycQuery({ signal: controller.signal, body: { kyc_id: store.getState().kycId! }, }); const status = data?.data?.status; if (status === 'success') { void joinEvent(event.eventId, store.getState().kycId!, controller.signal); } else if (status === 'failed') { setStage('failed'); } else if (status === 'pending') { timer = setTimeout(() => void poll(), 1000); } else { // What the fuck? setStage('failed'); } } catch (e) { if ((e as Error).name === 'AbortError') return; console.error('Error fetching KYC status:', e); setStage('failed'); } }; void poll(); return () => { controller.abort(); clearTimeout(timer); }; }, [stage, store, setStage, isDialogOpen, joinEvent, event.eventId]); return ( {children} {stage === 'prompt' && setStage('methodSelection')} />} {stage === 'methodSelection' && } {stage === 'pending' && } {stage === 'success' && } {stage === 'failed' && } ); }