import { useState, useCallback } from 'react'; import { useDubs } from '../provider'; import { signAndSendBase64Transaction } from '../utils/transaction'; import type { JoinGameParams, MutationStatus } from '../types'; import { emitCreditsChanged } from './useCredits'; export interface JoinGameMutationResult { gameId: string; gameAddress: string; signature: string; explorerUrl: string; } export function useJoinGame() { const { client, wallet, connection } = useDubs(); const [status, setStatus] = useState('idle'); const [error, setError] = useState(null); const [data, setData] = useState(null); const reset = useCallback(() => { setStatus('idle'); setError(null); setData(null); }, []); const execute = useCallback(async (params: JoinGameParams): Promise => { setStatus('building'); setError(null); setData(null); try { // 1. Build unsigned transaction console.log('[useJoinGame] Step 1: Building transaction...', { gameId: params.gameId, playerWallet: params.playerWallet, teamChoice: params.teamChoice, amount: params.amount }); const joinResult = await client.joinGame(params); console.log('[useJoinGame] Step 1 done:', { gameId: joinResult.gameId, gameAddress: joinResult.gameAddress, hasTx: !!joinResult.transaction }); // 2. Sign and send transaction setStatus('signing'); console.log('[useJoinGame] Step 2: Signing and sending transaction...'); const signature = await signAndSendBase64Transaction( joinResult.transaction, wallet, connection, ); console.log('[useJoinGame] Step 2 done. Signature:', signature); // 3. Confirm with backend (server handles on-chain verification) setStatus('confirming'); const confirmParams = { gameId: params.gameId, playerWallet: params.playerWallet, signature, teamChoice: params.teamChoice, wagerAmount: params.amount, role: 'joiner' as const, gameAddress: joinResult.gameAddress, // Pass through when this was a sponsored join — server marks // the credit as used after the on-chain confirm succeeds. promoCode: joinResult.promoCode, }; console.log('[useJoinGame] Step 3: Confirming with backend...', confirmParams); const confirmResult = await client.confirmGame(confirmParams); console.log('[useJoinGame] Step 3 done. Backend confirmed.'); const result: JoinGameMutationResult = { gameId: params.gameId, gameAddress: joinResult.gameAddress, signature, explorerUrl: confirmResult.explorerUrl, }; setData(result); setStatus('success'); console.log('[useJoinGame] Complete!'); // Sponsored join just consumed a credit server-side — broadcast so // every mounted useCredits instance (rewards widget, streak sheet, // join sheet) refetches and the count drops in real time. if (joinResult.promoCode) emitCreditsChanged(); return result; } catch (err) { console.error('[useJoinGame] FAILED at status:', status, err); const error = err instanceof Error ? err : new Error(String(err)); setError(error); setStatus('error'); throw error; } }, [client, wallet]); return { execute, status, error, data, reset }; }