@dubsdotapp/expo 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -510,6 +510,81 @@ var DubsClient = class {
510
510
  getErrorCodesLocal() {
511
511
  return { ...SOLANA_PROGRAM_ERRORS };
512
512
  }
513
+ // ── Arcade Pools ──
514
+ async getArcadePools(params) {
515
+ const qs = new URLSearchParams();
516
+ if (params?.gameSlug) qs.set("gameSlug", params.gameSlug);
517
+ if (params?.status) qs.set("status", params.status);
518
+ const query = qs.toString();
519
+ const res = await this.request(
520
+ "GET",
521
+ `/arcade/pools${query ? `?${query}` : ""}`
522
+ );
523
+ return res.pools;
524
+ }
525
+ async getArcadePool(poolId) {
526
+ const res = await this.request(
527
+ "GET",
528
+ `/arcade/pools/${poolId}`
529
+ );
530
+ return { pool: res.pool, stats: res.stats };
531
+ }
532
+ /** Build unsigned entry transaction for an arcade pool */
533
+ async buildArcadeEntry(poolId, walletAddress) {
534
+ const res = await this.request(
535
+ "POST",
536
+ `/arcade/pools/${poolId}/build-enter`,
537
+ { walletAddress }
538
+ );
539
+ return {
540
+ transaction: res.transaction,
541
+ poolId: res.poolId,
542
+ amount: res.amount,
543
+ destination: res.destination
544
+ };
545
+ }
546
+ async enterArcadePool(poolId, params) {
547
+ const res = await this.request(
548
+ "POST",
549
+ `/arcade/pools/${poolId}/enter`,
550
+ params
551
+ );
552
+ return res.entry;
553
+ }
554
+ async startArcadeAttempt(poolId, walletAddress) {
555
+ const res = await this.request(
556
+ "POST",
557
+ `/arcade/pools/${poolId}/start-attempt`,
558
+ { walletAddress }
559
+ );
560
+ return { sessionToken: res.sessionToken, attemptNumber: res.attemptNumber, livesRemaining: res.livesRemaining };
561
+ }
562
+ async submitArcadeScore(poolId, params) {
563
+ const res = await this.request(
564
+ "POST",
565
+ `/arcade/pools/${poolId}/submit-score`,
566
+ params
567
+ );
568
+ return { score: res.score, bestScore: res.bestScore, livesUsed: res.livesUsed, isNewBest: res.isNewBest };
569
+ }
570
+ async getArcadeLeaderboard(poolId, params) {
571
+ const qs = new URLSearchParams();
572
+ if (params?.limit != null) qs.set("limit", String(params.limit));
573
+ if (params?.offset != null) qs.set("offset", String(params.offset));
574
+ const query = qs.toString();
575
+ const res = await this.request(
576
+ "GET",
577
+ `/arcade/pools/${poolId}/leaderboard${query ? `?${query}` : ""}`
578
+ );
579
+ return res.leaderboard;
580
+ }
581
+ async getArcadeEntry(poolId, walletAddress) {
582
+ const res = await this.request(
583
+ "GET",
584
+ `/arcade/pools/${poolId}/my-entry?walletAddress=${encodeURIComponent(walletAddress)}`
585
+ );
586
+ return res.entry;
587
+ }
513
588
  // ── App Config ──
514
589
  /** Fetch the app's UI customization config (accent color, icon, tagline, environment) */
515
590
  async getAppConfig() {
@@ -561,7 +636,7 @@ function createSecureStoreStorage() {
561
636
  }
562
637
 
563
638
  // src/provider.tsx
564
- import { createContext as createContext4, useContext as useContext4, useMemo as useMemo2, useCallback as useCallback15, useState as useState16, useEffect as useEffect11 } from "react";
639
+ import { createContext as createContext4, useContext as useContext4, useMemo as useMemo3, useCallback as useCallback19, useState as useState20, useEffect as useEffect13 } from "react";
565
640
 
566
641
  // src/ui/theme.ts
567
642
  import { createContext, useContext } from "react";
@@ -1626,7 +1701,7 @@ function ManagedWalletProvider({
1626
1701
  }
1627
1702
 
1628
1703
  // src/ui/AuthGate.tsx
1629
- import React2, { useState as useState15, useEffect as useEffect10, useRef as useRef4, useCallback as useCallback14 } from "react";
1704
+ import React2, { useState as useState19, useEffect as useEffect12, useRef as useRef4, useCallback as useCallback18 } from "react";
1630
1705
  import {
1631
1706
  View as View3,
1632
1707
  Text as Text3,
@@ -2471,6 +2546,196 @@ function usePushNotifications() {
2471
2546
  };
2472
2547
  }
2473
2548
 
2549
+ // src/hooks/useArcadePools.ts
2550
+ import { useState as useState15, useEffect as useEffect10, useCallback as useCallback14 } from "react";
2551
+ function useArcadePools(gameSlug) {
2552
+ const { client } = useDubs();
2553
+ const [pools, setPools] = useState15([]);
2554
+ const [loading, setLoading] = useState15(false);
2555
+ const [error, setError] = useState15(null);
2556
+ const fetch2 = useCallback14(async () => {
2557
+ setLoading(true);
2558
+ setError(null);
2559
+ try {
2560
+ const result = await client.getArcadePools({ gameSlug });
2561
+ setPools(result);
2562
+ } catch (err) {
2563
+ setError(err instanceof Error ? err : new Error(String(err)));
2564
+ } finally {
2565
+ setLoading(false);
2566
+ }
2567
+ }, [client, gameSlug]);
2568
+ useEffect10(() => {
2569
+ fetch2();
2570
+ }, [fetch2]);
2571
+ return { pools, loading, error, refetch: fetch2 };
2572
+ }
2573
+
2574
+ // src/hooks/useArcadePool.ts
2575
+ import { useState as useState16, useEffect as useEffect11, useCallback as useCallback15 } from "react";
2576
+ function useArcadePool(poolId) {
2577
+ const { client } = useDubs();
2578
+ const [pool, setPool] = useState16(null);
2579
+ const [stats, setStats] = useState16(null);
2580
+ const [leaderboard, setLeaderboard] = useState16([]);
2581
+ const [loading, setLoading] = useState16(false);
2582
+ const [error, setError] = useState16(null);
2583
+ const fetch2 = useCallback15(async () => {
2584
+ if (!poolId) return;
2585
+ setLoading(true);
2586
+ setError(null);
2587
+ try {
2588
+ const [poolRes, lb] = await Promise.all([
2589
+ client.getArcadePool(poolId),
2590
+ client.getArcadeLeaderboard(poolId)
2591
+ ]);
2592
+ setPool(poolRes.pool);
2593
+ setStats(poolRes.stats);
2594
+ setLeaderboard(lb);
2595
+ } catch (err) {
2596
+ setError(err instanceof Error ? err : new Error(String(err)));
2597
+ } finally {
2598
+ setLoading(false);
2599
+ }
2600
+ }, [client, poolId]);
2601
+ useEffect11(() => {
2602
+ fetch2();
2603
+ }, [fetch2]);
2604
+ return { pool, stats, leaderboard, loading, error, refetch: fetch2 };
2605
+ }
2606
+
2607
+ // src/hooks/useArcadeGame.ts
2608
+ import { useState as useState17, useCallback as useCallback16 } from "react";
2609
+ function useArcadeGame(poolId, maxLives = 3) {
2610
+ const { client } = useDubs();
2611
+ const { user } = useAuth();
2612
+ const [entry, setEntry] = useState17(null);
2613
+ const [loading, setLoading] = useState17(false);
2614
+ const [error, setError] = useState17(null);
2615
+ const walletAddress = user?.walletAddress || "";
2616
+ const refreshEntry = useCallback16(async () => {
2617
+ if (!poolId || !walletAddress) return;
2618
+ setLoading(true);
2619
+ setError(null);
2620
+ try {
2621
+ const e = await client.getArcadeEntry(poolId, walletAddress);
2622
+ setEntry(e);
2623
+ } catch (err) {
2624
+ if (err instanceof Error && err.message.includes("No entry found")) {
2625
+ setEntry(null);
2626
+ } else {
2627
+ setError(err instanceof Error ? err : new Error(String(err)));
2628
+ }
2629
+ } finally {
2630
+ setLoading(false);
2631
+ }
2632
+ }, [client, poolId, walletAddress]);
2633
+ const startAttempt = useCallback16(async () => {
2634
+ if (!poolId || !walletAddress) throw new Error("Not ready");
2635
+ setError(null);
2636
+ try {
2637
+ const result = await client.startArcadeAttempt(poolId, walletAddress);
2638
+ return result;
2639
+ } catch (err) {
2640
+ const e = err instanceof Error ? err : new Error(String(err));
2641
+ setError(e);
2642
+ throw e;
2643
+ }
2644
+ }, [client, poolId, walletAddress]);
2645
+ const submitScore = useCallback16(async (sessionToken, score, durationMs) => {
2646
+ if (!poolId || !walletAddress) throw new Error("Not ready");
2647
+ setError(null);
2648
+ try {
2649
+ const result = await client.submitArcadeScore(poolId, {
2650
+ walletAddress,
2651
+ sessionToken,
2652
+ score,
2653
+ durationMs
2654
+ });
2655
+ setEntry((prev) => prev ? {
2656
+ ...prev,
2657
+ best_score: result.bestScore,
2658
+ lives_used: result.livesUsed
2659
+ } : prev);
2660
+ return result;
2661
+ } catch (err) {
2662
+ const e = err instanceof Error ? err : new Error(String(err));
2663
+ setError(e);
2664
+ throw e;
2665
+ }
2666
+ }, [client, poolId, walletAddress]);
2667
+ const livesRemaining = entry ? maxLives - entry.lives_used : maxLives;
2668
+ const bestScore = entry?.best_score || 0;
2669
+ return {
2670
+ entry,
2671
+ livesRemaining,
2672
+ bestScore,
2673
+ loading,
2674
+ error,
2675
+ refreshEntry,
2676
+ startAttempt,
2677
+ submitScore
2678
+ };
2679
+ }
2680
+
2681
+ // src/hooks/useEnterArcadePool.ts
2682
+ import { useState as useState18, useCallback as useCallback17 } from "react";
2683
+ function useEnterArcadePool() {
2684
+ const { client, wallet, connection } = useDubs();
2685
+ const { user } = useAuth();
2686
+ const [status, setStatus] = useState18("idle");
2687
+ const [error, setError] = useState18(null);
2688
+ const [data, setData] = useState18(null);
2689
+ const reset = useCallback17(() => {
2690
+ setStatus("idle");
2691
+ setError(null);
2692
+ setData(null);
2693
+ }, []);
2694
+ const execute = useCallback17(async (poolId) => {
2695
+ if (!wallet.publicKey) throw new Error("Wallet not connected");
2696
+ const walletAddress = wallet.publicKey.toBase58();
2697
+ setStatus("building");
2698
+ setError(null);
2699
+ setData(null);
2700
+ try {
2701
+ console.log("[useEnterArcadePool] Step 1: Building transaction...", { poolId, walletAddress });
2702
+ const buildResult = await client.buildArcadeEntry(poolId, walletAddress);
2703
+ console.log("[useEnterArcadePool] Step 1 done:", { poolId: buildResult.poolId, amount: buildResult.amount });
2704
+ setStatus("signing");
2705
+ console.log("[useEnterArcadePool] Step 2: Signing and sending...");
2706
+ const signature = await signAndSendBase64Transaction(
2707
+ buildResult.transaction,
2708
+ wallet,
2709
+ connection
2710
+ );
2711
+ console.log("[useEnterArcadePool] Step 2 done. Signature:", signature);
2712
+ setStatus("confirming");
2713
+ console.log("[useEnterArcadePool] Step 3: Confirming with backend...");
2714
+ const entry = await client.enterArcadePool(poolId, {
2715
+ walletAddress,
2716
+ txSignature: signature
2717
+ });
2718
+ console.log("[useEnterArcadePool] Step 3 done. Entry recorded.");
2719
+ const result = {
2720
+ poolId,
2721
+ signature,
2722
+ entry
2723
+ };
2724
+ setData(result);
2725
+ setStatus("success");
2726
+ console.log("[useEnterArcadePool] Complete!");
2727
+ return result;
2728
+ } catch (err) {
2729
+ console.error("[useEnterArcadePool] FAILED at status:", status, err);
2730
+ const e = err instanceof Error ? err : new Error(String(err));
2731
+ setError(e);
2732
+ setStatus("error");
2733
+ throw e;
2734
+ }
2735
+ }, [client, wallet, connection]);
2736
+ return { execute, status, error, data, reset };
2737
+ }
2738
+
2474
2739
  // src/ui/AvatarEditor.tsx
2475
2740
  import {
2476
2741
  View as View2,
@@ -2638,11 +2903,11 @@ function AuthGate({
2638
2903
  }) {
2639
2904
  const { client, pushEnabled } = useDubs();
2640
2905
  const auth = useAuth();
2641
- const [phase, setPhase] = useState15("init");
2642
- const [registrationPhase, setRegistrationPhase] = useState15(false);
2643
- const [showPushSetup, setShowPushSetup] = useState15(false);
2644
- const [isRestoredSession, setIsRestoredSession] = useState15(false);
2645
- useEffect10(() => {
2906
+ const [phase, setPhase] = useState19("init");
2907
+ const [registrationPhase, setRegistrationPhase] = useState19(false);
2908
+ const [showPushSetup, setShowPushSetup] = useState19(false);
2909
+ const [isRestoredSession, setIsRestoredSession] = useState19(false);
2910
+ useEffect12(() => {
2646
2911
  let cancelled = false;
2647
2912
  (async () => {
2648
2913
  try {
@@ -2669,23 +2934,23 @@ function AuthGate({
2669
2934
  cancelled = true;
2670
2935
  };
2671
2936
  }, []);
2672
- useEffect10(() => {
2937
+ useEffect12(() => {
2673
2938
  if (auth.status === "needsRegistration") setRegistrationPhase(true);
2674
2939
  }, [auth.status]);
2675
- useEffect10(() => {
2940
+ useEffect12(() => {
2676
2941
  if (pushEnabled && auth.status === "authenticated" && registrationPhase && !isRestoredSession) {
2677
2942
  setShowPushSetup(true);
2678
2943
  }
2679
2944
  }, [pushEnabled, auth.status, registrationPhase, isRestoredSession]);
2680
- useEffect10(() => {
2945
+ useEffect12(() => {
2681
2946
  if (auth.token) onSaveToken(auth.token);
2682
2947
  }, [auth.token]);
2683
- const retry = useCallback14(() => {
2948
+ const retry = useCallback18(() => {
2684
2949
  setRegistrationPhase(false);
2685
2950
  auth.reset();
2686
2951
  auth.authenticate();
2687
2952
  }, [auth]);
2688
- const handleRegister = useCallback14(
2953
+ const handleRegister = useCallback18(
2689
2954
  (username, referralCode, avatarUrl) => {
2690
2955
  auth.register(username, referralCode, avatarUrl);
2691
2956
  },
@@ -2801,20 +3066,20 @@ function DefaultRegistrationScreen({
2801
3066
  }) {
2802
3067
  const t = useDubsTheme();
2803
3068
  const accent = accentColor || t.accent;
2804
- const [step, setStep] = useState15(0);
2805
- const [avatarSeed, setAvatarSeed] = useState15(generateSeed);
2806
- const [avatarStyle, setAvatarStyle] = useState15("adventurer");
2807
- const [avatarBg, setAvatarBg] = useState15("1a1a2e");
2808
- const [showStyles, setShowStyles] = useState15(false);
2809
- const [username, setUsername] = useState15("");
2810
- const [referralCode, setReferralCode] = useState15("");
2811
- const [checking, setChecking] = useState15(false);
2812
- const [availability, setAvailability] = useState15(null);
3069
+ const [step, setStep] = useState19(0);
3070
+ const [avatarSeed, setAvatarSeed] = useState19(generateSeed);
3071
+ const [avatarStyle, setAvatarStyle] = useState19("adventurer");
3072
+ const [avatarBg, setAvatarBg] = useState19("1a1a2e");
3073
+ const [showStyles, setShowStyles] = useState19(false);
3074
+ const [username, setUsername] = useState19("");
3075
+ const [referralCode, setReferralCode] = useState19("");
3076
+ const [checking, setChecking] = useState19(false);
3077
+ const [availability, setAvailability] = useState19(null);
2813
3078
  const debounceRef = useRef4(null);
2814
3079
  const fadeAnim = useRef4(new Animated.Value(1)).current;
2815
3080
  const slideAnim = useRef4(new Animated.Value(0)).current;
2816
3081
  const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed, avatarBg);
2817
- useEffect10(() => {
3082
+ useEffect12(() => {
2818
3083
  if (debounceRef.current) clearTimeout(debounceRef.current);
2819
3084
  const trimmed = username.trim();
2820
3085
  if (trimmed.length < 3) {
@@ -2837,7 +3102,7 @@ function DefaultRegistrationScreen({
2837
3102
  if (debounceRef.current) clearTimeout(debounceRef.current);
2838
3103
  };
2839
3104
  }, [username, client]);
2840
- const animateToStep = useCallback14((newStep) => {
3105
+ const animateToStep = useCallback18((newStep) => {
2841
3106
  const dir = newStep > step ? 1 : -1;
2842
3107
  Keyboard.dismiss();
2843
3108
  Animated.parallel([
@@ -3077,7 +3342,7 @@ function DefaultRegistrationScreen({
3077
3342
  function PushTokenRestorer() {
3078
3343
  const push = usePushNotifications();
3079
3344
  const restored = useRef4(false);
3080
- useEffect10(() => {
3345
+ useEffect12(() => {
3081
3346
  if (restored.current) return;
3082
3347
  restored.current = true;
3083
3348
  push.restoreIfGranted();
@@ -3094,7 +3359,7 @@ function PushSetupScreen({
3094
3359
  const push = usePushNotifications();
3095
3360
  const fadeAnim = useRef4(new Animated.Value(0)).current;
3096
3361
  const slideAnim = useRef4(new Animated.Value(30)).current;
3097
- useEffect10(() => {
3362
+ useEffect12(() => {
3098
3363
  Animated.parallel([
3099
3364
  Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true }),
3100
3365
  Animated.timing(slideAnim, { toValue: 0, duration: 300, useNativeDriver: true })
@@ -3252,11 +3517,11 @@ function DubsProvider({
3252
3517
  const config = NETWORK_CONFIG[network];
3253
3518
  const baseUrl = baseUrlOverride || config.baseUrl;
3254
3519
  const rpcUrl = rpcUrlOverride || config.rpcUrl;
3255
- const client = useMemo2(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
3256
- const storage = useMemo2(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
3257
- const [uiConfig, setUiConfig] = useState16(null);
3258
- const [resolvedNetwork, setResolvedNetwork] = useState16(network);
3259
- useEffect11(() => {
3520
+ const client = useMemo3(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
3521
+ const storage = useMemo3(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
3522
+ const [uiConfig, setUiConfig] = useState20(null);
3523
+ const [resolvedNetwork, setResolvedNetwork] = useState20(network);
3524
+ useEffect13(() => {
3260
3525
  client.getAppConfig().then((cfg) => {
3261
3526
  console.log("[DubsProvider] UI config loaded:", JSON.stringify(cfg));
3262
3527
  setUiConfig(cfg);
@@ -3272,7 +3537,7 @@ function DubsProvider({
3272
3537
  const resolvedConfig = NETWORK_CONFIG[resolvedNetwork];
3273
3538
  const resolvedRpcUrl = rpcUrlOverride || resolvedConfig.rpcUrl;
3274
3539
  const cluster = resolvedConfig.cluster;
3275
- const connection = useMemo2(() => new Connection2(resolvedRpcUrl, { commitment: "confirmed" }), [resolvedRpcUrl]);
3540
+ const connection = useMemo3(() => new Connection2(resolvedRpcUrl, { commitment: "confirmed" }), [resolvedRpcUrl]);
3276
3541
  if (uiConfig === null) return null;
3277
3542
  const themeOverrides = {};
3278
3543
  if (uiConfig.accentColor) {
@@ -3348,11 +3613,11 @@ function ManagedInner({
3348
3613
  children
3349
3614
  }) {
3350
3615
  const managedDisconnect = useDisconnect();
3351
- const disconnect = useCallback15(async () => {
3616
+ const disconnect = useCallback19(async () => {
3352
3617
  client.setToken(null);
3353
3618
  await managedDisconnect?.();
3354
3619
  }, [client, managedDisconnect]);
3355
- const value = useMemo2(
3620
+ const value = useMemo3(
3356
3621
  () => ({ client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled }),
3357
3622
  [client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled]
3358
3623
  );
@@ -3389,13 +3654,13 @@ function ExternalWalletProvider({
3389
3654
  pushEnabled,
3390
3655
  children
3391
3656
  }) {
3392
- const disconnect = useCallback15(async () => {
3657
+ const disconnect = useCallback19(async () => {
3393
3658
  client.setToken(null);
3394
3659
  await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
3395
3660
  });
3396
3661
  await wallet.disconnect?.();
3397
3662
  }, [client, storage, wallet]);
3398
- const value = useMemo2(
3663
+ const value = useMemo3(
3399
3664
  () => ({ client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled }),
3400
3665
  [client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled]
3401
3666
  );
@@ -3432,7 +3697,7 @@ function useAppConfig() {
3432
3697
  }
3433
3698
 
3434
3699
  // src/ui/UserProfileCard.tsx
3435
- import { useMemo as useMemo3 } from "react";
3700
+ import { useMemo as useMemo4 } from "react";
3436
3701
  import { View as View4, Text as Text4, Image as Image4, StyleSheet as StyleSheet4 } from "react-native";
3437
3702
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
3438
3703
  function truncateAddress(address, chars = 4) {
@@ -3452,7 +3717,7 @@ function UserProfileCard({
3452
3717
  memberSince
3453
3718
  }) {
3454
3719
  const t = useDubsTheme();
3455
- const imageUri = useMemo3(
3720
+ const imageUri = useMemo4(
3456
3721
  () => ensurePngAvatar(avatarUrl) || `https://api.dicebear.com/9.x/avataaars/png?seed=${walletAddress}&size=128`,
3457
3722
  [avatarUrl, walletAddress]
3458
3723
  );
@@ -3652,7 +3917,7 @@ var styles4 = StyleSheet5.create({
3652
3917
  });
3653
3918
 
3654
3919
  // src/ui/UserProfileSheet.tsx
3655
- import { useState as useState17, useEffect as useEffect12, useRef as useRef5, useCallback as useCallback16, useMemo as useMemo4 } from "react";
3920
+ import { useState as useState21, useEffect as useEffect14, useRef as useRef5, useCallback as useCallback20, useMemo as useMemo5 } from "react";
3656
3921
  import {
3657
3922
  View as View6,
3658
3923
  Text as Text6,
@@ -3684,30 +3949,30 @@ function UserProfileSheet({
3684
3949
  const { refreshUser } = useAuth();
3685
3950
  const push = usePushNotifications();
3686
3951
  const overlayOpacity = useRef5(new Animated2.Value(0)).current;
3687
- const parsed = useMemo4(() => parseAvatarUrl(user.avatar), [user.avatar]);
3688
- const [avatarStyle, setAvatarStyle] = useState17(parsed.style);
3689
- const [avatarSeed, setAvatarSeed] = useState17(parsed.seed);
3690
- const [bgColor, setBgColor] = useState17(parsed.bg);
3691
- const [saving, setSaving] = useState17(false);
3692
- const [error, setError] = useState17(null);
3693
- useEffect12(() => {
3952
+ const parsed = useMemo5(() => parseAvatarUrl(user.avatar), [user.avatar]);
3953
+ const [avatarStyle, setAvatarStyle] = useState21(parsed.style);
3954
+ const [avatarSeed, setAvatarSeed] = useState21(parsed.seed);
3955
+ const [bgColor, setBgColor] = useState21(parsed.bg);
3956
+ const [saving, setSaving] = useState21(false);
3957
+ const [error, setError] = useState21(null);
3958
+ useEffect14(() => {
3694
3959
  const p = parseAvatarUrl(user.avatar);
3695
3960
  setAvatarStyle(p.style);
3696
3961
  setAvatarSeed(p.seed);
3697
3962
  setBgColor(p.bg);
3698
3963
  }, [user.avatar]);
3699
- useEffect12(() => {
3964
+ useEffect14(() => {
3700
3965
  Animated2.timing(overlayOpacity, {
3701
3966
  toValue: visible ? 1 : 0,
3702
3967
  duration: 250,
3703
3968
  useNativeDriver: true
3704
3969
  }).start();
3705
3970
  }, [visible, overlayOpacity]);
3706
- useEffect12(() => {
3971
+ useEffect14(() => {
3707
3972
  if (visible) setError(null);
3708
3973
  }, [visible]);
3709
3974
  const currentAvatarUrl = getAvatarUrl(avatarStyle, avatarSeed, bgColor);
3710
- const saveAvatar = useCallback16(async (newUrl) => {
3975
+ const saveAvatar = useCallback20(async (newUrl) => {
3711
3976
  setSaving(true);
3712
3977
  setError(null);
3713
3978
  try {
@@ -3720,16 +3985,16 @@ function UserProfileSheet({
3720
3985
  setSaving(false);
3721
3986
  }
3722
3987
  }, [client, refreshUser, onAvatarUpdated]);
3723
- const handleStyleChange = useCallback16((style) => {
3988
+ const handleStyleChange = useCallback20((style) => {
3724
3989
  setAvatarStyle(style);
3725
3990
  saveAvatar(getAvatarUrl(style, avatarSeed, bgColor));
3726
3991
  }, [avatarSeed, bgColor, saveAvatar]);
3727
- const handleShuffle = useCallback16(() => {
3992
+ const handleShuffle = useCallback20(() => {
3728
3993
  const newSeed = generateSeed();
3729
3994
  setAvatarSeed(newSeed);
3730
3995
  saveAvatar(getAvatarUrl(avatarStyle, newSeed, bgColor));
3731
3996
  }, [avatarStyle, bgColor, saveAvatar]);
3732
- const handleBgChange = useCallback16((color) => {
3997
+ const handleBgChange = useCallback20((color) => {
3733
3998
  setBgColor(color);
3734
3999
  saveAvatar(getAvatarUrl(avatarStyle, avatarSeed, color));
3735
4000
  }, [avatarStyle, avatarSeed, saveAvatar]);
@@ -4009,7 +4274,7 @@ var styles5 = StyleSheet6.create({
4009
4274
  });
4010
4275
 
4011
4276
  // src/ui/game/GamePoster.tsx
4012
- import { useState as useState18 } from "react";
4277
+ import { useState as useState22 } from "react";
4013
4278
  import { StyleSheet as StyleSheet7, View as View7, Text as Text7 } from "react-native";
4014
4279
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
4015
4280
  function computeCountdown(lockTimestamp) {
@@ -4059,7 +4324,7 @@ function GamePoster({ game, ImageComponent }) {
4059
4324
  ] });
4060
4325
  }
4061
4326
  function TeamLogoInternal({ url, size, Img }) {
4062
- const [failed, setFailed] = useState18(false);
4327
+ const [failed, setFailed] = useState22(false);
4063
4328
  if (!url || failed) {
4064
4329
  return /* @__PURE__ */ jsx9(View7, { style: [styles6.logoPlaceholder, { width: size, height: size, borderRadius: size / 2 }] });
4065
4330
  }
@@ -4160,7 +4425,7 @@ var styles6 = StyleSheet7.create({
4160
4425
  });
4161
4426
 
4162
4427
  // src/ui/game/LivePoolsCard.tsx
4163
- import { useMemo as useMemo5 } from "react";
4428
+ import { useMemo as useMemo6 } from "react";
4164
4429
  import { StyleSheet as StyleSheet8, View as View8, Text as Text8 } from "react-native";
4165
4430
  import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
4166
4431
  function LivePoolsCard({
@@ -4176,7 +4441,7 @@ function LivePoolsCard({
4176
4441
  const homePool = game.homePool || 0;
4177
4442
  const awayPool = game.awayPool || 0;
4178
4443
  const totalPool = game.totalPool || 0;
4179
- const { homePercent, awayPercent, homeOdds, awayOdds } = useMemo5(() => {
4444
+ const { homePercent, awayPercent, homeOdds, awayOdds } = useMemo6(() => {
4180
4445
  return {
4181
4446
  homePercent: totalPool > 0 ? homePool / totalPool * 100 : 50,
4182
4447
  awayPercent: totalPool > 0 ? awayPool / totalPool * 100 : 50,
@@ -4239,7 +4504,7 @@ var styles7 = StyleSheet8.create({
4239
4504
  });
4240
4505
 
4241
4506
  // src/ui/game/PickWinnerCard.tsx
4242
- import { useState as useState19, useMemo as useMemo6 } from "react";
4507
+ import { useState as useState23, useMemo as useMemo7 } from "react";
4243
4508
  import { StyleSheet as StyleSheet9, View as View9, Text as Text9, TouchableOpacity as TouchableOpacity6 } from "react-native";
4244
4509
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
4245
4510
  function PickWinnerCard({
@@ -4257,7 +4522,7 @@ function PickWinnerCard({
4257
4522
  const totalPool = game.totalPool || 0;
4258
4523
  const homePool = game.homePool || 0;
4259
4524
  const awayPool = game.awayPool || 0;
4260
- const { homeOdds, awayOdds, homeBets, awayBets } = useMemo6(() => ({
4525
+ const { homeOdds, awayOdds, homeBets, awayBets } = useMemo7(() => ({
4261
4526
  homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
4262
4527
  awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014",
4263
4528
  homeBets: bettors.filter((b) => b.team === "home").length,
@@ -4310,7 +4575,7 @@ function TeamOption({
4310
4575
  ImageComponent,
4311
4576
  t
4312
4577
  }) {
4313
- const [imgFailed, setImgFailed] = useState19(false);
4578
+ const [imgFailed, setImgFailed] = useState23(false);
4314
4579
  const Img = ImageComponent || __require("react-native").Image;
4315
4580
  const showImage = imageUrl && !imgFailed;
4316
4581
  return /* @__PURE__ */ jsxs9(
@@ -4351,7 +4616,7 @@ var styles8 = StyleSheet9.create({
4351
4616
  });
4352
4617
 
4353
4618
  // src/ui/game/PlayersCard.tsx
4354
- import { useState as useState20 } from "react";
4619
+ import { useState as useState24 } from "react";
4355
4620
  import { StyleSheet as StyleSheet10, View as View10, Text as Text10 } from "react-native";
4356
4621
  import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
4357
4622
  function truncateWallet(addr, chars) {
@@ -4400,7 +4665,7 @@ function BettorRow({
4400
4665
  ImageComponent,
4401
4666
  t
4402
4667
  }) {
4403
- const [imgFailed, setImgFailed] = useState20(false);
4668
+ const [imgFailed, setImgFailed] = useState24(false);
4404
4669
  const Img = ImageComponent || __require("react-native").Image;
4405
4670
  const showAvatar = bettor.avatar && !imgFailed;
4406
4671
  return /* @__PURE__ */ jsxs10(View10, { style: [styles9.row, !isFirst && { borderTopColor: t.border, borderTopWidth: 1 }], children: [
@@ -4427,7 +4692,7 @@ var styles9 = StyleSheet10.create({
4427
4692
  });
4428
4693
 
4429
4694
  // src/ui/game/JoinGameButton.tsx
4430
- import { useMemo as useMemo7 } from "react";
4695
+ import { useMemo as useMemo8 } from "react";
4431
4696
  import { StyleSheet as StyleSheet11, View as View11, Text as Text11, TouchableOpacity as TouchableOpacity7, ActivityIndicator as ActivityIndicator5 } from "react-native";
4432
4697
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
4433
4698
  var STATUS_LABELS = {
@@ -4438,7 +4703,7 @@ var STATUS_LABELS = {
4438
4703
  };
4439
4704
  function JoinGameButton({ game, walletAddress, selectedTeam, status, onJoin }) {
4440
4705
  const t = useDubsTheme();
4441
- const alreadyJoined = useMemo7(() => {
4706
+ const alreadyJoined = useMemo8(() => {
4442
4707
  if (!walletAddress) return false;
4443
4708
  return (game.bettors || []).some((b) => b.wallet === walletAddress);
4444
4709
  }, [game.bettors, walletAddress]);
@@ -4479,7 +4744,7 @@ var styles10 = StyleSheet11.create({
4479
4744
  });
4480
4745
 
4481
4746
  // src/ui/game/CreateCustomGameSheet.tsx
4482
- import { useState as useState21, useEffect as useEffect13, useRef as useRef6, useCallback as useCallback17 } from "react";
4747
+ import { useState as useState25, useEffect as useEffect15, useRef as useRef6, useCallback as useCallback21 } from "react";
4483
4748
  import {
4484
4749
  View as View12,
4485
4750
  Text as Text12,
@@ -4516,18 +4781,18 @@ function CreateCustomGameSheet({
4516
4781
  const t = useDubsTheme();
4517
4782
  const { wallet } = useDubs();
4518
4783
  const mutation = useCreateCustomGame();
4519
- const [selectedAmount, setSelectedAmount] = useState21(null);
4520
- const [customAmount, setCustomAmount] = useState21("");
4521
- const [isCustom, setIsCustom] = useState21(false);
4784
+ const [selectedAmount, setSelectedAmount] = useState25(null);
4785
+ const [customAmount, setCustomAmount] = useState25("");
4786
+ const [isCustom, setIsCustom] = useState25(false);
4522
4787
  const overlayOpacity = useRef6(new Animated3.Value(0)).current;
4523
- useEffect13(() => {
4788
+ useEffect15(() => {
4524
4789
  Animated3.timing(overlayOpacity, {
4525
4790
  toValue: visible ? 1 : 0,
4526
4791
  duration: 250,
4527
4792
  useNativeDriver: true
4528
4793
  }).start();
4529
4794
  }, [visible, overlayOpacity]);
4530
- useEffect13(() => {
4795
+ useEffect15(() => {
4531
4796
  if (visible) {
4532
4797
  setSelectedAmount(defaultAmount ?? null);
4533
4798
  setCustomAmount("");
@@ -4535,7 +4800,7 @@ function CreateCustomGameSheet({
4535
4800
  mutation.reset();
4536
4801
  }
4537
4802
  }, [visible]);
4538
- useEffect13(() => {
4803
+ useEffect15(() => {
4539
4804
  if (mutation.status === "success" && mutation.data) {
4540
4805
  onSuccess?.(mutation.data);
4541
4806
  const timer = setTimeout(() => {
@@ -4544,23 +4809,23 @@ function CreateCustomGameSheet({
4544
4809
  return () => clearTimeout(timer);
4545
4810
  }
4546
4811
  }, [mutation.status, mutation.data]);
4547
- useEffect13(() => {
4812
+ useEffect15(() => {
4548
4813
  if (mutation.status === "error" && mutation.error) {
4549
4814
  onError?.(mutation.error);
4550
4815
  }
4551
4816
  }, [mutation.status, mutation.error]);
4552
- const handlePresetSelect = useCallback17((amount) => {
4817
+ const handlePresetSelect = useCallback21((amount) => {
4553
4818
  setSelectedAmount(amount);
4554
4819
  setIsCustom(false);
4555
4820
  setCustomAmount("");
4556
4821
  onAmountChange?.(amount);
4557
4822
  }, [onAmountChange]);
4558
- const handleCustomSelect = useCallback17(() => {
4823
+ const handleCustomSelect = useCallback21(() => {
4559
4824
  setIsCustom(true);
4560
4825
  setSelectedAmount(null);
4561
4826
  onAmountChange?.(null);
4562
4827
  }, [onAmountChange]);
4563
- const handleCustomAmountChange = useCallback17((text) => {
4828
+ const handleCustomAmountChange = useCallback21((text) => {
4564
4829
  const cleaned = text.replace(/[^0-9.]/g, "").replace(/(\..*?)\..*/g, "$1");
4565
4830
  setCustomAmount(cleaned);
4566
4831
  const parsed = parseFloat(cleaned);
@@ -4575,7 +4840,7 @@ function CreateCustomGameSheet({
4575
4840
  const winnerTakes = pot * (1 - fee / 100);
4576
4841
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
4577
4842
  const canCreate = finalAmount !== null && finalAmount > 0 && !isMutating && mutation.status !== "success";
4578
- const handleCreate = useCallback17(async () => {
4843
+ const handleCreate = useCallback21(async () => {
4579
4844
  if (!finalAmount || !wallet.publicKey) return;
4580
4845
  try {
4581
4846
  await mutation.execute({
@@ -4844,7 +5109,7 @@ var styles11 = StyleSheet12.create({
4844
5109
  });
4845
5110
 
4846
5111
  // src/ui/game/JoinGameSheet.tsx
4847
- import { useState as useState22, useEffect as useEffect14, useRef as useRef7, useCallback as useCallback18, useMemo as useMemo8 } from "react";
5112
+ import { useState as useState26, useEffect as useEffect16, useRef as useRef7, useCallback as useCallback22, useMemo as useMemo9 } from "react";
4848
5113
  import {
4849
5114
  View as View13,
4850
5115
  Text as Text13,
@@ -4880,22 +5145,22 @@ function JoinGameSheet({
4880
5145
  const { wallet } = useDubs();
4881
5146
  const mutation = useJoinGame();
4882
5147
  const isCustomGame = game.gameMode === CUSTOM_GAME_MODE;
4883
- const [selectedTeam, setSelectedTeam] = useState22(null);
5148
+ const [selectedTeam, setSelectedTeam] = useState26(null);
4884
5149
  const overlayOpacity = useRef7(new Animated4.Value(0)).current;
4885
- useEffect14(() => {
5150
+ useEffect16(() => {
4886
5151
  Animated4.timing(overlayOpacity, {
4887
5152
  toValue: visible ? 1 : 0,
4888
5153
  duration: 250,
4889
5154
  useNativeDriver: true
4890
5155
  }).start();
4891
5156
  }, [visible, overlayOpacity]);
4892
- useEffect14(() => {
5157
+ useEffect16(() => {
4893
5158
  if (visible) {
4894
5159
  setSelectedTeam(isPoolModeEnabled ? "home" : isCustomGame ? "away" : null);
4895
5160
  mutation.reset();
4896
5161
  }
4897
5162
  }, [visible]);
4898
- useEffect14(() => {
5163
+ useEffect16(() => {
4899
5164
  if (mutation.status === "success" && mutation.data) {
4900
5165
  onSuccess?.(mutation.data);
4901
5166
  const timer = setTimeout(() => {
@@ -4904,7 +5169,7 @@ function JoinGameSheet({
4904
5169
  return () => clearTimeout(timer);
4905
5170
  }
4906
5171
  }, [mutation.status, mutation.data]);
4907
- useEffect14(() => {
5172
+ useEffect16(() => {
4908
5173
  if (mutation.status === "error" && mutation.error) {
4909
5174
  onError?.(mutation.error);
4910
5175
  }
@@ -4915,7 +5180,7 @@ function JoinGameSheet({
4915
5180
  const homePool = game.homePool || 0;
4916
5181
  const awayPool = game.awayPool || 0;
4917
5182
  const buyIn = game.buyIn;
4918
- const { homeOdds, awayOdds, homeBets, awayBets } = useMemo8(() => ({
5183
+ const { homeOdds, awayOdds, homeBets, awayBets } = useMemo9(() => ({
4919
5184
  homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
4920
5185
  awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014",
4921
5186
  homeBets: bettors.filter((b) => b.team === "home").length,
@@ -4927,14 +5192,14 @@ function JoinGameSheet({
4927
5192
  const homeName = shortName ? shortName(opponents[0]?.name) : opponents[0]?.name || "Home";
4928
5193
  const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
4929
5194
  const selectedName = selectedTeam === "home" ? homeName : selectedTeam === "away" ? awayName : "\u2014";
4930
- const alreadyJoined = useMemo8(() => {
5195
+ const alreadyJoined = useMemo9(() => {
4931
5196
  if (!wallet.publicKey) return false;
4932
5197
  const addr = wallet.publicKey.toBase58();
4933
5198
  return bettors.some((b) => b.wallet === addr);
4934
5199
  }, [bettors, wallet.publicKey]);
4935
5200
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
4936
5201
  const canJoin = selectedTeam !== null && !isMutating && mutation.status !== "success" && !alreadyJoined;
4937
- const handleJoin = useCallback18(async () => {
5202
+ const handleJoin = useCallback22(async () => {
4938
5203
  if (!selectedTeam || !wallet.publicKey) return;
4939
5204
  try {
4940
5205
  await mutation.execute({
@@ -5078,7 +5343,7 @@ function TeamButton({
5078
5343
  ImageComponent,
5079
5344
  t
5080
5345
  }) {
5081
- const [imgFailed, setImgFailed] = useState22(false);
5346
+ const [imgFailed, setImgFailed] = useState26(false);
5082
5347
  const Img = ImageComponent || __require("react-native").Image;
5083
5348
  const showImage = imageUrl && !imgFailed;
5084
5349
  return /* @__PURE__ */ jsxs13(
@@ -5255,7 +5520,7 @@ var styles12 = StyleSheet13.create({
5255
5520
  });
5256
5521
 
5257
5522
  // src/ui/game/ClaimPrizeSheet.tsx
5258
- import { useState as useState23, useEffect as useEffect15, useRef as useRef8, useCallback as useCallback19 } from "react";
5523
+ import { useState as useState27, useEffect as useEffect17, useRef as useRef8, useCallback as useCallback23 } from "react";
5259
5524
  import {
5260
5525
  View as View14,
5261
5526
  Text as Text14,
@@ -5289,15 +5554,15 @@ function ClaimPrizeSheet({
5289
5554
  const overlayOpacity = useRef8(new Animated5.Value(0)).current;
5290
5555
  const celebrationScale = useRef8(new Animated5.Value(0)).current;
5291
5556
  const celebrationOpacity = useRef8(new Animated5.Value(0)).current;
5292
- const [showCelebration, setShowCelebration] = useState23(false);
5293
- useEffect15(() => {
5557
+ const [showCelebration, setShowCelebration] = useState27(false);
5558
+ useEffect17(() => {
5294
5559
  Animated5.timing(overlayOpacity, {
5295
5560
  toValue: visible ? 1 : 0,
5296
5561
  duration: 250,
5297
5562
  useNativeDriver: true
5298
5563
  }).start();
5299
5564
  }, [visible, overlayOpacity]);
5300
- useEffect15(() => {
5565
+ useEffect17(() => {
5301
5566
  if (visible) {
5302
5567
  mutation.reset();
5303
5568
  setShowCelebration(false);
@@ -5305,7 +5570,7 @@ function ClaimPrizeSheet({
5305
5570
  celebrationOpacity.setValue(0);
5306
5571
  }
5307
5572
  }, [visible]);
5308
- useEffect15(() => {
5573
+ useEffect17(() => {
5309
5574
  if (mutation.status === "success" && mutation.data) {
5310
5575
  setShowCelebration(true);
5311
5576
  Animated5.parallel([
@@ -5328,14 +5593,14 @@ function ClaimPrizeSheet({
5328
5593
  return () => clearTimeout(timer);
5329
5594
  }
5330
5595
  }, [mutation.status, mutation.data]);
5331
- useEffect15(() => {
5596
+ useEffect17(() => {
5332
5597
  if (mutation.status === "error" && mutation.error) {
5333
5598
  onError?.(mutation.error);
5334
5599
  }
5335
5600
  }, [mutation.status, mutation.error]);
5336
5601
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
5337
5602
  const canClaim = !isMutating && mutation.status !== "success" && !!wallet.publicKey;
5338
- const handleClaim = useCallback19(async () => {
5603
+ const handleClaim = useCallback23(async () => {
5339
5604
  if (!wallet.publicKey) return;
5340
5605
  try {
5341
5606
  await mutation.execute({
@@ -5568,7 +5833,7 @@ var styles13 = StyleSheet14.create({
5568
5833
  });
5569
5834
 
5570
5835
  // src/ui/game/ClaimButton.tsx
5571
- import { useState as useState24, useMemo as useMemo9, useCallback as useCallback20 } from "react";
5836
+ import { useState as useState28, useMemo as useMemo10, useCallback as useCallback24 } from "react";
5572
5837
  import { StyleSheet as StyleSheet15, Text as Text15, TouchableOpacity as TouchableOpacity11 } from "react-native";
5573
5838
  import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
5574
5839
  function ClaimButton({ gameId, style, onSuccess, onError }) {
@@ -5576,9 +5841,9 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
5576
5841
  const { wallet } = useDubs();
5577
5842
  const game = useGame(gameId);
5578
5843
  const claimStatus = useHasClaimed(gameId);
5579
- const [sheetVisible, setSheetVisible] = useState24(false);
5844
+ const [sheetVisible, setSheetVisible] = useState28(false);
5580
5845
  const walletAddress = wallet.publicKey?.toBase58() ?? null;
5581
- const myBet = useMemo9(() => {
5846
+ const myBet = useMemo10(() => {
5582
5847
  if (!walletAddress || !game.data?.bettors) return null;
5583
5848
  return game.data.bettors.find((b) => b.wallet === walletAddress) ?? null;
5584
5849
  }, [walletAddress, game.data?.bettors]);
@@ -5587,7 +5852,7 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
5587
5852
  const isWinner = isResolved && myBet != null && myBet.team === game.data?.winnerSide;
5588
5853
  const isEligible = myBet != null && isResolved && (isWinner || isRefund);
5589
5854
  const prizeAmount = isRefund ? myBet?.amount ?? 0 : game.data?.totalPool ?? 0;
5590
- const handleSuccess = useCallback20(
5855
+ const handleSuccess = useCallback24(
5591
5856
  (result) => {
5592
5857
  claimStatus.refetch();
5593
5858
  onSuccess?.(result);
@@ -5672,6 +5937,216 @@ var styles14 = StyleSheet15.create({
5672
5937
  fontWeight: "700"
5673
5938
  }
5674
5939
  });
5940
+
5941
+ // src/ui/game/EnterArcadePoolSheet.tsx
5942
+ import { useEffect as useEffect18, useRef as useRef9, useCallback as useCallback25 } from "react";
5943
+ import {
5944
+ View as View15,
5945
+ Text as Text16,
5946
+ TouchableOpacity as TouchableOpacity12,
5947
+ ActivityIndicator as ActivityIndicator9,
5948
+ Modal as Modal5,
5949
+ Animated as Animated6,
5950
+ StyleSheet as StyleSheet16,
5951
+ KeyboardAvoidingView as KeyboardAvoidingView6,
5952
+ Platform as Platform9
5953
+ } from "react-native";
5954
+ import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
5955
+ var STATUS_LABELS5 = {
5956
+ building: "Building transaction...",
5957
+ signing: "Approve in wallet...",
5958
+ confirming: "Confirming...",
5959
+ success: "Joined!"
5960
+ };
5961
+ function EnterArcadePoolSheet({
5962
+ visible,
5963
+ onDismiss,
5964
+ pool,
5965
+ stats,
5966
+ onSuccess,
5967
+ onError
5968
+ }) {
5969
+ const t = useDubsTheme();
5970
+ const { wallet } = useDubs();
5971
+ const mutation = useEnterArcadePool();
5972
+ const overlayOpacity = useRef9(new Animated6.Value(0)).current;
5973
+ useEffect18(() => {
5974
+ Animated6.timing(overlayOpacity, {
5975
+ toValue: visible ? 1 : 0,
5976
+ duration: 250,
5977
+ useNativeDriver: true
5978
+ }).start();
5979
+ }, [visible, overlayOpacity]);
5980
+ useEffect18(() => {
5981
+ if (visible) {
5982
+ mutation.reset();
5983
+ }
5984
+ }, [visible]);
5985
+ useEffect18(() => {
5986
+ if (mutation.status === "success" && mutation.data) {
5987
+ onSuccess?.(mutation.data);
5988
+ const timer = setTimeout(() => {
5989
+ onDismiss();
5990
+ }, 1500);
5991
+ return () => clearTimeout(timer);
5992
+ }
5993
+ }, [mutation.status, mutation.data]);
5994
+ useEffect18(() => {
5995
+ if (mutation.status === "error" && mutation.error) {
5996
+ onError?.(mutation.error);
5997
+ }
5998
+ }, [mutation.status, mutation.error]);
5999
+ const buyInSol = (pool.buy_in_lamports / 1e9).toFixed(4);
6000
+ const totalPlayers = stats?.total_entries ?? pool.total_entries ?? 0;
6001
+ const topScore = stats?.top_score ?? 0;
6002
+ const potSol = (pool.buy_in_lamports * Number(totalPlayers) / 1e9).toFixed(4);
6003
+ const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
6004
+ const canJoin = !isMutating && mutation.status !== "success";
6005
+ const handleJoin = useCallback25(async () => {
6006
+ if (!wallet.publicKey) return;
6007
+ try {
6008
+ await mutation.execute(pool.id);
6009
+ } catch {
6010
+ }
6011
+ }, [wallet.publicKey, mutation.execute, pool.id]);
6012
+ const statusLabel = STATUS_LABELS5[mutation.status] || "";
6013
+ return /* @__PURE__ */ jsxs16(
6014
+ Modal5,
6015
+ {
6016
+ visible,
6017
+ animationType: "slide",
6018
+ transparent: true,
6019
+ onRequestClose: onDismiss,
6020
+ children: [
6021
+ /* @__PURE__ */ jsx18(Animated6.View, { style: [styles15.overlay, { opacity: overlayOpacity }], children: /* @__PURE__ */ jsx18(TouchableOpacity12, { style: styles15.overlayTap, activeOpacity: 1, onPress: onDismiss }) }),
6022
+ /* @__PURE__ */ jsx18(
6023
+ KeyboardAvoidingView6,
6024
+ {
6025
+ style: styles15.keyboardView,
6026
+ behavior: Platform9.OS === "ios" ? "padding" : void 0,
6027
+ children: /* @__PURE__ */ jsx18(View15, { style: styles15.sheetPositioner, children: /* @__PURE__ */ jsxs16(View15, { style: [styles15.sheet, { backgroundColor: t.background }], children: [
6028
+ /* @__PURE__ */ jsx18(View15, { style: styles15.handleRow, children: /* @__PURE__ */ jsx18(View15, { style: [styles15.handle, { backgroundColor: t.textMuted }] }) }),
6029
+ /* @__PURE__ */ jsxs16(View15, { style: styles15.header, children: [
6030
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.headerTitle, { color: t.text }], children: "Join Pool" }),
6031
+ /* @__PURE__ */ jsx18(TouchableOpacity12, { onPress: onDismiss, activeOpacity: 0.8, children: /* @__PURE__ */ jsx18(Text16, { style: [styles15.closeButton, { color: t.textMuted }], children: "\u2715" }) })
6032
+ ] }),
6033
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.poolName, { color: t.textSecondary }], children: pool.name }),
6034
+ /* @__PURE__ */ jsxs16(View15, { style: [styles15.summaryCard, { backgroundColor: t.surface, borderColor: t.border }], children: [
6035
+ /* @__PURE__ */ jsxs16(View15, { style: styles15.summaryRow, children: [
6036
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.summaryLabel, { color: t.textMuted }], children: "Buy-in" }),
6037
+ /* @__PURE__ */ jsxs16(Text16, { style: [styles15.summaryValue, { color: t.text }], children: [
6038
+ buyInSol,
6039
+ " SOL"
6040
+ ] })
6041
+ ] }),
6042
+ /* @__PURE__ */ jsx18(View15, { style: [styles15.summarySep, { backgroundColor: t.border }] }),
6043
+ /* @__PURE__ */ jsxs16(View15, { style: styles15.summaryRow, children: [
6044
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.summaryLabel, { color: t.textMuted }], children: "Players in" }),
6045
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.summaryValue, { color: t.text }], children: totalPlayers })
6046
+ ] }),
6047
+ /* @__PURE__ */ jsx18(View15, { style: [styles15.summarySep, { backgroundColor: t.border }] }),
6048
+ /* @__PURE__ */ jsxs16(View15, { style: styles15.summaryRow, children: [
6049
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.summaryLabel, { color: t.textMuted }], children: "Current pot" }),
6050
+ /* @__PURE__ */ jsxs16(Text16, { style: [styles15.summaryValue, { color: t.success }], children: [
6051
+ potSol,
6052
+ " SOL"
6053
+ ] })
6054
+ ] }),
6055
+ /* @__PURE__ */ jsx18(View15, { style: [styles15.summarySep, { backgroundColor: t.border }] }),
6056
+ /* @__PURE__ */ jsxs16(View15, { style: styles15.summaryRow, children: [
6057
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.summaryLabel, { color: t.textMuted }], children: "Lives" }),
6058
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.summaryValue, { color: t.text }], children: pool.max_lives })
6059
+ ] }),
6060
+ topScore > 0 && /* @__PURE__ */ jsxs16(Fragment6, { children: [
6061
+ /* @__PURE__ */ jsx18(View15, { style: [styles15.summarySep, { backgroundColor: t.border }] }),
6062
+ /* @__PURE__ */ jsxs16(View15, { style: styles15.summaryRow, children: [
6063
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.summaryLabel, { color: t.textMuted }], children: "Top score" }),
6064
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.summaryValue, { color: t.text }], children: topScore })
6065
+ ] })
6066
+ ] })
6067
+ ] }),
6068
+ mutation.error && /* @__PURE__ */ jsx18(View15, { style: [styles15.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ jsx18(Text16, { style: [styles15.errorText, { color: t.errorText }], children: mutation.error.message }) }),
6069
+ /* @__PURE__ */ jsx18(
6070
+ TouchableOpacity12,
6071
+ {
6072
+ style: [
6073
+ styles15.ctaButton,
6074
+ { backgroundColor: canJoin ? t.accent : t.border }
6075
+ ],
6076
+ disabled: !canJoin,
6077
+ onPress: handleJoin,
6078
+ activeOpacity: 0.8,
6079
+ children: isMutating ? /* @__PURE__ */ jsxs16(View15, { style: styles15.ctaLoading, children: [
6080
+ /* @__PURE__ */ jsx18(ActivityIndicator9, { size: "small", color: "#FFFFFF" }),
6081
+ /* @__PURE__ */ jsx18(Text16, { style: styles15.ctaText, children: statusLabel })
6082
+ ] }) : mutation.status === "success" ? /* @__PURE__ */ jsx18(Text16, { style: styles15.ctaText, children: "Joined!" }) : /* @__PURE__ */ jsx18(Text16, { style: [styles15.ctaText, !canJoin && { opacity: 0.5 }], children: `Join Pool \u2014 ${buyInSol} SOL` })
6083
+ }
6084
+ )
6085
+ ] }) })
6086
+ }
6087
+ )
6088
+ ]
6089
+ }
6090
+ );
6091
+ }
6092
+ var styles15 = StyleSheet16.create({
6093
+ overlay: {
6094
+ ...StyleSheet16.absoluteFillObject,
6095
+ backgroundColor: "rgba(0,0,0,0.5)"
6096
+ },
6097
+ overlayTap: { flex: 1 },
6098
+ keyboardView: { flex: 1, justifyContent: "flex-end" },
6099
+ sheetPositioner: { justifyContent: "flex-end" },
6100
+ sheet: {
6101
+ borderTopLeftRadius: 24,
6102
+ borderTopRightRadius: 24,
6103
+ paddingHorizontal: 20,
6104
+ paddingBottom: 40
6105
+ },
6106
+ handleRow: { alignItems: "center", paddingTop: 10, paddingBottom: 8 },
6107
+ handle: { width: 36, height: 4, borderRadius: 2, opacity: 0.4 },
6108
+ header: {
6109
+ flexDirection: "row",
6110
+ alignItems: "center",
6111
+ justifyContent: "space-between",
6112
+ paddingVertical: 12
6113
+ },
6114
+ headerTitle: { fontSize: 20, fontWeight: "700" },
6115
+ closeButton: { fontSize: 20, padding: 4 },
6116
+ poolName: { fontSize: 15, fontWeight: "600", marginBottom: 8 },
6117
+ summaryCard: {
6118
+ marginTop: 12,
6119
+ borderRadius: 16,
6120
+ borderWidth: 1,
6121
+ overflow: "hidden"
6122
+ },
6123
+ summaryRow: {
6124
+ flexDirection: "row",
6125
+ alignItems: "center",
6126
+ justifyContent: "space-between",
6127
+ paddingHorizontal: 16,
6128
+ paddingVertical: 14
6129
+ },
6130
+ summaryLabel: { fontSize: 14 },
6131
+ summaryValue: { fontSize: 15, fontWeight: "700" },
6132
+ summarySep: { height: 1, marginHorizontal: 16 },
6133
+ errorBox: {
6134
+ marginTop: 16,
6135
+ borderRadius: 12,
6136
+ borderWidth: 1,
6137
+ padding: 12
6138
+ },
6139
+ errorText: { fontSize: 13, fontWeight: "500" },
6140
+ ctaButton: {
6141
+ marginTop: 20,
6142
+ height: 56,
6143
+ borderRadius: 14,
6144
+ justifyContent: "center",
6145
+ alignItems: "center"
6146
+ },
6147
+ ctaText: { color: "#FFFFFF", fontSize: 16, fontWeight: "700" },
6148
+ ctaLoading: { flexDirection: "row", alignItems: "center", gap: 10 }
6149
+ });
5675
6150
  export {
5676
6151
  AuthGate,
5677
6152
  ClaimButton,
@@ -5683,6 +6158,7 @@ export {
5683
6158
  DubsApiError,
5684
6159
  DubsClient,
5685
6160
  DubsProvider,
6161
+ EnterArcadePoolSheet,
5686
6162
  GamePoster,
5687
6163
  JoinGameButton,
5688
6164
  JoinGameSheet,
@@ -5705,12 +6181,16 @@ export {
5705
6181
  parseSolanaError,
5706
6182
  signAndSendBase64Transaction,
5707
6183
  useAppConfig,
6184
+ useArcadeGame,
6185
+ useArcadePool,
6186
+ useArcadePools,
5708
6187
  useAuth,
5709
6188
  useClaim,
5710
6189
  useCreateCustomGame,
5711
6190
  useCreateGame,
5712
6191
  useDubs,
5713
6192
  useDubsTheme,
6193
+ useEnterArcadePool,
5714
6194
  useEvents,
5715
6195
  useGame,
5716
6196
  useGames,