@dubsdotapp/expo 0.3.8 → 0.4.0

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
@@ -636,7 +636,7 @@ function createSecureStoreStorage() {
636
636
  }
637
637
 
638
638
  // src/provider.tsx
639
- import { createContext as createContext4, useContext as useContext4, useMemo as useMemo3, useCallback as useCallback19, useState as useState20, useEffect as useEffect13 } from "react";
639
+ import { createContext as createContext4, useContext as useContext4, useMemo as useMemo3, useCallback as useCallback20, useState as useState22, useEffect as useEffect14 } from "react";
640
640
 
641
641
  // src/ui/theme.ts
642
642
  import { createContext, useContext } from "react";
@@ -1701,7 +1701,7 @@ function ManagedWalletProvider({
1701
1701
  }
1702
1702
 
1703
1703
  // src/ui/AuthGate.tsx
1704
- import React2, { useState as useState19, useEffect as useEffect12, useRef as useRef4, useCallback as useCallback18 } from "react";
1704
+ import React2, { useState as useState21, useEffect as useEffect13, useRef as useRef6, useCallback as useCallback19 } from "react";
1705
1705
  import {
1706
1706
  View as View3,
1707
1707
  Text as Text3,
@@ -2736,6 +2736,135 @@ function useEnterArcadePool() {
2736
2736
  return { execute, status, error, data, reset };
2737
2737
  }
2738
2738
 
2739
+ // src/hooks/useArcadeCountdown.ts
2740
+ import { useState as useState19, useEffect as useEffect12, useRef as useRef4 } from "react";
2741
+ function formatCountdown(ms) {
2742
+ if (ms <= 0) return "Ended";
2743
+ const s2 = Math.floor(ms / 1e3);
2744
+ const m = Math.floor(s2 / 60);
2745
+ const h = Math.floor(m / 60);
2746
+ const d = Math.floor(h / 24);
2747
+ if (d > 0) return `${d}d ${h % 24}h ${m % 60}m`;
2748
+ if (h > 0) return `${h}h ${m % 60}m ${s2 % 60}s`;
2749
+ if (m > 0) return `${m}m ${s2 % 60}s`;
2750
+ return `${s2}s`;
2751
+ }
2752
+ function useArcadeCountdown(nextResolution) {
2753
+ const [now, setNow] = useState19(Date.now());
2754
+ const intervalRef = useRef4(null);
2755
+ useEffect12(() => {
2756
+ if (!nextResolution) return;
2757
+ intervalRef.current = setInterval(() => setNow(Date.now()), 1e3);
2758
+ return () => {
2759
+ if (intervalRef.current) clearInterval(intervalRef.current);
2760
+ };
2761
+ }, [nextResolution]);
2762
+ if (!nextResolution) {
2763
+ return { totalMs: 0, days: 0, hours: 0, minutes: 0, seconds: 0, formatted: "--", isExpired: false };
2764
+ }
2765
+ const target = new Date(nextResolution).getTime();
2766
+ const totalMs = Math.max(0, target - now);
2767
+ const totalSec = Math.floor(totalMs / 1e3);
2768
+ const days = Math.floor(totalSec / 86400);
2769
+ const hours = Math.floor(totalSec % 86400 / 3600);
2770
+ const minutes = Math.floor(totalSec % 3600 / 60);
2771
+ const seconds = totalSec % 60;
2772
+ return {
2773
+ totalMs,
2774
+ days,
2775
+ hours,
2776
+ minutes,
2777
+ seconds,
2778
+ formatted: formatCountdown(totalMs),
2779
+ isExpired: totalMs <= 0
2780
+ };
2781
+ }
2782
+
2783
+ // src/hooks/useArcadeBridge.ts
2784
+ import { useRef as useRef5, useState as useState20, useCallback as useCallback18 } from "react";
2785
+ var PROTOCOL_VERSION = "1.0";
2786
+ function useArcadeBridge({
2787
+ canPlay,
2788
+ startAttempt,
2789
+ submitScore,
2790
+ onScoreSubmitted,
2791
+ onError
2792
+ }) {
2793
+ const webviewRef = useRef5(null);
2794
+ const sessionTokenRef = useRef5(null);
2795
+ const gameStartTimeRef = useRef5(0);
2796
+ const [lastResult, setLastResult] = useState20(null);
2797
+ const [bridgeLoading, setBridgeLoading] = useState20(false);
2798
+ const injectSession = useCallback18((token, attemptNumber) => {
2799
+ webviewRef.current?.injectJavaScript(`
2800
+ window.ARCADE_SESSION_TOKEN = ${JSON.stringify(token)};
2801
+ window.ARCADE_ATTEMPT_NUMBER = ${attemptNumber};
2802
+ window._ARCADE_GAME_START_TIME = Date.now();
2803
+ window.dispatchEvent(new Event('ARCADE_START'));
2804
+ true;
2805
+ `);
2806
+ }, []);
2807
+ const triggerPlay = useCallback18(async () => {
2808
+ if (!canPlay) return;
2809
+ setBridgeLoading(true);
2810
+ try {
2811
+ const result = await startAttempt();
2812
+ sessionTokenRef.current = result.sessionToken;
2813
+ gameStartTimeRef.current = Date.now();
2814
+ setLastResult(null);
2815
+ injectSession(result.sessionToken, result.attemptNumber);
2816
+ } catch (err) {
2817
+ const e = err instanceof Error ? err : new Error(String(err));
2818
+ onError?.(e);
2819
+ } finally {
2820
+ setBridgeLoading(false);
2821
+ }
2822
+ }, [canPlay, startAttempt, injectSession, onError]);
2823
+ const handleMessage = useCallback18(
2824
+ async (event) => {
2825
+ let data;
2826
+ try {
2827
+ data = JSON.parse(event.nativeEvent.data);
2828
+ } catch {
2829
+ return;
2830
+ }
2831
+ if (data.dubsArcade !== PROTOCOL_VERSION) return;
2832
+ switch (data.type) {
2833
+ case "TAP_PLAY": {
2834
+ if (canPlay) {
2835
+ triggerPlay();
2836
+ }
2837
+ return;
2838
+ }
2839
+ case "GAME_OVER": {
2840
+ const token = sessionTokenRef.current;
2841
+ if (!token) return;
2842
+ const score = typeof data.score === "number" ? data.score : 0;
2843
+ const duration = gameStartTimeRef.current > 0 ? Date.now() - gameStartTimeRef.current : typeof data.durationMs === "number" ? data.durationMs : void 0;
2844
+ sessionTokenRef.current = null;
2845
+ gameStartTimeRef.current = 0;
2846
+ setBridgeLoading(true);
2847
+ try {
2848
+ const result = await submitScore(token, score, duration);
2849
+ setLastResult(result);
2850
+ onScoreSubmitted?.(result);
2851
+ } catch (err) {
2852
+ const e = err instanceof Error ? err : new Error(String(err));
2853
+ onError?.(e);
2854
+ } finally {
2855
+ setBridgeLoading(false);
2856
+ }
2857
+ return;
2858
+ }
2859
+ default:
2860
+ return;
2861
+ }
2862
+ },
2863
+ [canPlay, triggerPlay, submitScore, onScoreSubmitted, onError]
2864
+ );
2865
+ return { webviewRef, handleMessage, triggerPlay, lastResult, bridgeLoading };
2866
+ }
2867
+
2739
2868
  // src/ui/AvatarEditor.tsx
2740
2869
  import {
2741
2870
  View as View2,
@@ -2903,11 +3032,11 @@ function AuthGate({
2903
3032
  }) {
2904
3033
  const { client, pushEnabled } = useDubs();
2905
3034
  const auth = useAuth();
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(() => {
3035
+ const [phase, setPhase] = useState21("init");
3036
+ const [registrationPhase, setRegistrationPhase] = useState21(false);
3037
+ const [showPushSetup, setShowPushSetup] = useState21(false);
3038
+ const [isRestoredSession, setIsRestoredSession] = useState21(false);
3039
+ useEffect13(() => {
2911
3040
  let cancelled = false;
2912
3041
  (async () => {
2913
3042
  try {
@@ -2934,23 +3063,23 @@ function AuthGate({
2934
3063
  cancelled = true;
2935
3064
  };
2936
3065
  }, []);
2937
- useEffect12(() => {
3066
+ useEffect13(() => {
2938
3067
  if (auth.status === "needsRegistration") setRegistrationPhase(true);
2939
3068
  }, [auth.status]);
2940
- useEffect12(() => {
3069
+ useEffect13(() => {
2941
3070
  if (pushEnabled && auth.status === "authenticated" && registrationPhase && !isRestoredSession) {
2942
3071
  setShowPushSetup(true);
2943
3072
  }
2944
3073
  }, [pushEnabled, auth.status, registrationPhase, isRestoredSession]);
2945
- useEffect12(() => {
3074
+ useEffect13(() => {
2946
3075
  if (auth.token) onSaveToken(auth.token);
2947
3076
  }, [auth.token]);
2948
- const retry = useCallback18(() => {
3077
+ const retry = useCallback19(() => {
2949
3078
  setRegistrationPhase(false);
2950
3079
  auth.reset();
2951
3080
  auth.authenticate();
2952
3081
  }, [auth]);
2953
- const handleRegister = useCallback18(
3082
+ const handleRegister = useCallback19(
2954
3083
  (username, referralCode, avatarUrl) => {
2955
3084
  auth.register(username, referralCode, avatarUrl);
2956
3085
  },
@@ -3066,20 +3195,20 @@ function DefaultRegistrationScreen({
3066
3195
  }) {
3067
3196
  const t = useDubsTheme();
3068
3197
  const accent = accentColor || t.accent;
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);
3078
- const debounceRef = useRef4(null);
3079
- const fadeAnim = useRef4(new Animated.Value(1)).current;
3080
- const slideAnim = useRef4(new Animated.Value(0)).current;
3198
+ const [step, setStep] = useState21(0);
3199
+ const [avatarSeed, setAvatarSeed] = useState21(generateSeed);
3200
+ const [avatarStyle, setAvatarStyle] = useState21("adventurer");
3201
+ const [avatarBg, setAvatarBg] = useState21("1a1a2e");
3202
+ const [showStyles, setShowStyles] = useState21(false);
3203
+ const [username, setUsername] = useState21("");
3204
+ const [referralCode, setReferralCode] = useState21("");
3205
+ const [checking, setChecking] = useState21(false);
3206
+ const [availability, setAvailability] = useState21(null);
3207
+ const debounceRef = useRef6(null);
3208
+ const fadeAnim = useRef6(new Animated.Value(1)).current;
3209
+ const slideAnim = useRef6(new Animated.Value(0)).current;
3081
3210
  const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed, avatarBg);
3082
- useEffect12(() => {
3211
+ useEffect13(() => {
3083
3212
  if (debounceRef.current) clearTimeout(debounceRef.current);
3084
3213
  const trimmed = username.trim();
3085
3214
  if (trimmed.length < 3) {
@@ -3102,7 +3231,7 @@ function DefaultRegistrationScreen({
3102
3231
  if (debounceRef.current) clearTimeout(debounceRef.current);
3103
3232
  };
3104
3233
  }, [username, client]);
3105
- const animateToStep = useCallback18((newStep) => {
3234
+ const animateToStep = useCallback19((newStep) => {
3106
3235
  const dir = newStep > step ? 1 : -1;
3107
3236
  Keyboard.dismiss();
3108
3237
  Animated.parallel([
@@ -3341,8 +3470,8 @@ function DefaultRegistrationScreen({
3341
3470
  }
3342
3471
  function PushTokenRestorer() {
3343
3472
  const push = usePushNotifications();
3344
- const restored = useRef4(false);
3345
- useEffect12(() => {
3473
+ const restored = useRef6(false);
3474
+ useEffect13(() => {
3346
3475
  if (restored.current) return;
3347
3476
  restored.current = true;
3348
3477
  push.restoreIfGranted();
@@ -3357,9 +3486,9 @@ function PushSetupScreen({
3357
3486
  const t = useDubsTheme();
3358
3487
  const accent = accentColor || t.accent;
3359
3488
  const push = usePushNotifications();
3360
- const fadeAnim = useRef4(new Animated.Value(0)).current;
3361
- const slideAnim = useRef4(new Animated.Value(30)).current;
3362
- useEffect12(() => {
3489
+ const fadeAnim = useRef6(new Animated.Value(0)).current;
3490
+ const slideAnim = useRef6(new Animated.Value(30)).current;
3491
+ useEffect13(() => {
3363
3492
  Animated.parallel([
3364
3493
  Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true }),
3365
3494
  Animated.timing(slideAnim, { toValue: 0, duration: 300, useNativeDriver: true })
@@ -3519,9 +3648,9 @@ function DubsProvider({
3519
3648
  const rpcUrl = rpcUrlOverride || config.rpcUrl;
3520
3649
  const client = useMemo3(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
3521
3650
  const storage = useMemo3(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
3522
- const [uiConfig, setUiConfig] = useState20(null);
3523
- const [resolvedNetwork, setResolvedNetwork] = useState20(network);
3524
- useEffect13(() => {
3651
+ const [uiConfig, setUiConfig] = useState22(null);
3652
+ const [resolvedNetwork, setResolvedNetwork] = useState22(network);
3653
+ useEffect14(() => {
3525
3654
  client.getAppConfig().then((cfg) => {
3526
3655
  console.log("[DubsProvider] UI config loaded:", JSON.stringify(cfg));
3527
3656
  setUiConfig(cfg);
@@ -3613,7 +3742,7 @@ function ManagedInner({
3613
3742
  children
3614
3743
  }) {
3615
3744
  const managedDisconnect = useDisconnect();
3616
- const disconnect = useCallback19(async () => {
3745
+ const disconnect = useCallback20(async () => {
3617
3746
  client.setToken(null);
3618
3747
  await managedDisconnect?.();
3619
3748
  }, [client, managedDisconnect]);
@@ -3654,7 +3783,7 @@ function ExternalWalletProvider({
3654
3783
  pushEnabled,
3655
3784
  children
3656
3785
  }) {
3657
- const disconnect = useCallback19(async () => {
3786
+ const disconnect = useCallback20(async () => {
3658
3787
  client.setToken(null);
3659
3788
  await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
3660
3789
  });
@@ -3917,7 +4046,7 @@ var styles4 = StyleSheet5.create({
3917
4046
  });
3918
4047
 
3919
4048
  // src/ui/UserProfileSheet.tsx
3920
- import { useState as useState21, useEffect as useEffect14, useRef as useRef5, useCallback as useCallback20, useMemo as useMemo5 } from "react";
4049
+ import { useState as useState23, useEffect as useEffect15, useRef as useRef7, useCallback as useCallback21, useMemo as useMemo5 } from "react";
3921
4050
  import {
3922
4051
  View as View6,
3923
4052
  Text as Text6,
@@ -3948,31 +4077,31 @@ function UserProfileSheet({
3948
4077
  const { client } = useDubs();
3949
4078
  const { refreshUser } = useAuth();
3950
4079
  const push = usePushNotifications();
3951
- const overlayOpacity = useRef5(new Animated2.Value(0)).current;
4080
+ const overlayOpacity = useRef7(new Animated2.Value(0)).current;
3952
4081
  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(() => {
4082
+ const [avatarStyle, setAvatarStyle] = useState23(parsed.style);
4083
+ const [avatarSeed, setAvatarSeed] = useState23(parsed.seed);
4084
+ const [bgColor, setBgColor] = useState23(parsed.bg);
4085
+ const [saving, setSaving] = useState23(false);
4086
+ const [error, setError] = useState23(null);
4087
+ useEffect15(() => {
3959
4088
  const p = parseAvatarUrl(user.avatar);
3960
4089
  setAvatarStyle(p.style);
3961
4090
  setAvatarSeed(p.seed);
3962
4091
  setBgColor(p.bg);
3963
4092
  }, [user.avatar]);
3964
- useEffect14(() => {
4093
+ useEffect15(() => {
3965
4094
  Animated2.timing(overlayOpacity, {
3966
4095
  toValue: visible ? 1 : 0,
3967
4096
  duration: 250,
3968
4097
  useNativeDriver: true
3969
4098
  }).start();
3970
4099
  }, [visible, overlayOpacity]);
3971
- useEffect14(() => {
4100
+ useEffect15(() => {
3972
4101
  if (visible) setError(null);
3973
4102
  }, [visible]);
3974
4103
  const currentAvatarUrl = getAvatarUrl(avatarStyle, avatarSeed, bgColor);
3975
- const saveAvatar = useCallback20(async (newUrl) => {
4104
+ const saveAvatar = useCallback21(async (newUrl) => {
3976
4105
  setSaving(true);
3977
4106
  setError(null);
3978
4107
  try {
@@ -3985,16 +4114,16 @@ function UserProfileSheet({
3985
4114
  setSaving(false);
3986
4115
  }
3987
4116
  }, [client, refreshUser, onAvatarUpdated]);
3988
- const handleStyleChange = useCallback20((style) => {
4117
+ const handleStyleChange = useCallback21((style) => {
3989
4118
  setAvatarStyle(style);
3990
4119
  saveAvatar(getAvatarUrl(style, avatarSeed, bgColor));
3991
4120
  }, [avatarSeed, bgColor, saveAvatar]);
3992
- const handleShuffle = useCallback20(() => {
4121
+ const handleShuffle = useCallback21(() => {
3993
4122
  const newSeed = generateSeed();
3994
4123
  setAvatarSeed(newSeed);
3995
4124
  saveAvatar(getAvatarUrl(avatarStyle, newSeed, bgColor));
3996
4125
  }, [avatarStyle, bgColor, saveAvatar]);
3997
- const handleBgChange = useCallback20((color) => {
4126
+ const handleBgChange = useCallback21((color) => {
3998
4127
  setBgColor(color);
3999
4128
  saveAvatar(getAvatarUrl(avatarStyle, avatarSeed, color));
4000
4129
  }, [avatarStyle, avatarSeed, saveAvatar]);
@@ -4274,7 +4403,7 @@ var styles5 = StyleSheet6.create({
4274
4403
  });
4275
4404
 
4276
4405
  // src/ui/game/GamePoster.tsx
4277
- import { useState as useState22 } from "react";
4406
+ import { useState as useState24 } from "react";
4278
4407
  import { StyleSheet as StyleSheet7, View as View7, Text as Text7 } from "react-native";
4279
4408
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
4280
4409
  function computeCountdown(lockTimestamp) {
@@ -4324,7 +4453,7 @@ function GamePoster({ game, ImageComponent }) {
4324
4453
  ] });
4325
4454
  }
4326
4455
  function TeamLogoInternal({ url, size, Img }) {
4327
- const [failed, setFailed] = useState22(false);
4456
+ const [failed, setFailed] = useState24(false);
4328
4457
  if (!url || failed) {
4329
4458
  return /* @__PURE__ */ jsx9(View7, { style: [styles6.logoPlaceholder, { width: size, height: size, borderRadius: size / 2 }] });
4330
4459
  }
@@ -4504,7 +4633,7 @@ var styles7 = StyleSheet8.create({
4504
4633
  });
4505
4634
 
4506
4635
  // src/ui/game/PickWinnerCard.tsx
4507
- import { useState as useState23, useMemo as useMemo7 } from "react";
4636
+ import { useState as useState25, useMemo as useMemo7 } from "react";
4508
4637
  import { StyleSheet as StyleSheet9, View as View9, Text as Text9, TouchableOpacity as TouchableOpacity6 } from "react-native";
4509
4638
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
4510
4639
  function PickWinnerCard({
@@ -4575,7 +4704,7 @@ function TeamOption({
4575
4704
  ImageComponent,
4576
4705
  t
4577
4706
  }) {
4578
- const [imgFailed, setImgFailed] = useState23(false);
4707
+ const [imgFailed, setImgFailed] = useState25(false);
4579
4708
  const Img = ImageComponent || __require("react-native").Image;
4580
4709
  const showImage = imageUrl && !imgFailed;
4581
4710
  return /* @__PURE__ */ jsxs9(
@@ -4616,7 +4745,7 @@ var styles8 = StyleSheet9.create({
4616
4745
  });
4617
4746
 
4618
4747
  // src/ui/game/PlayersCard.tsx
4619
- import { useState as useState24 } from "react";
4748
+ import { useState as useState26 } from "react";
4620
4749
  import { StyleSheet as StyleSheet10, View as View10, Text as Text10 } from "react-native";
4621
4750
  import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
4622
4751
  function truncateWallet(addr, chars) {
@@ -4665,7 +4794,7 @@ function BettorRow({
4665
4794
  ImageComponent,
4666
4795
  t
4667
4796
  }) {
4668
- const [imgFailed, setImgFailed] = useState24(false);
4797
+ const [imgFailed, setImgFailed] = useState26(false);
4669
4798
  const Img = ImageComponent || __require("react-native").Image;
4670
4799
  const showAvatar = bettor.avatar && !imgFailed;
4671
4800
  return /* @__PURE__ */ jsxs10(View10, { style: [styles9.row, !isFirst && { borderTopColor: t.border, borderTopWidth: 1 }], children: [
@@ -4744,7 +4873,7 @@ var styles10 = StyleSheet11.create({
4744
4873
  });
4745
4874
 
4746
4875
  // src/ui/game/CreateCustomGameSheet.tsx
4747
- import { useState as useState25, useEffect as useEffect15, useRef as useRef6, useCallback as useCallback21 } from "react";
4876
+ import { useState as useState27, useEffect as useEffect16, useRef as useRef8, useCallback as useCallback22 } from "react";
4748
4877
  import {
4749
4878
  View as View12,
4750
4879
  Text as Text12,
@@ -4781,18 +4910,18 @@ function CreateCustomGameSheet({
4781
4910
  const t = useDubsTheme();
4782
4911
  const { wallet } = useDubs();
4783
4912
  const mutation = useCreateCustomGame();
4784
- const [selectedAmount, setSelectedAmount] = useState25(null);
4785
- const [customAmount, setCustomAmount] = useState25("");
4786
- const [isCustom, setIsCustom] = useState25(false);
4787
- const overlayOpacity = useRef6(new Animated3.Value(0)).current;
4788
- useEffect15(() => {
4913
+ const [selectedAmount, setSelectedAmount] = useState27(null);
4914
+ const [customAmount, setCustomAmount] = useState27("");
4915
+ const [isCustom, setIsCustom] = useState27(false);
4916
+ const overlayOpacity = useRef8(new Animated3.Value(0)).current;
4917
+ useEffect16(() => {
4789
4918
  Animated3.timing(overlayOpacity, {
4790
4919
  toValue: visible ? 1 : 0,
4791
4920
  duration: 250,
4792
4921
  useNativeDriver: true
4793
4922
  }).start();
4794
4923
  }, [visible, overlayOpacity]);
4795
- useEffect15(() => {
4924
+ useEffect16(() => {
4796
4925
  if (visible) {
4797
4926
  setSelectedAmount(defaultAmount ?? null);
4798
4927
  setCustomAmount("");
@@ -4800,7 +4929,7 @@ function CreateCustomGameSheet({
4800
4929
  mutation.reset();
4801
4930
  }
4802
4931
  }, [visible]);
4803
- useEffect15(() => {
4932
+ useEffect16(() => {
4804
4933
  if (mutation.status === "success" && mutation.data) {
4805
4934
  onSuccess?.(mutation.data);
4806
4935
  const timer = setTimeout(() => {
@@ -4809,23 +4938,23 @@ function CreateCustomGameSheet({
4809
4938
  return () => clearTimeout(timer);
4810
4939
  }
4811
4940
  }, [mutation.status, mutation.data]);
4812
- useEffect15(() => {
4941
+ useEffect16(() => {
4813
4942
  if (mutation.status === "error" && mutation.error) {
4814
4943
  onError?.(mutation.error);
4815
4944
  }
4816
4945
  }, [mutation.status, mutation.error]);
4817
- const handlePresetSelect = useCallback21((amount) => {
4946
+ const handlePresetSelect = useCallback22((amount) => {
4818
4947
  setSelectedAmount(amount);
4819
4948
  setIsCustom(false);
4820
4949
  setCustomAmount("");
4821
4950
  onAmountChange?.(amount);
4822
4951
  }, [onAmountChange]);
4823
- const handleCustomSelect = useCallback21(() => {
4952
+ const handleCustomSelect = useCallback22(() => {
4824
4953
  setIsCustom(true);
4825
4954
  setSelectedAmount(null);
4826
4955
  onAmountChange?.(null);
4827
4956
  }, [onAmountChange]);
4828
- const handleCustomAmountChange = useCallback21((text) => {
4957
+ const handleCustomAmountChange = useCallback22((text) => {
4829
4958
  const cleaned = text.replace(/[^0-9.]/g, "").replace(/(\..*?)\..*/g, "$1");
4830
4959
  setCustomAmount(cleaned);
4831
4960
  const parsed = parseFloat(cleaned);
@@ -4840,7 +4969,7 @@ function CreateCustomGameSheet({
4840
4969
  const winnerTakes = pot * (1 - fee / 100);
4841
4970
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
4842
4971
  const canCreate = finalAmount !== null && finalAmount > 0 && !isMutating && mutation.status !== "success";
4843
- const handleCreate = useCallback21(async () => {
4972
+ const handleCreate = useCallback22(async () => {
4844
4973
  if (!finalAmount || !wallet.publicKey) return;
4845
4974
  try {
4846
4975
  await mutation.execute({
@@ -5109,7 +5238,7 @@ var styles11 = StyleSheet12.create({
5109
5238
  });
5110
5239
 
5111
5240
  // src/ui/game/JoinGameSheet.tsx
5112
- import { useState as useState26, useEffect as useEffect16, useRef as useRef7, useCallback as useCallback22, useMemo as useMemo9 } from "react";
5241
+ import { useState as useState28, useEffect as useEffect17, useRef as useRef9, useCallback as useCallback23, useMemo as useMemo9 } from "react";
5113
5242
  import {
5114
5243
  View as View13,
5115
5244
  Text as Text13,
@@ -5145,22 +5274,22 @@ function JoinGameSheet({
5145
5274
  const { wallet } = useDubs();
5146
5275
  const mutation = useJoinGame();
5147
5276
  const isCustomGame = game.gameMode === CUSTOM_GAME_MODE;
5148
- const [selectedTeam, setSelectedTeam] = useState26(null);
5149
- const overlayOpacity = useRef7(new Animated4.Value(0)).current;
5150
- useEffect16(() => {
5277
+ const [selectedTeam, setSelectedTeam] = useState28(null);
5278
+ const overlayOpacity = useRef9(new Animated4.Value(0)).current;
5279
+ useEffect17(() => {
5151
5280
  Animated4.timing(overlayOpacity, {
5152
5281
  toValue: visible ? 1 : 0,
5153
5282
  duration: 250,
5154
5283
  useNativeDriver: true
5155
5284
  }).start();
5156
5285
  }, [visible, overlayOpacity]);
5157
- useEffect16(() => {
5286
+ useEffect17(() => {
5158
5287
  if (visible) {
5159
5288
  setSelectedTeam(isPoolModeEnabled ? "home" : isCustomGame ? "away" : null);
5160
5289
  mutation.reset();
5161
5290
  }
5162
5291
  }, [visible]);
5163
- useEffect16(() => {
5292
+ useEffect17(() => {
5164
5293
  if (mutation.status === "success" && mutation.data) {
5165
5294
  onSuccess?.(mutation.data);
5166
5295
  const timer = setTimeout(() => {
@@ -5169,7 +5298,7 @@ function JoinGameSheet({
5169
5298
  return () => clearTimeout(timer);
5170
5299
  }
5171
5300
  }, [mutation.status, mutation.data]);
5172
- useEffect16(() => {
5301
+ useEffect17(() => {
5173
5302
  if (mutation.status === "error" && mutation.error) {
5174
5303
  onError?.(mutation.error);
5175
5304
  }
@@ -5199,7 +5328,7 @@ function JoinGameSheet({
5199
5328
  }, [bettors, wallet.publicKey]);
5200
5329
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
5201
5330
  const canJoin = selectedTeam !== null && !isMutating && mutation.status !== "success" && !alreadyJoined;
5202
- const handleJoin = useCallback22(async () => {
5331
+ const handleJoin = useCallback23(async () => {
5203
5332
  if (!selectedTeam || !wallet.publicKey) return;
5204
5333
  try {
5205
5334
  await mutation.execute({
@@ -5343,7 +5472,7 @@ function TeamButton({
5343
5472
  ImageComponent,
5344
5473
  t
5345
5474
  }) {
5346
- const [imgFailed, setImgFailed] = useState26(false);
5475
+ const [imgFailed, setImgFailed] = useState28(false);
5347
5476
  const Img = ImageComponent || __require("react-native").Image;
5348
5477
  const showImage = imageUrl && !imgFailed;
5349
5478
  return /* @__PURE__ */ jsxs13(
@@ -5520,7 +5649,7 @@ var styles12 = StyleSheet13.create({
5520
5649
  });
5521
5650
 
5522
5651
  // src/ui/game/ClaimPrizeSheet.tsx
5523
- import { useState as useState27, useEffect as useEffect17, useRef as useRef8, useCallback as useCallback23 } from "react";
5652
+ import { useState as useState29, useEffect as useEffect18, useRef as useRef10, useCallback as useCallback24 } from "react";
5524
5653
  import {
5525
5654
  View as View14,
5526
5655
  Text as Text14,
@@ -5551,18 +5680,18 @@ function ClaimPrizeSheet({
5551
5680
  const t = useDubsTheme();
5552
5681
  const { wallet } = useDubs();
5553
5682
  const mutation = useClaim();
5554
- const overlayOpacity = useRef8(new Animated5.Value(0)).current;
5555
- const celebrationScale = useRef8(new Animated5.Value(0)).current;
5556
- const celebrationOpacity = useRef8(new Animated5.Value(0)).current;
5557
- const [showCelebration, setShowCelebration] = useState27(false);
5558
- useEffect17(() => {
5683
+ const overlayOpacity = useRef10(new Animated5.Value(0)).current;
5684
+ const celebrationScale = useRef10(new Animated5.Value(0)).current;
5685
+ const celebrationOpacity = useRef10(new Animated5.Value(0)).current;
5686
+ const [showCelebration, setShowCelebration] = useState29(false);
5687
+ useEffect18(() => {
5559
5688
  Animated5.timing(overlayOpacity, {
5560
5689
  toValue: visible ? 1 : 0,
5561
5690
  duration: 250,
5562
5691
  useNativeDriver: true
5563
5692
  }).start();
5564
5693
  }, [visible, overlayOpacity]);
5565
- useEffect17(() => {
5694
+ useEffect18(() => {
5566
5695
  if (visible) {
5567
5696
  mutation.reset();
5568
5697
  setShowCelebration(false);
@@ -5570,7 +5699,7 @@ function ClaimPrizeSheet({
5570
5699
  celebrationOpacity.setValue(0);
5571
5700
  }
5572
5701
  }, [visible]);
5573
- useEffect17(() => {
5702
+ useEffect18(() => {
5574
5703
  if (mutation.status === "success" && mutation.data) {
5575
5704
  setShowCelebration(true);
5576
5705
  Animated5.parallel([
@@ -5593,14 +5722,14 @@ function ClaimPrizeSheet({
5593
5722
  return () => clearTimeout(timer);
5594
5723
  }
5595
5724
  }, [mutation.status, mutation.data]);
5596
- useEffect17(() => {
5725
+ useEffect18(() => {
5597
5726
  if (mutation.status === "error" && mutation.error) {
5598
5727
  onError?.(mutation.error);
5599
5728
  }
5600
5729
  }, [mutation.status, mutation.error]);
5601
5730
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
5602
5731
  const canClaim = !isMutating && mutation.status !== "success" && !!wallet.publicKey;
5603
- const handleClaim = useCallback23(async () => {
5732
+ const handleClaim = useCallback24(async () => {
5604
5733
  if (!wallet.publicKey) return;
5605
5734
  try {
5606
5735
  await mutation.execute({
@@ -5833,7 +5962,7 @@ var styles13 = StyleSheet14.create({
5833
5962
  });
5834
5963
 
5835
5964
  // src/ui/game/ClaimButton.tsx
5836
- import { useState as useState28, useMemo as useMemo10, useCallback as useCallback24 } from "react";
5965
+ import { useState as useState30, useMemo as useMemo10, useCallback as useCallback25 } from "react";
5837
5966
  import { StyleSheet as StyleSheet15, Text as Text15, TouchableOpacity as TouchableOpacity11 } from "react-native";
5838
5967
  import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
5839
5968
  function ClaimButton({ gameId, style, onSuccess, onError }) {
@@ -5841,7 +5970,7 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
5841
5970
  const { wallet } = useDubs();
5842
5971
  const game = useGame(gameId);
5843
5972
  const claimStatus = useHasClaimed(gameId);
5844
- const [sheetVisible, setSheetVisible] = useState28(false);
5973
+ const [sheetVisible, setSheetVisible] = useState30(false);
5845
5974
  const walletAddress = wallet.publicKey?.toBase58() ?? null;
5846
5975
  const myBet = useMemo10(() => {
5847
5976
  if (!walletAddress || !game.data?.bettors) return null;
@@ -5852,7 +5981,7 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
5852
5981
  const isWinner = isResolved && myBet != null && myBet.team === game.data?.winnerSide;
5853
5982
  const isEligible = myBet != null && isResolved && (isWinner || isRefund);
5854
5983
  const prizeAmount = isRefund ? myBet?.amount ?? 0 : game.data?.totalPool ?? 0;
5855
- const handleSuccess = useCallback24(
5984
+ const handleSuccess = useCallback25(
5856
5985
  (result) => {
5857
5986
  claimStatus.refetch();
5858
5987
  onSuccess?.(result);
@@ -5939,7 +6068,7 @@ var styles14 = StyleSheet15.create({
5939
6068
  });
5940
6069
 
5941
6070
  // src/ui/game/EnterArcadePoolSheet.tsx
5942
- import { useEffect as useEffect18, useRef as useRef9, useCallback as useCallback25 } from "react";
6071
+ import { useEffect as useEffect19, useRef as useRef11, useCallback as useCallback26 } from "react";
5943
6072
  import {
5944
6073
  View as View15,
5945
6074
  Text as Text16,
@@ -5970,20 +6099,20 @@ function EnterArcadePoolSheet({
5970
6099
  const t = useDubsTheme();
5971
6100
  const { wallet } = useDubs();
5972
6101
  const mutation = useEnterArcadePool();
5973
- const overlayOpacity = useRef9(new Animated6.Value(0)).current;
5974
- useEffect18(() => {
6102
+ const overlayOpacity = useRef11(new Animated6.Value(0)).current;
6103
+ useEffect19(() => {
5975
6104
  Animated6.timing(overlayOpacity, {
5976
6105
  toValue: visible ? 1 : 0,
5977
6106
  duration: 250,
5978
6107
  useNativeDriver: true
5979
6108
  }).start();
5980
6109
  }, [visible, overlayOpacity]);
5981
- useEffect18(() => {
6110
+ useEffect19(() => {
5982
6111
  if (visible) {
5983
6112
  mutation.reset();
5984
6113
  }
5985
6114
  }, [visible]);
5986
- useEffect18(() => {
6115
+ useEffect19(() => {
5987
6116
  if (mutation.status === "success" && mutation.data) {
5988
6117
  onSuccess?.(mutation.data);
5989
6118
  const timer = setTimeout(() => {
@@ -5992,7 +6121,7 @@ function EnterArcadePoolSheet({
5992
6121
  return () => clearTimeout(timer);
5993
6122
  }
5994
6123
  }, [mutation.status, mutation.data]);
5995
- useEffect18(() => {
6124
+ useEffect19(() => {
5996
6125
  if (mutation.status === "error" && mutation.error) {
5997
6126
  onError?.(mutation.error);
5998
6127
  }
@@ -6003,7 +6132,7 @@ function EnterArcadePoolSheet({
6003
6132
  const potSol = (pool.buy_in_lamports * Number(totalPlayers) / 1e9).toFixed(4);
6004
6133
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
6005
6134
  const canJoin = !isMutating && mutation.status !== "success";
6006
- const handleJoin = useCallback25(async () => {
6135
+ const handleJoin = useCallback26(async () => {
6007
6136
  if (!wallet.publicKey) return;
6008
6137
  try {
6009
6138
  await mutation.execute(pool.id);
@@ -6154,7 +6283,7 @@ var styles15 = StyleSheet16.create({
6154
6283
  });
6155
6284
 
6156
6285
  // src/ui/game/ArcadeLeaderboardSheet.tsx
6157
- import { useEffect as useEffect19, useRef as useRef10 } from "react";
6286
+ import { useEffect as useEffect20, useRef as useRef12 } from "react";
6158
6287
  import {
6159
6288
  View as View16,
6160
6289
  Text as Text17,
@@ -6182,15 +6311,15 @@ function ArcadeLeaderboardSheet({
6182
6311
  }) {
6183
6312
  const t = useDubsTheme();
6184
6313
  const { pool, leaderboard, stats, loading, refetch } = useArcadePool(poolId);
6185
- const overlayOpacity = useRef10(new Animated7.Value(0)).current;
6186
- useEffect19(() => {
6314
+ const overlayOpacity = useRef12(new Animated7.Value(0)).current;
6315
+ useEffect20(() => {
6187
6316
  Animated7.timing(overlayOpacity, {
6188
6317
  toValue: visible ? 1 : 0,
6189
6318
  duration: 250,
6190
6319
  useNativeDriver: true
6191
6320
  }).start();
6192
6321
  }, [visible, overlayOpacity]);
6193
- useEffect19(() => {
6322
+ useEffect20(() => {
6194
6323
  if (visible) refetch();
6195
6324
  }, [visible]);
6196
6325
  const renderItem = ({ item, index }) => {
@@ -6370,6 +6499,8 @@ export {
6370
6499
  parseSolanaError,
6371
6500
  signAndSendBase64Transaction,
6372
6501
  useAppConfig,
6502
+ useArcadeBridge,
6503
+ useArcadeCountdown,
6373
6504
  useArcadeGame,
6374
6505
  useArcadePool,
6375
6506
  useArcadePools,