@dubsdotapp/expo 0.5.16 → 0.5.18

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.js CHANGED
@@ -32,6 +32,8 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  ArcadeLeaderboardSheet: () => ArcadeLeaderboardSheet,
34
34
  AuthGate: () => AuthGate,
35
+ ChatProvider: () => ChatProvider,
36
+ ChatSocket: () => ChatSocket,
35
37
  ClaimButton: () => ClaimButton,
36
38
  ClaimPrizeSheet: () => ClaimPrizeSheet,
37
39
  ConnectWalletButton: () => ConnectWalletButton,
@@ -45,6 +47,9 @@ __export(index_exports, {
45
47
  DubsProvider: () => DubsProvider,
46
48
  EnterArcadePoolSheet: () => EnterArcadePoolSheet,
47
49
  GamePoster: () => GamePoster,
50
+ JackpotCard: () => JackpotCard,
51
+ JackpotSheet: () => JackpotSheet,
52
+ JackpotWidget: () => JackpotWidget,
48
53
  JoinGameButton: () => JoinGameButton,
49
54
  JoinGameSheet: () => JoinGameSheet,
50
55
  LivePoolsCard: () => LivePoolsCard,
@@ -73,23 +78,39 @@ __export(index_exports, {
73
78
  useArcadePool: () => useArcadePool,
74
79
  useArcadePools: () => useArcadePools,
75
80
  useAuth: () => useAuth,
81
+ useChatContext: () => useChatContext,
82
+ useChatMessages: () => useChatMessages,
83
+ useChatStatus: () => useChatStatus,
76
84
  useClaim: () => useClaim,
85
+ useConversations: () => useConversations,
77
86
  useCreateCustomGame: () => useCreateCustomGame,
78
87
  useCreateGame: () => useCreateGame,
88
+ useDirectMessages: () => useDirectMessages,
79
89
  useDubs: () => useDubs,
80
90
  useDubsTheme: () => useDubsTheme,
81
91
  useEnterArcadePool: () => useEnterArcadePool,
92
+ useEnterJackpot: () => useEnterJackpot,
82
93
  useEvents: () => useEvents,
94
+ useFriendRequests: () => useFriendRequests,
95
+ useFriends: () => useFriends,
83
96
  useGame: () => useGame,
84
97
  useGames: () => useGames,
85
98
  useHasClaimed: () => useHasClaimed,
86
99
  useHighlights: () => useHighlights,
100
+ useJackpot: () => useJackpot,
101
+ useJackpotHistory: () => useJackpotHistory,
87
102
  useJoinGame: () => useJoinGame,
88
103
  useNetworkGames: () => useNetworkGames,
104
+ useOnlineUsers: () => useOnlineUsers,
89
105
  usePushNotifications: () => usePushNotifications,
106
+ useRespondToFriendRequest: () => useRespondToFriendRequest,
107
+ useSearchUsers: () => useSearchUsers,
108
+ useSendFriendRequest: () => useSendFriendRequest,
109
+ useSendMessage: () => useSendMessage,
90
110
  useShorts: () => useShorts,
91
111
  useUFCFightCard: () => useUFCFightCard,
92
- useUFCFighterDetail: () => useUFCFighterDetail
112
+ useUFCFighterDetail: () => useUFCFighterDetail,
113
+ useUnreadCount: () => useUnreadCount
93
114
  });
94
115
  module.exports = __toCommonJS(index_exports);
95
116
 
@@ -682,6 +703,151 @@ var DubsClient = class {
682
703
  );
683
704
  return res.entry;
684
705
  }
706
+ // ── Jackpot ──
707
+ /** Get current jackpot round + last winner */
708
+ async getJackpotCurrent() {
709
+ const res = await this.request(
710
+ "GET",
711
+ "/jackpot/current"
712
+ );
713
+ return { round: res.round, lastWinner: res.lastWinner };
714
+ }
715
+ /** Get current round entries with odds */
716
+ async getJackpotEntries() {
717
+ const res = await this.request(
718
+ "GET",
719
+ "/jackpot/entries"
720
+ );
721
+ return { roundId: res.roundId, entries: res.entries, totalEntries: res.totalEntries };
722
+ }
723
+ /** Get recent jackpot round results */
724
+ async getJackpotHistory(limit) {
725
+ const qs = limit ? `?limit=${limit}` : "";
726
+ const res = await this.request(
727
+ "GET",
728
+ `/jackpot/history${qs}`
729
+ );
730
+ return res.rounds;
731
+ }
732
+ /** Get jackpot protocol config */
733
+ async getJackpotConfig() {
734
+ const res = await this.request(
735
+ "GET",
736
+ "/jackpot/config"
737
+ );
738
+ return res.config;
739
+ }
740
+ /** Build unsigned jackpot enter transaction */
741
+ async buildJackpotEnter(playerAddress, amount) {
742
+ const res = await this.request(
743
+ "POST",
744
+ "/jackpot/build-enter",
745
+ { playerAddress, amount }
746
+ );
747
+ return { transaction: res.transaction, roundId: res.roundId, amount: res.amount, amountSol: res.amountSol };
748
+ }
749
+ /** Confirm jackpot entry after wallet signs (creates developer attribution) */
750
+ async confirmJackpotEnter(params) {
751
+ const res = await this.request(
752
+ "POST",
753
+ "/jackpot/confirm-enter",
754
+ params
755
+ );
756
+ return { attributed: res.attributed, appId: res.appId, signature: res.signature };
757
+ }
758
+ // ── Chat ──
759
+ /** Get recent global chat messages */
760
+ async getChatMessages(params) {
761
+ const qs = new URLSearchParams();
762
+ if (params?.limit) qs.set("limit", String(params.limit));
763
+ if (params?.before) qs.set("before", String(params.before));
764
+ const query = qs.toString();
765
+ return this.request("GET", `/chat/messages${query ? `?${query}` : ""}`);
766
+ }
767
+ /** Send a message to global chat */
768
+ async sendChatMessage(params) {
769
+ return this.request("POST", "/chat/message", params);
770
+ }
771
+ /** Edit your own message */
772
+ async editChatMessage(id, message) {
773
+ return this.request("PUT", `/chat/message/${id}`, { message });
774
+ }
775
+ /** Delete your own message */
776
+ async deleteChatMessage(id) {
777
+ return this.request("DELETE", `/chat/message/${id}`);
778
+ }
779
+ /** Block a user */
780
+ async blockUser(targetUserId) {
781
+ await this.request("POST", `/chat/block/${targetUserId}`);
782
+ }
783
+ /** Unblock a user */
784
+ async unblockUser(targetUserId) {
785
+ await this.request("DELETE", `/chat/block/${targetUserId}`);
786
+ }
787
+ // ── DMs ──
788
+ /** Get DM conversations inbox */
789
+ async getConversations(limit) {
790
+ const qs = limit ? `?limit=${limit}` : "";
791
+ return this.request("GET", `/dm/conversations${qs}`);
792
+ }
793
+ /** Get conversation history with a specific user */
794
+ async getConversation(walletAddress, params) {
795
+ const qs = new URLSearchParams();
796
+ if (params?.limit) qs.set("limit", String(params.limit));
797
+ if (params?.beforeId) qs.set("beforeId", String(params.beforeId));
798
+ const query = qs.toString();
799
+ return this.request("GET", `/dm/conversation/${encodeURIComponent(walletAddress)}${query ? `?${query}` : ""}`);
800
+ }
801
+ /** Send a direct message */
802
+ async sendDirectMessage(params) {
803
+ return this.request("POST", "/dm/send", params);
804
+ }
805
+ /** Mark all DMs from a user as read */
806
+ async markDMRead(walletAddress) {
807
+ return this.request("POST", `/dm/read/${encodeURIComponent(walletAddress)}`);
808
+ }
809
+ /** Get unread DM count */
810
+ async getDMUnreadCount() {
811
+ return this.request("GET", "/dm/unread");
812
+ }
813
+ /** Delete a DM conversation (soft delete) */
814
+ async deleteConversation(walletAddress) {
815
+ await this.request("DELETE", `/dm/conversation/${encodeURIComponent(walletAddress)}`);
816
+ }
817
+ // ── Social ──
818
+ /** Search users by username */
819
+ async searchUsers(query) {
820
+ const qs = query ? `?q=${encodeURIComponent(query)}` : "";
821
+ return this.request("GET", `/social/search${qs}`);
822
+ }
823
+ /** Send a friend request */
824
+ async sendFriendRequest(targetUserId) {
825
+ return this.request("POST", `/social/friend-request/${targetUserId}`);
826
+ }
827
+ /** Get pending friend requests (received) */
828
+ async getPendingFriendRequests() {
829
+ return this.request("GET", "/social/friend-requests");
830
+ }
831
+ /** Accept a friend request */
832
+ async acceptFriendRequest(requestId) {
833
+ await this.request("POST", `/social/request/${requestId}/accept`);
834
+ }
835
+ /** Reject a friend request */
836
+ async rejectFriendRequest(requestId) {
837
+ await this.request("POST", `/social/request/${requestId}/reject`);
838
+ }
839
+ /** Get friends list */
840
+ async getFriends() {
841
+ return this.request("GET", "/social/friends");
842
+ }
843
+ /** Remove a friend */
844
+ async removeFriend(targetUserId) {
845
+ await this.request("DELETE", `/social/friend/${targetUserId}`);
846
+ }
847
+ /** Get blocked users list */
848
+ async getBlockedUsers() {
849
+ return this.request("GET", "/social/blocked");
850
+ }
685
851
  // ── App Config ──
686
852
  /** Fetch the app's UI customization config (accent color, icon, tagline, environment) */
687
853
  async getAppConfig() {
@@ -733,7 +899,7 @@ function createSecureStoreStorage() {
733
899
  }
734
900
 
735
901
  // src/provider.tsx
736
- var import_react26 = require("react");
902
+ var import_react29 = require("react");
737
903
 
738
904
  // src/ui/theme.ts
739
905
  var import_react = require("react");
@@ -1791,7 +1957,7 @@ function ManagedWalletProvider({
1791
1957
  }
1792
1958
 
1793
1959
  // src/ui/AuthGate.tsx
1794
- var import_react25 = __toESM(require("react"));
1960
+ var import_react28 = __toESM(require("react"));
1795
1961
  var import_react_native8 = require("react-native");
1796
1962
 
1797
1963
  // src/hooks/useEvents.ts
@@ -3002,6 +3168,117 @@ function useArcadeBridge({
3002
3168
  return { webviewRef, handleMessage, triggerPlay, lastResult, bridgeLoading };
3003
3169
  }
3004
3170
 
3171
+ // src/hooks/useJackpot.ts
3172
+ var import_react25 = require("react");
3173
+ function useJackpot() {
3174
+ const { client } = useDubs();
3175
+ const [round, setRound] = (0, import_react25.useState)(null);
3176
+ const [lastWinner, setLastWinner] = (0, import_react25.useState)(null);
3177
+ const [loading, setLoading] = (0, import_react25.useState)(false);
3178
+ const [error, setError] = (0, import_react25.useState)(null);
3179
+ const fetch2 = (0, import_react25.useCallback)(async () => {
3180
+ setLoading(true);
3181
+ setError(null);
3182
+ try {
3183
+ const result = await client.getJackpotCurrent();
3184
+ setRound(result.round);
3185
+ setLastWinner(result.lastWinner);
3186
+ } catch (err) {
3187
+ setError(err instanceof Error ? err : new Error(String(err)));
3188
+ } finally {
3189
+ setLoading(false);
3190
+ }
3191
+ }, [client]);
3192
+ (0, import_react25.useEffect)(() => {
3193
+ fetch2();
3194
+ }, [fetch2]);
3195
+ return { round, lastWinner, loading, error, refetch: fetch2 };
3196
+ }
3197
+
3198
+ // src/hooks/useJackpotHistory.ts
3199
+ var import_react26 = require("react");
3200
+ function useJackpotHistory(limit) {
3201
+ const { client } = useDubs();
3202
+ const [rounds, setRounds] = (0, import_react26.useState)([]);
3203
+ const [loading, setLoading] = (0, import_react26.useState)(false);
3204
+ const [error, setError] = (0, import_react26.useState)(null);
3205
+ const fetch2 = (0, import_react26.useCallback)(async () => {
3206
+ setLoading(true);
3207
+ setError(null);
3208
+ try {
3209
+ const result = await client.getJackpotHistory(limit);
3210
+ setRounds(result);
3211
+ } catch (err) {
3212
+ setError(err instanceof Error ? err : new Error(String(err)));
3213
+ } finally {
3214
+ setLoading(false);
3215
+ }
3216
+ }, [client, limit]);
3217
+ (0, import_react26.useEffect)(() => {
3218
+ fetch2();
3219
+ }, [fetch2]);
3220
+ return { rounds, loading, error, refetch: fetch2 };
3221
+ }
3222
+
3223
+ // src/hooks/useEnterJackpot.ts
3224
+ var import_react27 = require("react");
3225
+ function useEnterJackpot() {
3226
+ const { client, wallet, connection } = useDubs();
3227
+ const [status, setStatus] = (0, import_react27.useState)("idle");
3228
+ const [error, setError] = (0, import_react27.useState)(null);
3229
+ const [data, setData] = (0, import_react27.useState)(null);
3230
+ const reset = (0, import_react27.useCallback)(() => {
3231
+ setStatus("idle");
3232
+ setError(null);
3233
+ setData(null);
3234
+ }, []);
3235
+ const execute = (0, import_react27.useCallback)(async (amountLamports) => {
3236
+ if (!wallet.publicKey) throw new Error("Wallet not connected");
3237
+ const walletAddress = wallet.publicKey.toBase58();
3238
+ setStatus("building");
3239
+ setError(null);
3240
+ setData(null);
3241
+ try {
3242
+ console.log("[useEnterJackpot] Step 1: Building transaction...", { walletAddress, amountLamports });
3243
+ const buildResult = await client.buildJackpotEnter(walletAddress, amountLamports);
3244
+ console.log("[useEnterJackpot] Step 1 done:", { roundId: buildResult.roundId, amount: buildResult.amount });
3245
+ setStatus("signing");
3246
+ console.log("[useEnterJackpot] Step 2: Signing and sending...");
3247
+ const signature = await signAndSendBase64Transaction(
3248
+ buildResult.transaction,
3249
+ wallet,
3250
+ connection
3251
+ );
3252
+ console.log("[useEnterJackpot] Step 2 done. Signature:", signature);
3253
+ setStatus("confirming");
3254
+ console.log("[useEnterJackpot] Step 3: Confirming with backend...");
3255
+ await client.confirmJackpotEnter({
3256
+ playerAddress: walletAddress,
3257
+ roundId: buildResult.roundId,
3258
+ amount: amountLamports,
3259
+ signature
3260
+ });
3261
+ console.log("[useEnterJackpot] Step 3 done. Entry confirmed + attributed.");
3262
+ const result = {
3263
+ roundId: buildResult.roundId,
3264
+ amount: buildResult.amount,
3265
+ amountSol: buildResult.amountSol,
3266
+ signature
3267
+ };
3268
+ setData(result);
3269
+ setStatus("success");
3270
+ return result;
3271
+ } catch (err) {
3272
+ console.error("[useEnterJackpot] FAILED:", err);
3273
+ const e = err instanceof Error ? err : new Error(String(err));
3274
+ setError(e);
3275
+ setStatus("error");
3276
+ throw e;
3277
+ }
3278
+ }, [client, wallet, connection]);
3279
+ return { execute, status, error, data, reset };
3280
+ }
3281
+
3005
3282
  // src/ui/AvatarEditor.tsx
3006
3283
  var import_react_native7 = require("react-native");
3007
3284
  var import_jsx_runtime3 = require("react/jsx-runtime");
@@ -3163,11 +3440,11 @@ function AuthGate({
3163
3440
  }) {
3164
3441
  const { client, pushEnabled } = useDubs();
3165
3442
  const auth = useAuth();
3166
- const [phase, setPhase] = (0, import_react25.useState)("init");
3167
- const [registrationPhase, setRegistrationPhase] = (0, import_react25.useState)(false);
3168
- const [showPushSetup, setShowPushSetup] = (0, import_react25.useState)(false);
3169
- const [isRestoredSession, setIsRestoredSession] = (0, import_react25.useState)(false);
3170
- (0, import_react25.useEffect)(() => {
3443
+ const [phase, setPhase] = (0, import_react28.useState)("init");
3444
+ const [registrationPhase, setRegistrationPhase] = (0, import_react28.useState)(false);
3445
+ const [showPushSetup, setShowPushSetup] = (0, import_react28.useState)(false);
3446
+ const [isRestoredSession, setIsRestoredSession] = (0, import_react28.useState)(false);
3447
+ (0, import_react28.useEffect)(() => {
3171
3448
  let cancelled = false;
3172
3449
  (async () => {
3173
3450
  try {
@@ -3194,23 +3471,23 @@ function AuthGate({
3194
3471
  cancelled = true;
3195
3472
  };
3196
3473
  }, []);
3197
- (0, import_react25.useEffect)(() => {
3474
+ (0, import_react28.useEffect)(() => {
3198
3475
  if (auth.status === "needsRegistration") setRegistrationPhase(true);
3199
3476
  }, [auth.status]);
3200
- (0, import_react25.useEffect)(() => {
3477
+ (0, import_react28.useEffect)(() => {
3201
3478
  if (pushEnabled && auth.status === "authenticated" && registrationPhase && !isRestoredSession) {
3202
3479
  setShowPushSetup(true);
3203
3480
  }
3204
3481
  }, [pushEnabled, auth.status, registrationPhase, isRestoredSession]);
3205
- (0, import_react25.useEffect)(() => {
3482
+ (0, import_react28.useEffect)(() => {
3206
3483
  if (auth.token) onSaveToken(auth.token);
3207
3484
  }, [auth.token]);
3208
- const retry = (0, import_react25.useCallback)(() => {
3485
+ const retry = (0, import_react28.useCallback)(() => {
3209
3486
  setRegistrationPhase(false);
3210
3487
  auth.reset();
3211
3488
  auth.authenticate();
3212
3489
  }, [auth]);
3213
- const handleRegister = (0, import_react25.useCallback)(
3490
+ const handleRegister = (0, import_react28.useCallback)(
3214
3491
  (username, referralCode, avatarUrl) => {
3215
3492
  auth.register(username, referralCode, avatarUrl);
3216
3493
  },
@@ -3310,7 +3587,7 @@ function DefaultErrorScreen({ error, onRetry, appName, accentColor }) {
3310
3587
  function StepIndicator({ currentStep }) {
3311
3588
  const t = useDubsTheme();
3312
3589
  const steps = [0, 1, 2, 3];
3313
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native8.View, { style: s.stepRow, children: steps.map((i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react25.default.Fragment, { children: [
3590
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native8.View, { style: s.stepRow, children: steps.map((i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react28.default.Fragment, { children: [
3314
3591
  i > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native8.View, { style: [s.stepLine, { backgroundColor: i <= currentStep ? t.success : t.border }] }),
3315
3592
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3316
3593
  import_react_native8.View,
@@ -3334,20 +3611,20 @@ function DefaultRegistrationScreen({
3334
3611
  }) {
3335
3612
  const t = useDubsTheme();
3336
3613
  const accent = accentColor || t.accent;
3337
- const [step, setStep] = (0, import_react25.useState)(0);
3338
- const [avatarSeed, setAvatarSeed] = (0, import_react25.useState)(generateSeed);
3339
- const [avatarStyle, setAvatarStyle] = (0, import_react25.useState)("adventurer");
3340
- const [avatarBg, setAvatarBg] = (0, import_react25.useState)("1a1a2e");
3341
- const [showStyles, setShowStyles] = (0, import_react25.useState)(false);
3342
- const [username, setUsername] = (0, import_react25.useState)("");
3343
- const [referralCode, setReferralCode] = (0, import_react25.useState)("");
3344
- const [checking, setChecking] = (0, import_react25.useState)(false);
3345
- const [availability, setAvailability] = (0, import_react25.useState)(null);
3346
- const debounceRef = (0, import_react25.useRef)(null);
3347
- const fadeAnim = (0, import_react25.useRef)(new import_react_native8.Animated.Value(1)).current;
3348
- const slideAnim = (0, import_react25.useRef)(new import_react_native8.Animated.Value(0)).current;
3614
+ const [step, setStep] = (0, import_react28.useState)(0);
3615
+ const [avatarSeed, setAvatarSeed] = (0, import_react28.useState)(generateSeed);
3616
+ const [avatarStyle, setAvatarStyle] = (0, import_react28.useState)("adventurer");
3617
+ const [avatarBg, setAvatarBg] = (0, import_react28.useState)("1a1a2e");
3618
+ const [showStyles, setShowStyles] = (0, import_react28.useState)(false);
3619
+ const [username, setUsername] = (0, import_react28.useState)("");
3620
+ const [referralCode, setReferralCode] = (0, import_react28.useState)("");
3621
+ const [checking, setChecking] = (0, import_react28.useState)(false);
3622
+ const [availability, setAvailability] = (0, import_react28.useState)(null);
3623
+ const debounceRef = (0, import_react28.useRef)(null);
3624
+ const fadeAnim = (0, import_react28.useRef)(new import_react_native8.Animated.Value(1)).current;
3625
+ const slideAnim = (0, import_react28.useRef)(new import_react_native8.Animated.Value(0)).current;
3349
3626
  const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed, avatarBg);
3350
- (0, import_react25.useEffect)(() => {
3627
+ (0, import_react28.useEffect)(() => {
3351
3628
  if (debounceRef.current) clearTimeout(debounceRef.current);
3352
3629
  const trimmed = username.trim();
3353
3630
  if (trimmed.length < 3) {
@@ -3370,7 +3647,7 @@ function DefaultRegistrationScreen({
3370
3647
  if (debounceRef.current) clearTimeout(debounceRef.current);
3371
3648
  };
3372
3649
  }, [username, client]);
3373
- const animateToStep = (0, import_react25.useCallback)((newStep) => {
3650
+ const animateToStep = (0, import_react28.useCallback)((newStep) => {
3374
3651
  const dir = newStep > step ? 1 : -1;
3375
3652
  import_react_native8.Keyboard.dismiss();
3376
3653
  import_react_native8.Animated.parallel([
@@ -3609,8 +3886,8 @@ function DefaultRegistrationScreen({
3609
3886
  }
3610
3887
  function PushTokenRestorer() {
3611
3888
  const push = usePushNotifications();
3612
- const restored = (0, import_react25.useRef)(false);
3613
- (0, import_react25.useEffect)(() => {
3889
+ const restored = (0, import_react28.useRef)(false);
3890
+ (0, import_react28.useEffect)(() => {
3614
3891
  if (restored.current) return;
3615
3892
  restored.current = true;
3616
3893
  push.restoreIfGranted();
@@ -3625,9 +3902,9 @@ function PushSetupScreen({
3625
3902
  const t = useDubsTheme();
3626
3903
  const accent = accentColor || t.accent;
3627
3904
  const push = usePushNotifications();
3628
- const fadeAnim = (0, import_react25.useRef)(new import_react_native8.Animated.Value(0)).current;
3629
- const slideAnim = (0, import_react25.useRef)(new import_react_native8.Animated.Value(30)).current;
3630
- (0, import_react25.useEffect)(() => {
3905
+ const fadeAnim = (0, import_react28.useRef)(new import_react_native8.Animated.Value(0)).current;
3906
+ const slideAnim = (0, import_react28.useRef)(new import_react_native8.Animated.Value(30)).current;
3907
+ (0, import_react28.useEffect)(() => {
3631
3908
  import_react_native8.Animated.parallel([
3632
3909
  import_react_native8.Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true }),
3633
3910
  import_react_native8.Animated.timing(slideAnim, { toValue: 0, duration: 300, useNativeDriver: true })
@@ -3763,7 +4040,7 @@ var s = import_react_native8.StyleSheet.create({
3763
4040
 
3764
4041
  // src/provider.tsx
3765
4042
  var import_jsx_runtime5 = require("react/jsx-runtime");
3766
- var DubsContext = (0, import_react26.createContext)(null);
4043
+ var DubsContext = (0, import_react29.createContext)(null);
3767
4044
  function DubsProvider({
3768
4045
  apiKey,
3769
4046
  children,
@@ -3785,11 +4062,11 @@ function DubsProvider({
3785
4062
  const config = NETWORK_CONFIG[network];
3786
4063
  const baseUrl = baseUrlOverride || config.baseUrl;
3787
4064
  const rpcUrl = rpcUrlOverride || config.rpcUrl;
3788
- const client = (0, import_react26.useMemo)(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
3789
- const storage = (0, import_react26.useMemo)(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
3790
- const [uiConfig, setUiConfig] = (0, import_react26.useState)(null);
3791
- const [resolvedNetwork, setResolvedNetwork] = (0, import_react26.useState)(network);
3792
- (0, import_react26.useEffect)(() => {
4065
+ const client = (0, import_react29.useMemo)(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
4066
+ const storage = (0, import_react29.useMemo)(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
4067
+ const [uiConfig, setUiConfig] = (0, import_react29.useState)(null);
4068
+ const [resolvedNetwork, setResolvedNetwork] = (0, import_react29.useState)(network);
4069
+ (0, import_react29.useEffect)(() => {
3793
4070
  client.getAppConfig().then((cfg) => {
3794
4071
  console.log("[DubsProvider] UI config loaded:", JSON.stringify(cfg));
3795
4072
  setUiConfig(cfg);
@@ -3805,7 +4082,7 @@ function DubsProvider({
3805
4082
  const resolvedConfig = NETWORK_CONFIG[resolvedNetwork];
3806
4083
  const resolvedRpcUrl = rpcUrlOverride || resolvedConfig.rpcUrl;
3807
4084
  const cluster = resolvedConfig.cluster;
3808
- const connection = (0, import_react26.useMemo)(() => new import_web34.Connection(resolvedRpcUrl, { commitment: "confirmed" }), [resolvedRpcUrl]);
4085
+ const connection = (0, import_react29.useMemo)(() => new import_web34.Connection(resolvedRpcUrl, { commitment: "confirmed" }), [resolvedRpcUrl]);
3809
4086
  if (uiConfig === null) return null;
3810
4087
  const themeOverrides = {};
3811
4088
  if (uiConfig.accentColor) {
@@ -3881,11 +4158,11 @@ function ManagedInner({
3881
4158
  children
3882
4159
  }) {
3883
4160
  const managedDisconnect = useDisconnect();
3884
- const disconnect = (0, import_react26.useCallback)(async () => {
4161
+ const disconnect = (0, import_react29.useCallback)(async () => {
3885
4162
  client.setToken(null);
3886
4163
  await managedDisconnect?.();
3887
4164
  }, [client, managedDisconnect]);
3888
- const value = (0, import_react26.useMemo)(
4165
+ const value = (0, import_react29.useMemo)(
3889
4166
  () => ({ client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled }),
3890
4167
  [client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled]
3891
4168
  );
@@ -3922,13 +4199,13 @@ function ExternalWalletProvider({
3922
4199
  pushEnabled,
3923
4200
  children
3924
4201
  }) {
3925
- const disconnect = (0, import_react26.useCallback)(async () => {
4202
+ const disconnect = (0, import_react29.useCallback)(async () => {
3926
4203
  client.setToken(null);
3927
4204
  await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
3928
4205
  });
3929
4206
  await wallet.disconnect?.();
3930
4207
  }, [client, storage, wallet]);
3931
- const value = (0, import_react26.useMemo)(
4208
+ const value = (0, import_react29.useMemo)(
3932
4209
  () => ({ client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled }),
3933
4210
  [client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled]
3934
4211
  );
@@ -3953,14 +4230,14 @@ function ExternalWalletProvider({
3953
4230
  ) });
3954
4231
  }
3955
4232
  function useDubs() {
3956
- const ctx = (0, import_react26.useContext)(DubsContext);
4233
+ const ctx = (0, import_react29.useContext)(DubsContext);
3957
4234
  if (!ctx) {
3958
4235
  throw new Error("useDubs must be used within a <DubsProvider>");
3959
4236
  }
3960
4237
  return ctx;
3961
4238
  }
3962
4239
  function useAppConfig() {
3963
- const ctx = (0, import_react26.useContext)(DubsContext);
4240
+ const ctx = (0, import_react29.useContext)(DubsContext);
3964
4241
  return ctx?.uiConfig || {};
3965
4242
  }
3966
4243
 
@@ -4018,7 +4295,7 @@ var styles3 = import_react_native9.StyleSheet.create({
4018
4295
  });
4019
4296
 
4020
4297
  // src/ui/UserProfileCard.tsx
4021
- var import_react27 = require("react");
4298
+ var import_react30 = require("react");
4022
4299
  var import_react_native10 = require("react-native");
4023
4300
  var import_jsx_runtime7 = require("react/jsx-runtime");
4024
4301
  function truncateAddress(address, chars = 4) {
@@ -4038,7 +4315,7 @@ function UserProfileCard({
4038
4315
  memberSince
4039
4316
  }) {
4040
4317
  const t = useDubsTheme();
4041
- const imageUri = (0, import_react27.useMemo)(
4318
+ const imageUri = (0, import_react30.useMemo)(
4042
4319
  () => ensurePngAvatar(avatarUrl) || `https://api.dicebear.com/9.x/avataaars/png?seed=${walletAddress}&size=128`,
4043
4320
  [avatarUrl, walletAddress]
4044
4321
  );
@@ -4231,7 +4508,7 @@ var styles5 = import_react_native11.StyleSheet.create({
4231
4508
  });
4232
4509
 
4233
4510
  // src/ui/UserProfileSheet.tsx
4234
- var import_react28 = require("react");
4511
+ var import_react31 = require("react");
4235
4512
  var import_react_native12 = require("react-native");
4236
4513
  var import_jsx_runtime9 = require("react/jsx-runtime");
4237
4514
  function truncateAddress3(address, chars = 4) {
@@ -4249,31 +4526,31 @@ function UserProfileSheet({
4249
4526
  const { client } = useDubs();
4250
4527
  const { refreshUser } = useAuth();
4251
4528
  const push = usePushNotifications();
4252
- const overlayOpacity = (0, import_react28.useRef)(new import_react_native12.Animated.Value(0)).current;
4253
- const parsed = (0, import_react28.useMemo)(() => parseAvatarUrl(user.avatar), [user.avatar]);
4254
- const [avatarStyle, setAvatarStyle] = (0, import_react28.useState)(parsed.style);
4255
- const [avatarSeed, setAvatarSeed] = (0, import_react28.useState)(parsed.seed);
4256
- const [bgColor, setBgColor] = (0, import_react28.useState)(parsed.bg);
4257
- const [saving, setSaving] = (0, import_react28.useState)(false);
4258
- const [error, setError] = (0, import_react28.useState)(null);
4259
- (0, import_react28.useEffect)(() => {
4529
+ const overlayOpacity = (0, import_react31.useRef)(new import_react_native12.Animated.Value(0)).current;
4530
+ const parsed = (0, import_react31.useMemo)(() => parseAvatarUrl(user.avatar), [user.avatar]);
4531
+ const [avatarStyle, setAvatarStyle] = (0, import_react31.useState)(parsed.style);
4532
+ const [avatarSeed, setAvatarSeed] = (0, import_react31.useState)(parsed.seed);
4533
+ const [bgColor, setBgColor] = (0, import_react31.useState)(parsed.bg);
4534
+ const [saving, setSaving] = (0, import_react31.useState)(false);
4535
+ const [error, setError] = (0, import_react31.useState)(null);
4536
+ (0, import_react31.useEffect)(() => {
4260
4537
  const p = parseAvatarUrl(user.avatar);
4261
4538
  setAvatarStyle(p.style);
4262
4539
  setAvatarSeed(p.seed);
4263
4540
  setBgColor(p.bg);
4264
4541
  }, [user.avatar]);
4265
- (0, import_react28.useEffect)(() => {
4542
+ (0, import_react31.useEffect)(() => {
4266
4543
  import_react_native12.Animated.timing(overlayOpacity, {
4267
4544
  toValue: visible ? 1 : 0,
4268
4545
  duration: 250,
4269
4546
  useNativeDriver: true
4270
4547
  }).start();
4271
4548
  }, [visible, overlayOpacity]);
4272
- (0, import_react28.useEffect)(() => {
4549
+ (0, import_react31.useEffect)(() => {
4273
4550
  if (visible) setError(null);
4274
4551
  }, [visible]);
4275
4552
  const currentAvatarUrl = getAvatarUrl(avatarStyle, avatarSeed, bgColor);
4276
- const saveAvatar = (0, import_react28.useCallback)(async (newUrl) => {
4553
+ const saveAvatar = (0, import_react31.useCallback)(async (newUrl) => {
4277
4554
  setSaving(true);
4278
4555
  setError(null);
4279
4556
  try {
@@ -4286,16 +4563,16 @@ function UserProfileSheet({
4286
4563
  setSaving(false);
4287
4564
  }
4288
4565
  }, [client, refreshUser, onAvatarUpdated]);
4289
- const handleStyleChange = (0, import_react28.useCallback)((style) => {
4566
+ const handleStyleChange = (0, import_react31.useCallback)((style) => {
4290
4567
  setAvatarStyle(style);
4291
4568
  saveAvatar(getAvatarUrl(style, avatarSeed, bgColor));
4292
4569
  }, [avatarSeed, bgColor, saveAvatar]);
4293
- const handleShuffle = (0, import_react28.useCallback)(() => {
4570
+ const handleShuffle = (0, import_react31.useCallback)(() => {
4294
4571
  const newSeed = generateSeed();
4295
4572
  setAvatarSeed(newSeed);
4296
4573
  saveAvatar(getAvatarUrl(avatarStyle, newSeed, bgColor));
4297
4574
  }, [avatarStyle, bgColor, saveAvatar]);
4298
- const handleBgChange = (0, import_react28.useCallback)((color) => {
4575
+ const handleBgChange = (0, import_react31.useCallback)((color) => {
4299
4576
  setBgColor(color);
4300
4577
  saveAvatar(getAvatarUrl(avatarStyle, avatarSeed, color));
4301
4578
  }, [avatarStyle, avatarSeed, saveAvatar]);
@@ -4575,7 +4852,7 @@ var styles6 = import_react_native12.StyleSheet.create({
4575
4852
  });
4576
4853
 
4577
4854
  // src/ui/game/GamePoster.tsx
4578
- var import_react29 = require("react");
4855
+ var import_react32 = require("react");
4579
4856
  var import_react_native13 = require("react-native");
4580
4857
  var import_jsx_runtime10 = require("react/jsx-runtime");
4581
4858
  function computeCountdown(lockTimestamp) {
@@ -4625,7 +4902,7 @@ function GamePoster({ game, ImageComponent }) {
4625
4902
  ] });
4626
4903
  }
4627
4904
  function TeamLogoInternal({ url, size, Img }) {
4628
- const [failed, setFailed] = (0, import_react29.useState)(false);
4905
+ const [failed, setFailed] = (0, import_react32.useState)(false);
4629
4906
  if (!url || failed) {
4630
4907
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native13.View, { style: [styles7.logoPlaceholder, { width: size, height: size, borderRadius: size / 2 }] });
4631
4908
  }
@@ -4726,7 +5003,7 @@ var styles7 = import_react_native13.StyleSheet.create({
4726
5003
  });
4727
5004
 
4728
5005
  // src/ui/game/LivePoolsCard.tsx
4729
- var import_react30 = require("react");
5006
+ var import_react33 = require("react");
4730
5007
  var import_react_native14 = require("react-native");
4731
5008
  var import_jsx_runtime11 = require("react/jsx-runtime");
4732
5009
  function LivePoolsCard({
@@ -4742,7 +5019,7 @@ function LivePoolsCard({
4742
5019
  const homePool = game.homePool || 0;
4743
5020
  const awayPool = game.awayPool || 0;
4744
5021
  const totalPool = game.totalPool || 0;
4745
- const { homePercent, awayPercent, homeOdds, awayOdds } = (0, import_react30.useMemo)(() => {
5022
+ const { homePercent, awayPercent, homeOdds, awayOdds } = (0, import_react33.useMemo)(() => {
4746
5023
  return {
4747
5024
  homePercent: totalPool > 0 ? homePool / totalPool * 100 : 50,
4748
5025
  awayPercent: totalPool > 0 ? awayPool / totalPool * 100 : 50,
@@ -4805,7 +5082,7 @@ var styles8 = import_react_native14.StyleSheet.create({
4805
5082
  });
4806
5083
 
4807
5084
  // src/ui/game/PickWinnerCard.tsx
4808
- var import_react31 = require("react");
5085
+ var import_react34 = require("react");
4809
5086
  var import_react_native15 = require("react-native");
4810
5087
  var import_jsx_runtime12 = require("react/jsx-runtime");
4811
5088
  function PickWinnerCard({
@@ -4823,7 +5100,7 @@ function PickWinnerCard({
4823
5100
  const totalPool = game.totalPool || 0;
4824
5101
  const homePool = game.homePool || 0;
4825
5102
  const awayPool = game.awayPool || 0;
4826
- const { homeOdds, awayOdds, homeBets, awayBets } = (0, import_react31.useMemo)(() => ({
5103
+ const { homeOdds, awayOdds, homeBets, awayBets } = (0, import_react34.useMemo)(() => ({
4827
5104
  homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
4828
5105
  awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014",
4829
5106
  homeBets: bettors.filter((b) => b.team === "home").length,
@@ -4876,7 +5153,7 @@ function TeamOption({
4876
5153
  ImageComponent,
4877
5154
  t
4878
5155
  }) {
4879
- const [imgFailed, setImgFailed] = (0, import_react31.useState)(false);
5156
+ const [imgFailed, setImgFailed] = (0, import_react34.useState)(false);
4880
5157
  const Img = ImageComponent || require("react-native").Image;
4881
5158
  const showImage = imageUrl && !imgFailed;
4882
5159
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
@@ -4917,7 +5194,7 @@ var styles9 = import_react_native15.StyleSheet.create({
4917
5194
  });
4918
5195
 
4919
5196
  // src/ui/game/PlayersCard.tsx
4920
- var import_react32 = require("react");
5197
+ var import_react35 = require("react");
4921
5198
  var import_react_native16 = require("react-native");
4922
5199
  var import_jsx_runtime13 = require("react/jsx-runtime");
4923
5200
  function truncateWallet(addr, chars) {
@@ -4966,7 +5243,7 @@ function BettorRow({
4966
5243
  ImageComponent,
4967
5244
  t
4968
5245
  }) {
4969
- const [imgFailed, setImgFailed] = (0, import_react32.useState)(false);
5246
+ const [imgFailed, setImgFailed] = (0, import_react35.useState)(false);
4970
5247
  const Img = ImageComponent || require("react-native").Image;
4971
5248
  const showAvatar = bettor.avatar && !imgFailed;
4972
5249
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native16.View, { style: [styles10.row, !isFirst && { borderTopColor: t.border, borderTopWidth: 1 }], children: [
@@ -4993,7 +5270,7 @@ var styles10 = import_react_native16.StyleSheet.create({
4993
5270
  });
4994
5271
 
4995
5272
  // src/ui/game/JoinGameButton.tsx
4996
- var import_react33 = require("react");
5273
+ var import_react36 = require("react");
4997
5274
  var import_react_native17 = require("react-native");
4998
5275
  var import_jsx_runtime14 = require("react/jsx-runtime");
4999
5276
  var STATUS_LABELS = {
@@ -5004,7 +5281,7 @@ var STATUS_LABELS = {
5004
5281
  };
5005
5282
  function JoinGameButton({ game, walletAddress, selectedTeam, status, onJoin }) {
5006
5283
  const t = useDubsTheme();
5007
- const alreadyJoined = (0, import_react33.useMemo)(() => {
5284
+ const alreadyJoined = (0, import_react36.useMemo)(() => {
5008
5285
  if (!walletAddress) return false;
5009
5286
  return (game.bettors || []).some((b) => b.wallet === walletAddress);
5010
5287
  }, [game.bettors, walletAddress]);
@@ -5045,7 +5322,7 @@ var styles11 = import_react_native17.StyleSheet.create({
5045
5322
  });
5046
5323
 
5047
5324
  // src/ui/game/CreateCustomGameSheet.tsx
5048
- var import_react34 = require("react");
5325
+ var import_react37 = require("react");
5049
5326
  var import_react_native18 = require("react-native");
5050
5327
  var import_jsx_runtime15 = require("react/jsx-runtime");
5051
5328
  var STATUS_LABELS2 = {
@@ -5071,18 +5348,18 @@ function CreateCustomGameSheet({
5071
5348
  const t = useDubsTheme();
5072
5349
  const { wallet } = useDubs();
5073
5350
  const mutation = useCreateCustomGame();
5074
- const [selectedAmount, setSelectedAmount] = (0, import_react34.useState)(null);
5075
- const [customAmount, setCustomAmount] = (0, import_react34.useState)("");
5076
- const [isCustom, setIsCustom] = (0, import_react34.useState)(false);
5077
- const overlayOpacity = (0, import_react34.useRef)(new import_react_native18.Animated.Value(0)).current;
5078
- (0, import_react34.useEffect)(() => {
5351
+ const [selectedAmount, setSelectedAmount] = (0, import_react37.useState)(null);
5352
+ const [customAmount, setCustomAmount] = (0, import_react37.useState)("");
5353
+ const [isCustom, setIsCustom] = (0, import_react37.useState)(false);
5354
+ const overlayOpacity = (0, import_react37.useRef)(new import_react_native18.Animated.Value(0)).current;
5355
+ (0, import_react37.useEffect)(() => {
5079
5356
  import_react_native18.Animated.timing(overlayOpacity, {
5080
5357
  toValue: visible ? 1 : 0,
5081
5358
  duration: 250,
5082
5359
  useNativeDriver: true
5083
5360
  }).start();
5084
5361
  }, [visible, overlayOpacity]);
5085
- (0, import_react34.useEffect)(() => {
5362
+ (0, import_react37.useEffect)(() => {
5086
5363
  if (visible) {
5087
5364
  setSelectedAmount(defaultAmount ?? null);
5088
5365
  setCustomAmount("");
@@ -5090,7 +5367,7 @@ function CreateCustomGameSheet({
5090
5367
  mutation.reset();
5091
5368
  }
5092
5369
  }, [visible]);
5093
- (0, import_react34.useEffect)(() => {
5370
+ (0, import_react37.useEffect)(() => {
5094
5371
  if (mutation.status === "success" && mutation.data) {
5095
5372
  onSuccess?.(mutation.data);
5096
5373
  const timer = setTimeout(() => {
@@ -5099,23 +5376,23 @@ function CreateCustomGameSheet({
5099
5376
  return () => clearTimeout(timer);
5100
5377
  }
5101
5378
  }, [mutation.status, mutation.data]);
5102
- (0, import_react34.useEffect)(() => {
5379
+ (0, import_react37.useEffect)(() => {
5103
5380
  if (mutation.status === "error" && mutation.error) {
5104
5381
  onError?.(mutation.error);
5105
5382
  }
5106
5383
  }, [mutation.status, mutation.error]);
5107
- const handlePresetSelect = (0, import_react34.useCallback)((amount) => {
5384
+ const handlePresetSelect = (0, import_react37.useCallback)((amount) => {
5108
5385
  setSelectedAmount(amount);
5109
5386
  setIsCustom(false);
5110
5387
  setCustomAmount("");
5111
5388
  onAmountChange?.(amount);
5112
5389
  }, [onAmountChange]);
5113
- const handleCustomSelect = (0, import_react34.useCallback)(() => {
5390
+ const handleCustomSelect = (0, import_react37.useCallback)(() => {
5114
5391
  setIsCustom(true);
5115
5392
  setSelectedAmount(null);
5116
5393
  onAmountChange?.(null);
5117
5394
  }, [onAmountChange]);
5118
- const handleCustomAmountChange = (0, import_react34.useCallback)((text) => {
5395
+ const handleCustomAmountChange = (0, import_react37.useCallback)((text) => {
5119
5396
  const cleaned = text.replace(/[^0-9.]/g, "").replace(/(\..*?)\..*/g, "$1");
5120
5397
  setCustomAmount(cleaned);
5121
5398
  const parsed = parseFloat(cleaned);
@@ -5130,7 +5407,7 @@ function CreateCustomGameSheet({
5130
5407
  const winnerTakes = pot * (1 - fee / 100);
5131
5408
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
5132
5409
  const canCreate = finalAmount !== null && finalAmount > 0 && !isMutating && mutation.status !== "success";
5133
- const handleCreate = (0, import_react34.useCallback)(async () => {
5410
+ const handleCreate = (0, import_react37.useCallback)(async () => {
5134
5411
  if (!finalAmount || !wallet.publicKey) return;
5135
5412
  try {
5136
5413
  await mutation.execute({
@@ -5399,11 +5676,11 @@ var styles12 = import_react_native18.StyleSheet.create({
5399
5676
  });
5400
5677
 
5401
5678
  // src/ui/game/JoinGameSheet.tsx
5402
- var import_react37 = require("react");
5679
+ var import_react40 = require("react");
5403
5680
  var import_react_native21 = require("react-native");
5404
5681
 
5405
5682
  // src/ui/game/SolSlider.tsx
5406
- var import_react35 = require("react");
5683
+ var import_react38 = require("react");
5407
5684
  var import_react_native19 = require("react-native");
5408
5685
  var import_jsx_runtime16 = require("react/jsx-runtime");
5409
5686
  var THUMB_SIZE = 32;
@@ -5422,9 +5699,9 @@ function SolSlider({
5422
5699
  }) {
5423
5700
  const t = useDubsTheme();
5424
5701
  const accent = accentColor || t.accent;
5425
- const trackRef = (0, import_react35.useRef)(null);
5426
- const trackWidth = (0, import_react35.useRef)(0);
5427
- const lastTickValue = (0, import_react35.useRef)(value);
5702
+ const trackRef = (0, import_react38.useRef)(null);
5703
+ const trackWidth = (0, import_react38.useRef)(0);
5704
+ const lastTickValue = (0, import_react38.useRef)(value);
5428
5705
  const clamp = (v) => {
5429
5706
  const stepped = Math.round(v / step) * step;
5430
5707
  return Math.max(min, Math.min(max, parseFloat(stepped.toFixed(4))));
@@ -5437,7 +5714,7 @@ function SolSlider({
5437
5714
  const ratio2 = Math.max(0, Math.min(1, x / trackWidth.current));
5438
5715
  return clamp(min + ratio2 * (max - min));
5439
5716
  };
5440
- const panResponder = (0, import_react35.useRef)(
5717
+ const panResponder = (0, import_react38.useRef)(
5441
5718
  import_react_native19.PanResponder.create({
5442
5719
  onStartShouldSetPanResponder: () => !disabled,
5443
5720
  onMoveShouldSetPanResponder: () => !disabled,
@@ -5592,7 +5869,7 @@ var styles13 = import_react_native19.StyleSheet.create({
5592
5869
  });
5593
5870
 
5594
5871
  // src/ui/game/TeamButton.tsx
5595
- var import_react36 = require("react");
5872
+ var import_react39 = require("react");
5596
5873
  var import_react_native20 = require("react-native");
5597
5874
  var import_jsx_runtime17 = require("react/jsx-runtime");
5598
5875
  function TeamButton({
@@ -5606,7 +5883,7 @@ function TeamButton({
5606
5883
  ImageComponent,
5607
5884
  t
5608
5885
  }) {
5609
- const [imgFailed, setImgFailed] = (0, import_react36.useState)(false);
5886
+ const [imgFailed, setImgFailed] = (0, import_react39.useState)(false);
5610
5887
  const Img = ImageComponent || require("react-native").Image;
5611
5888
  const showImage = imageUrl && !imgFailed;
5612
5889
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
@@ -5710,20 +5987,20 @@ function JoinGameSheet({
5710
5987
  const { wallet } = useDubs();
5711
5988
  const mutation = useJoinGame();
5712
5989
  const isCustomGame = game.gameMode === CUSTOM_GAME_MODE;
5713
- const [selectedTeam, setSelectedTeam] = (0, import_react37.useState)(null);
5714
- const [wager, setWager] = (0, import_react37.useState)(game.buyIn);
5715
- const [showSuccess, setShowSuccess] = (0, import_react37.useState)(false);
5716
- const overlayOpacity = (0, import_react37.useRef)(new import_react_native21.Animated.Value(0)).current;
5717
- const successScale = (0, import_react37.useRef)(new import_react_native21.Animated.Value(0)).current;
5718
- const successOpacity = (0, import_react37.useRef)(new import_react_native21.Animated.Value(0)).current;
5719
- (0, import_react37.useEffect)(() => {
5990
+ const [selectedTeam, setSelectedTeam] = (0, import_react40.useState)(null);
5991
+ const [wager, setWager] = (0, import_react40.useState)(game.buyIn);
5992
+ const [showSuccess, setShowSuccess] = (0, import_react40.useState)(false);
5993
+ const overlayOpacity = (0, import_react40.useRef)(new import_react_native21.Animated.Value(0)).current;
5994
+ const successScale = (0, import_react40.useRef)(new import_react_native21.Animated.Value(0)).current;
5995
+ const successOpacity = (0, import_react40.useRef)(new import_react_native21.Animated.Value(0)).current;
5996
+ (0, import_react40.useEffect)(() => {
5720
5997
  import_react_native21.Animated.timing(overlayOpacity, {
5721
5998
  toValue: visible ? 1 : 0,
5722
5999
  duration: 250,
5723
6000
  useNativeDriver: true
5724
6001
  }).start();
5725
6002
  }, [visible, overlayOpacity]);
5726
- (0, import_react37.useEffect)(() => {
6003
+ (0, import_react40.useEffect)(() => {
5727
6004
  if (visible) {
5728
6005
  setSelectedTeam(isPoolModeEnabled ? "home" : isCustomGame ? "away" : null);
5729
6006
  setWager(game.buyIn);
@@ -5733,7 +6010,7 @@ function JoinGameSheet({
5733
6010
  mutation.reset();
5734
6011
  }
5735
6012
  }, [visible]);
5736
- (0, import_react37.useEffect)(() => {
6013
+ (0, import_react40.useEffect)(() => {
5737
6014
  if (mutation.status === "success" && mutation.data) {
5738
6015
  setShowSuccess(true);
5739
6016
  onSuccess?.(mutation.data);
@@ -5750,7 +6027,7 @@ function JoinGameSheet({
5750
6027
  return () => clearTimeout(timer);
5751
6028
  }
5752
6029
  }, [mutation.status, mutation.data]);
5753
- (0, import_react37.useEffect)(() => {
6030
+ (0, import_react40.useEffect)(() => {
5754
6031
  if (mutation.status === "error" && mutation.error) {
5755
6032
  onError?.(mutation.error);
5756
6033
  }
@@ -5765,7 +6042,7 @@ function JoinGameSheet({
5765
6042
  const drawBettors = bettors.filter((b) => b.team === "draw");
5766
6043
  const hasDrawOption = drawPool > 0 || drawBettors.length > 0 || game.league && ["English Premier League", "EPL", "MLS", "La Liga", "Serie A", "Bundesliga", "Ligue 1"].some((l) => (game.league || "").includes(l));
5767
6044
  const poolAfterJoin = totalPool + wager;
5768
- const { homeOdds, awayOdds, drawOdds, homeBets, awayBets, drawBets } = (0, import_react37.useMemo)(() => {
6045
+ const { homeOdds, awayOdds, drawOdds, homeBets, awayBets, drawBets } = (0, import_react40.useMemo)(() => {
5769
6046
  const homeBetsCount = bettors.filter((b) => b.team === "home").length;
5770
6047
  const awayBetsCount = bettors.filter((b) => b.team === "away").length;
5771
6048
  const drawBetsCount = bettors.filter((b) => b.team === "draw").length;
@@ -5786,7 +6063,7 @@ function JoinGameSheet({
5786
6063
  const potentialWinnings = selectedOdds !== "\u2014" ? formatSol(parseFloat(selectedOdds) * wager) : "\u2014";
5787
6064
  const homeName = shortName ? shortName(opponents[0]?.name) : opponents[0]?.name || "Home";
5788
6065
  const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
5789
- const myBet = (0, import_react37.useMemo)(() => {
6066
+ const myBet = (0, import_react40.useMemo)(() => {
5790
6067
  if (!wallet.publicKey) return null;
5791
6068
  const addr = wallet.publicKey.toBase58();
5792
6069
  return bettors.find((b) => b.wallet === addr) ?? null;
@@ -5794,7 +6071,7 @@ function JoinGameSheet({
5794
6071
  const alreadyJoined = myBet !== null;
5795
6072
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
5796
6073
  const canJoin = selectedTeam !== null && !isMutating && mutation.status !== "success" && !alreadyJoined;
5797
- const handleJoin = (0, import_react37.useCallback)(async () => {
6074
+ const handleJoin = (0, import_react40.useCallback)(async () => {
5798
6075
  if (!selectedTeam || !wallet.publicKey) return;
5799
6076
  try {
5800
6077
  await mutation.execute({
@@ -5854,13 +6131,15 @@ function JoinGameSheet({
5854
6131
  ] }) })
5855
6132
  ] })
5856
6133
  ] }),
5857
- !isCustomGame && !isPoolModeEnabled && !alreadyJoined && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.View, { style: styles15.section, children: [
5858
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [styles15.sectionLabel, { color: t.textSecondary }], children: "Pick Your Side" }),
5859
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.View, { style: styles15.teamsRow, children: [
6134
+ !isCustomGame && !isPoolModeEnabled && !alreadyJoined && (hasDrawOption ? (
6135
+ /* ── 3-way layout: Home / VS / Away / OR / Draw ── */
6136
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.View, { style: styles15.section, children: [
6137
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [styles15.sectionLabel, { color: t.textSecondary }], children: "Who will win?" }),
5860
6138
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5861
- TeamButton,
6139
+ PickRow,
5862
6140
  {
5863
6141
  name: homeName,
6142
+ subtitle: "Home Team",
5864
6143
  imageUrl: opponents[0]?.imageUrl,
5865
6144
  odds: homeOdds,
5866
6145
  bets: homeBets,
@@ -5874,10 +6153,16 @@ function JoinGameSheet({
5874
6153
  t
5875
6154
  }
5876
6155
  ),
6156
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.View, { style: styles15.dividerRow, children: [
6157
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.View, { style: [styles15.dividerLine, { backgroundColor: t.border }] }),
6158
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [styles15.dividerText, { color: t.textMuted }], children: "VS" }),
6159
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.View, { style: [styles15.dividerLine, { backgroundColor: t.border }] })
6160
+ ] }),
5877
6161
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5878
- TeamButton,
6162
+ PickRow,
5879
6163
  {
5880
6164
  name: awayName,
6165
+ subtitle: "Away Team",
5881
6166
  imageUrl: opponents[1]?.imageUrl,
5882
6167
  odds: awayOdds,
5883
6168
  bets: awayBets,
@@ -5890,24 +6175,71 @@ function JoinGameSheet({
5890
6175
  ImageComponent,
5891
6176
  t
5892
6177
  }
6178
+ ),
6179
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.View, { style: styles15.dividerRow, children: [
6180
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.View, { style: [styles15.dividerLine, { backgroundColor: t.border }] }),
6181
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [styles15.dividerText, { color: t.textMuted }], children: "OR" }),
6182
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.View, { style: [styles15.dividerLine, { backgroundColor: t.border }] })
6183
+ ] }),
6184
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6185
+ PickRow,
6186
+ {
6187
+ name: "Draw",
6188
+ subtitle: "Match ends in a tie",
6189
+ odds: drawOdds,
6190
+ bets: drawBets,
6191
+ color: drawColor,
6192
+ selected: selectedTeam === "draw",
6193
+ onPress: () => {
6194
+ setSelectedTeam("draw");
6195
+ onTeamSelect?.("draw");
6196
+ },
6197
+ t
6198
+ }
5893
6199
  )
5894
- ] }),
5895
- hasDrawOption && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.View, { style: styles15.drawRow, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5896
- TeamButton,
5897
- {
5898
- name: "Draw",
5899
- odds: drawOdds,
5900
- bets: drawBets,
5901
- color: drawColor,
5902
- selected: selectedTeam === "draw",
5903
- onPress: () => {
5904
- setSelectedTeam("draw");
5905
- onTeamSelect?.("draw");
5906
- },
5907
- t
5908
- }
5909
- ) })
5910
- ] }),
6200
+ ] })
6201
+ ) : (
6202
+ /* ── 2-way layout: side by side ── */
6203
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.View, { style: styles15.section, children: [
6204
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [styles15.sectionLabel, { color: t.textSecondary }], children: "Pick Your Side" }),
6205
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.View, { style: styles15.teamsRow, children: [
6206
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6207
+ TeamButton,
6208
+ {
6209
+ name: homeName,
6210
+ imageUrl: opponents[0]?.imageUrl,
6211
+ odds: homeOdds,
6212
+ bets: homeBets,
6213
+ color: homeColor,
6214
+ selected: selectedTeam === "home",
6215
+ onPress: () => {
6216
+ setSelectedTeam("home");
6217
+ onTeamSelect?.("home");
6218
+ },
6219
+ ImageComponent,
6220
+ t
6221
+ }
6222
+ ),
6223
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6224
+ TeamButton,
6225
+ {
6226
+ name: awayName,
6227
+ imageUrl: opponents[1]?.imageUrl,
6228
+ odds: awayOdds,
6229
+ bets: awayBets,
6230
+ color: awayColor,
6231
+ selected: selectedTeam === "away",
6232
+ onPress: () => {
6233
+ setSelectedTeam("away");
6234
+ onTeamSelect?.("away");
6235
+ },
6236
+ ImageComponent,
6237
+ t
6238
+ }
6239
+ )
6240
+ ] })
6241
+ ] })
6242
+ )),
5911
6243
  alreadyJoined && myBet && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.View, { style: [styles15.myBetCard, { backgroundColor: (myBet.team === "home" ? homeColor : myBet.team === "away" ? awayColor : drawColor) + "15", borderColor: myBet.team === "home" ? homeColor : myBet.team === "away" ? awayColor : drawColor }], children: [
5912
6244
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [styles15.myBetLabel, { color: myBet.team === "home" ? homeColor : myBet.team === "away" ? awayColor : drawColor }], children: "YOUR BET" }),
5913
6245
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [styles15.myBetTeam, { color: t.text }], children: myBet.team === "home" ? homeName : myBet.team === "away" ? awayName : "Draw" }),
@@ -5990,6 +6322,100 @@ function JoinGameSheet({
5990
6322
  }
5991
6323
  );
5992
6324
  }
6325
+ function PickRow({
6326
+ name,
6327
+ subtitle,
6328
+ imageUrl,
6329
+ odds,
6330
+ bets,
6331
+ color,
6332
+ selected,
6333
+ onPress,
6334
+ ImageComponent,
6335
+ t
6336
+ }) {
6337
+ const [imgFailed, setImgFailed] = (0, import_react40.useState)(false);
6338
+ const Img = ImageComponent || require("react-native").Image;
6339
+ const showImage = imageUrl && !imgFailed;
6340
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
6341
+ import_react_native21.TouchableOpacity,
6342
+ {
6343
+ style: [pickStyles.row, { borderColor: selected ? color : t.border, backgroundColor: selected ? color + "12" : t.background }],
6344
+ onPress,
6345
+ activeOpacity: 0.7,
6346
+ children: [
6347
+ showImage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Img, { source: { uri: imageUrl }, style: pickStyles.logo, resizeMode: "contain", onError: () => setImgFailed(true) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.View, { style: [pickStyles.logoPlaceholder, { backgroundColor: color + "20" }], children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [pickStyles.logoEmoji, { color }], children: name === "Draw" ? "\u{1F91D}" : name.charAt(0) }) }),
6348
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.View, { style: pickStyles.info, children: [
6349
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [pickStyles.name, { color: t.text }], children: name }),
6350
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [pickStyles.subtitle, { color: t.textMuted }], children: subtitle })
6351
+ ] }),
6352
+ odds !== "\u2014" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native21.Text, { style: [pickStyles.odds, { color }], children: [
6353
+ odds,
6354
+ "x"
6355
+ ] }),
6356
+ bets > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: [pickStyles.bets, { color: t.textMuted }], children: bets }),
6357
+ selected && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.View, { style: [pickStyles.check, { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native21.Text, { style: pickStyles.checkText, children: "\u2713" }) })
6358
+ ]
6359
+ }
6360
+ );
6361
+ }
6362
+ var pickStyles = import_react_native21.StyleSheet.create({
6363
+ row: {
6364
+ flexDirection: "row",
6365
+ alignItems: "center",
6366
+ borderWidth: 1.5,
6367
+ borderRadius: 14,
6368
+ paddingVertical: 12,
6369
+ paddingHorizontal: 14,
6370
+ gap: 12
6371
+ },
6372
+ logo: {
6373
+ width: 36,
6374
+ height: 36,
6375
+ borderRadius: 18
6376
+ },
6377
+ logoPlaceholder: {
6378
+ width: 36,
6379
+ height: 36,
6380
+ borderRadius: 18,
6381
+ alignItems: "center",
6382
+ justifyContent: "center"
6383
+ },
6384
+ logoEmoji: {
6385
+ fontSize: 16,
6386
+ fontWeight: "800"
6387
+ },
6388
+ info: {
6389
+ flex: 1
6390
+ },
6391
+ name: {
6392
+ fontSize: 15,
6393
+ fontWeight: "700"
6394
+ },
6395
+ subtitle: {
6396
+ fontSize: 12,
6397
+ marginTop: 1
6398
+ },
6399
+ odds: {
6400
+ fontSize: 16,
6401
+ fontWeight: "800"
6402
+ },
6403
+ bets: {
6404
+ fontSize: 12
6405
+ },
6406
+ check: {
6407
+ width: 22,
6408
+ height: 22,
6409
+ borderRadius: 11,
6410
+ alignItems: "center",
6411
+ justifyContent: "center"
6412
+ },
6413
+ checkText: {
6414
+ color: "#FFF",
6415
+ fontSize: 13,
6416
+ fontWeight: "800"
6417
+ }
6418
+ });
5993
6419
  var styles15 = import_react_native21.StyleSheet.create({
5994
6420
  overlay: {
5995
6421
  ...import_react_native21.StyleSheet.absoluteFillObject,
@@ -6112,8 +6538,22 @@ var styles15 = import_react_native21.StyleSheet.create({
6112
6538
  drawRow: {
6113
6539
  marginTop: 8
6114
6540
  },
6115
- summaryCard: {
6116
- marginTop: 20,
6541
+ dividerRow: {
6542
+ flexDirection: "row",
6543
+ alignItems: "center",
6544
+ gap: 12,
6545
+ marginVertical: 6
6546
+ },
6547
+ dividerLine: {
6548
+ flex: 1,
6549
+ height: 1
6550
+ },
6551
+ dividerText: {
6552
+ fontSize: 12,
6553
+ fontWeight: "700"
6554
+ },
6555
+ summaryCard: {
6556
+ marginTop: 20,
6117
6557
  borderRadius: 16,
6118
6558
  borderWidth: 1,
6119
6559
  overflow: "hidden"
@@ -6187,7 +6627,7 @@ var styles15 = import_react_native21.StyleSheet.create({
6187
6627
  });
6188
6628
 
6189
6629
  // src/ui/game/ClaimPrizeSheet.tsx
6190
- var import_react38 = require("react");
6630
+ var import_react41 = require("react");
6191
6631
  var import_react_native22 = require("react-native");
6192
6632
  var import_jsx_runtime19 = require("react/jsx-runtime");
6193
6633
  var STATUS_LABELS4 = {
@@ -6208,18 +6648,18 @@ function ClaimPrizeSheet({
6208
6648
  const t = useDubsTheme();
6209
6649
  const { wallet } = useDubs();
6210
6650
  const mutation = useClaim();
6211
- const overlayOpacity = (0, import_react38.useRef)(new import_react_native22.Animated.Value(0)).current;
6212
- const celebrationScale = (0, import_react38.useRef)(new import_react_native22.Animated.Value(0)).current;
6213
- const celebrationOpacity = (0, import_react38.useRef)(new import_react_native22.Animated.Value(0)).current;
6214
- const [showCelebration, setShowCelebration] = (0, import_react38.useState)(false);
6215
- (0, import_react38.useEffect)(() => {
6651
+ const overlayOpacity = (0, import_react41.useRef)(new import_react_native22.Animated.Value(0)).current;
6652
+ const celebrationScale = (0, import_react41.useRef)(new import_react_native22.Animated.Value(0)).current;
6653
+ const celebrationOpacity = (0, import_react41.useRef)(new import_react_native22.Animated.Value(0)).current;
6654
+ const [showCelebration, setShowCelebration] = (0, import_react41.useState)(false);
6655
+ (0, import_react41.useEffect)(() => {
6216
6656
  import_react_native22.Animated.timing(overlayOpacity, {
6217
6657
  toValue: visible ? 1 : 0,
6218
6658
  duration: 250,
6219
6659
  useNativeDriver: true
6220
6660
  }).start();
6221
6661
  }, [visible, overlayOpacity]);
6222
- (0, import_react38.useEffect)(() => {
6662
+ (0, import_react41.useEffect)(() => {
6223
6663
  if (visible) {
6224
6664
  mutation.reset();
6225
6665
  setShowCelebration(false);
@@ -6227,7 +6667,7 @@ function ClaimPrizeSheet({
6227
6667
  celebrationOpacity.setValue(0);
6228
6668
  }
6229
6669
  }, [visible]);
6230
- (0, import_react38.useEffect)(() => {
6670
+ (0, import_react41.useEffect)(() => {
6231
6671
  if (mutation.status === "success" && mutation.data) {
6232
6672
  setShowCelebration(true);
6233
6673
  import_react_native22.Animated.parallel([
@@ -6250,14 +6690,14 @@ function ClaimPrizeSheet({
6250
6690
  return () => clearTimeout(timer);
6251
6691
  }
6252
6692
  }, [mutation.status, mutation.data]);
6253
- (0, import_react38.useEffect)(() => {
6693
+ (0, import_react41.useEffect)(() => {
6254
6694
  if (mutation.status === "error" && mutation.error) {
6255
6695
  onError?.(mutation.error);
6256
6696
  }
6257
6697
  }, [mutation.status, mutation.error]);
6258
6698
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
6259
6699
  const canClaim = !isMutating && mutation.status !== "success" && !!wallet.publicKey;
6260
- const handleClaim = (0, import_react38.useCallback)(async () => {
6700
+ const handleClaim = (0, import_react41.useCallback)(async () => {
6261
6701
  if (!wallet.publicKey) return;
6262
6702
  try {
6263
6703
  await mutation.execute({
@@ -6490,7 +6930,7 @@ var styles16 = import_react_native22.StyleSheet.create({
6490
6930
  });
6491
6931
 
6492
6932
  // src/ui/game/ClaimButton.tsx
6493
- var import_react39 = require("react");
6933
+ var import_react42 = require("react");
6494
6934
  var import_react_native23 = require("react-native");
6495
6935
  var import_jsx_runtime20 = require("react/jsx-runtime");
6496
6936
  function ClaimButton({ gameId, style, onSuccess, onError }) {
@@ -6498,9 +6938,9 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
6498
6938
  const { wallet } = useDubs();
6499
6939
  const game = useGame(gameId);
6500
6940
  const claimStatus = useHasClaimed(gameId);
6501
- const [sheetVisible, setSheetVisible] = (0, import_react39.useState)(false);
6941
+ const [sheetVisible, setSheetVisible] = (0, import_react42.useState)(false);
6502
6942
  const walletAddress = wallet.publicKey?.toBase58() ?? null;
6503
- const myBet = (0, import_react39.useMemo)(() => {
6943
+ const myBet = (0, import_react42.useMemo)(() => {
6504
6944
  if (!walletAddress || !game.data?.bettors) return null;
6505
6945
  return game.data.bettors.find((b) => b.wallet === walletAddress) ?? null;
6506
6946
  }, [walletAddress, game.data?.bettors]);
@@ -6509,7 +6949,7 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
6509
6949
  const isWinner = isResolved && myBet != null && myBet.team === game.data?.winnerSide;
6510
6950
  const isEligible = myBet != null && isResolved && (isWinner || isRefund);
6511
6951
  const prizeAmount = isRefund ? myBet?.amount ?? 0 : game.data?.totalPool ?? 0;
6512
- const handleSuccess = (0, import_react39.useCallback)(
6952
+ const handleSuccess = (0, import_react42.useCallback)(
6513
6953
  (result) => {
6514
6954
  claimStatus.refetch();
6515
6955
  onSuccess?.(result);
@@ -6596,7 +7036,7 @@ var styles17 = import_react_native23.StyleSheet.create({
6596
7036
  });
6597
7037
 
6598
7038
  // src/ui/game/EnterArcadePoolSheet.tsx
6599
- var import_react40 = require("react");
7039
+ var import_react43 = require("react");
6600
7040
  var import_react_native24 = require("react-native");
6601
7041
  var import_jsx_runtime21 = require("react/jsx-runtime");
6602
7042
  var STATUS_LABELS5 = {
@@ -6617,20 +7057,20 @@ function EnterArcadePoolSheet({
6617
7057
  const t = useDubsTheme();
6618
7058
  const { wallet } = useDubs();
6619
7059
  const mutation = useEnterArcadePool();
6620
- const overlayOpacity = (0, import_react40.useRef)(new import_react_native24.Animated.Value(0)).current;
6621
- (0, import_react40.useEffect)(() => {
7060
+ const overlayOpacity = (0, import_react43.useRef)(new import_react_native24.Animated.Value(0)).current;
7061
+ (0, import_react43.useEffect)(() => {
6622
7062
  import_react_native24.Animated.timing(overlayOpacity, {
6623
7063
  toValue: visible ? 1 : 0,
6624
7064
  duration: 250,
6625
7065
  useNativeDriver: true
6626
7066
  }).start();
6627
7067
  }, [visible, overlayOpacity]);
6628
- (0, import_react40.useEffect)(() => {
7068
+ (0, import_react43.useEffect)(() => {
6629
7069
  if (visible) {
6630
7070
  mutation.reset();
6631
7071
  }
6632
7072
  }, [visible]);
6633
- (0, import_react40.useEffect)(() => {
7073
+ (0, import_react43.useEffect)(() => {
6634
7074
  if (mutation.status === "success" && mutation.data) {
6635
7075
  onSuccess?.(mutation.data);
6636
7076
  const timer = setTimeout(() => {
@@ -6639,7 +7079,7 @@ function EnterArcadePoolSheet({
6639
7079
  return () => clearTimeout(timer);
6640
7080
  }
6641
7081
  }, [mutation.status, mutation.data]);
6642
- (0, import_react40.useEffect)(() => {
7082
+ (0, import_react43.useEffect)(() => {
6643
7083
  if (mutation.status === "error" && mutation.error) {
6644
7084
  onError?.(mutation.error);
6645
7085
  }
@@ -6651,7 +7091,7 @@ function EnterArcadePoolSheet({
6651
7091
  const potSol = (pool.buy_in_lamports * Number(totalBuyIns) / 1e9).toFixed(4);
6652
7092
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
6653
7093
  const canJoin = !isMutating && mutation.status !== "success";
6654
- const handleJoin = (0, import_react40.useCallback)(async () => {
7094
+ const handleJoin = (0, import_react43.useCallback)(async () => {
6655
7095
  if (!wallet.publicKey) return;
6656
7096
  try {
6657
7097
  await mutation.execute(pool.id);
@@ -6802,7 +7242,7 @@ var styles18 = import_react_native24.StyleSheet.create({
6802
7242
  });
6803
7243
 
6804
7244
  // src/ui/game/ArcadeLeaderboardSheet.tsx
6805
- var import_react41 = require("react");
7245
+ var import_react44 = require("react");
6806
7246
  var import_react_native25 = require("react-native");
6807
7247
  var import_jsx_runtime22 = require("react/jsx-runtime");
6808
7248
  function RankLabel({ index }) {
@@ -6819,15 +7259,15 @@ function ArcadeLeaderboardSheet({
6819
7259
  }) {
6820
7260
  const t = useDubsTheme();
6821
7261
  const { pool, leaderboard, stats, loading, refetch } = useArcadePool(poolId);
6822
- const overlayOpacity = (0, import_react41.useRef)(new import_react_native25.Animated.Value(0)).current;
6823
- (0, import_react41.useEffect)(() => {
7262
+ const overlayOpacity = (0, import_react44.useRef)(new import_react_native25.Animated.Value(0)).current;
7263
+ (0, import_react44.useEffect)(() => {
6824
7264
  import_react_native25.Animated.timing(overlayOpacity, {
6825
7265
  toValue: visible ? 1 : 0,
6826
7266
  duration: 250,
6827
7267
  useNativeDriver: true
6828
7268
  }).start();
6829
7269
  }, [visible, overlayOpacity]);
6830
- (0, import_react41.useEffect)(() => {
7270
+ (0, import_react44.useEffect)(() => {
6831
7271
  if (visible) refetch();
6832
7272
  }, [visible]);
6833
7273
  const renderItem = ({ item, index }) => {
@@ -6974,7 +7414,7 @@ var styles19 = import_react_native25.StyleSheet.create({
6974
7414
  });
6975
7415
 
6976
7416
  // src/ui/game/CreateGameSheet.tsx
6977
- var import_react42 = require("react");
7417
+ var import_react45 = require("react");
6978
7418
  var import_react_native26 = require("react-native");
6979
7419
  var import_jsx_runtime23 = require("react/jsx-runtime");
6980
7420
  var STATUS_LABELS6 = {
@@ -7003,20 +7443,20 @@ function CreateGameSheet({
7003
7443
  const t = useDubsTheme();
7004
7444
  const { wallet } = useDubs();
7005
7445
  const mutation = useCreateGame();
7006
- const [selectedTeam, setSelectedTeam] = (0, import_react42.useState)(null);
7007
- const [wager, setWager] = (0, import_react42.useState)(0.01);
7008
- const [showSuccess, setShowSuccess] = (0, import_react42.useState)(false);
7009
- const overlayOpacity = (0, import_react42.useRef)(new import_react_native26.Animated.Value(0)).current;
7010
- const successScale = (0, import_react42.useRef)(new import_react_native26.Animated.Value(0)).current;
7011
- const successOpacity = (0, import_react42.useRef)(new import_react_native26.Animated.Value(0)).current;
7012
- (0, import_react42.useEffect)(() => {
7446
+ const [selectedTeam, setSelectedTeam] = (0, import_react45.useState)(null);
7447
+ const [wager, setWager] = (0, import_react45.useState)(0.01);
7448
+ const [showSuccess, setShowSuccess] = (0, import_react45.useState)(false);
7449
+ const overlayOpacity = (0, import_react45.useRef)(new import_react_native26.Animated.Value(0)).current;
7450
+ const successScale = (0, import_react45.useRef)(new import_react_native26.Animated.Value(0)).current;
7451
+ const successOpacity = (0, import_react45.useRef)(new import_react_native26.Animated.Value(0)).current;
7452
+ (0, import_react45.useEffect)(() => {
7013
7453
  import_react_native26.Animated.timing(overlayOpacity, {
7014
7454
  toValue: visible ? 1 : 0,
7015
7455
  duration: 250,
7016
7456
  useNativeDriver: true
7017
7457
  }).start();
7018
7458
  }, [visible]);
7019
- (0, import_react42.useEffect)(() => {
7459
+ (0, import_react45.useEffect)(() => {
7020
7460
  if (visible) {
7021
7461
  setSelectedTeam(null);
7022
7462
  setWager(0.01);
@@ -7026,7 +7466,7 @@ function CreateGameSheet({
7026
7466
  mutation.reset();
7027
7467
  }
7028
7468
  }, [visible]);
7029
- (0, import_react42.useEffect)(() => {
7469
+ (0, import_react45.useEffect)(() => {
7030
7470
  if (mutation.status === "success" && mutation.data) {
7031
7471
  setShowSuccess(true);
7032
7472
  onSuccess?.(mutation.data);
@@ -7043,7 +7483,7 @@ function CreateGameSheet({
7043
7483
  return () => clearTimeout(timer);
7044
7484
  }
7045
7485
  }, [mutation.status, mutation.data]);
7046
- (0, import_react42.useEffect)(() => {
7486
+ (0, import_react45.useEffect)(() => {
7047
7487
  if (mutation.status === "error" && mutation.error) {
7048
7488
  onError?.(mutation.error);
7049
7489
  }
@@ -7053,7 +7493,7 @@ function CreateGameSheet({
7053
7493
  const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
7054
7494
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
7055
7495
  const canCreate = selectedTeam !== null && !isMutating && mutation.status !== "success";
7056
- const handleCreate = (0, import_react42.useCallback)(async () => {
7496
+ const handleCreate = (0, import_react45.useCallback)(async () => {
7057
7497
  if (!selectedTeam || !wallet.publicKey) return;
7058
7498
  try {
7059
7499
  await mutation.execute({
@@ -7199,10 +7639,1483 @@ var styles20 = import_react_native26.StyleSheet.create({
7199
7639
  successTitle: { color: "#FFFFFF", fontSize: 28, fontWeight: "900" },
7200
7640
  successSub: { color: "#8E8E93", fontSize: 16 }
7201
7641
  });
7642
+
7643
+ // src/ui/jackpot/JackpotCard.tsx
7644
+ var import_react46 = require("react");
7645
+ var import_react_native27 = require("react-native");
7646
+ var import_jsx_runtime24 = require("react/jsx-runtime");
7647
+ function formatSOL(lamports) {
7648
+ const val = typeof lamports === "string" ? parseInt(lamports, 10) : lamports;
7649
+ if (isNaN(val) || val === 0) return "0";
7650
+ const sol = val / 1e9;
7651
+ if (sol >= 100) return sol.toFixed(0);
7652
+ if (sol >= 1) return sol.toFixed(2);
7653
+ if (sol >= 0.01) return sol.toFixed(3);
7654
+ return sol.toFixed(4);
7655
+ }
7656
+ function truncateWallet2(addr) {
7657
+ if (!addr || addr.length < 8) return addr || "";
7658
+ return `${addr.slice(0, 4)}...${addr.slice(-4)}`;
7659
+ }
7660
+ function JackpotCard({ round, lastWinner, entries, onPress, style }) {
7661
+ const shimmerAnim = (0, import_react46.useRef)(new import_react_native27.Animated.Value(-1)).current;
7662
+ const pulseAnim = (0, import_react46.useRef)(new import_react_native27.Animated.Value(0.4)).current;
7663
+ (0, import_react46.useEffect)(() => {
7664
+ const shimmer = import_react_native27.Animated.loop(
7665
+ import_react_native27.Animated.sequence([
7666
+ import_react_native27.Animated.timing(shimmerAnim, { toValue: 1, duration: 4e3, useNativeDriver: true }),
7667
+ import_react_native27.Animated.delay(500),
7668
+ import_react_native27.Animated.timing(shimmerAnim, { toValue: -1, duration: 0, useNativeDriver: true })
7669
+ ])
7670
+ );
7671
+ shimmer.start();
7672
+ const pulse = import_react_native27.Animated.loop(
7673
+ import_react_native27.Animated.sequence([
7674
+ import_react_native27.Animated.timing(pulseAnim, { toValue: 1, duration: 1e3, useNativeDriver: true }),
7675
+ import_react_native27.Animated.timing(pulseAnim, { toValue: 0.4, duration: 1e3, useNativeDriver: true })
7676
+ ])
7677
+ );
7678
+ pulse.start();
7679
+ return () => {
7680
+ shimmer.stop();
7681
+ pulse.stop();
7682
+ };
7683
+ }, [shimmerAnim, pulseAnim]);
7684
+ const potSol = round ? formatSOL(round.totalPotLamports) : "0";
7685
+ const isOpen = round?.status === "Open";
7686
+ const entryCount = round?.entryCount ?? 0;
7687
+ const totalWeight = round ? Number(BigInt(round.totalWeight || "0")) : 0;
7688
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
7689
+ import_react_native27.TouchableOpacity,
7690
+ {
7691
+ activeOpacity: 0.9,
7692
+ onPress,
7693
+ style: [styles21.card, style],
7694
+ children: [
7695
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.View, { style: styles21.gradientBg }),
7696
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7697
+ import_react_native27.Animated.View,
7698
+ {
7699
+ style: [
7700
+ styles21.shimmer,
7701
+ {
7702
+ transform: [{
7703
+ translateX: shimmerAnim.interpolate({
7704
+ inputRange: [-1, 1],
7705
+ outputRange: [-400, 400]
7706
+ })
7707
+ }]
7708
+ }
7709
+ ]
7710
+ }
7711
+ ),
7712
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.View, { style: styles21.accentBar }),
7713
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.content, children: [
7714
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.statusRow, children: [
7715
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: [styles21.statusBadge, isOpen ? styles21.statusOpen : styles21.statusClosed], children: [
7716
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Animated.View, { style: [styles21.statusDot, { opacity: pulseAnim }] }),
7717
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: [styles21.statusText, { color: isOpen ? "#22c55e" : "#9ca3af" }], children: isOpen ? "Open" : round?.status ?? "Loading" })
7718
+ ] }),
7719
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.Text, { style: styles21.entryCountText, children: [
7720
+ entryCount,
7721
+ " player",
7722
+ entryCount !== 1 ? "s" : ""
7723
+ ] })
7724
+ ] }),
7725
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.heroSection, children: [
7726
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.potInfo, children: [
7727
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.jackpotLabel, children: "JACKPOT" }),
7728
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.Text, { style: styles21.potValue, children: [
7729
+ potSol,
7730
+ " SOL"
7731
+ ] })
7732
+ ] }),
7733
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.potEmoji, children: "\u{1F911}" })
7734
+ ] }),
7735
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.infoGrid, children: [
7736
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.infoCard, children: [
7737
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.infoLabel, children: "PLAYERS" }),
7738
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.infoValue, children: entryCount })
7739
+ ] }),
7740
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.infoCard, children: [
7741
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.infoLabel, children: "TOTAL POT" }),
7742
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: [styles21.infoValue, { color: "#4ade80" }], children: potSol })
7743
+ ] }),
7744
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.infoCard, children: [
7745
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.infoLabel, children: "LAST WIN" }),
7746
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: [styles21.infoValue, { color: "#22c55e" }], children: lastWinner ? formatSOL(lastWinner.winAmount) : "\u2014" })
7747
+ ] })
7748
+ ] }),
7749
+ entries && entries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.playersSection, children: [
7750
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.playersSectionHeader, children: [
7751
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.playersSectionTitle, children: "Players in Round" }),
7752
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.View, { style: styles21.activeCountBadge, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.activeCountText, children: entries.length }) })
7753
+ ] }),
7754
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.playersCarousel, children: [
7755
+ entries.slice(0, 8).map((entry, i) => {
7756
+ const odds = entry.oddsPercent;
7757
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.View, { style: styles21.playerCard, children: [
7758
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.View, { style: styles21.playerAvatar, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.playerAvatarText, children: entry.player.slice(0, 2).toUpperCase() }) }),
7759
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.playerWallet, numberOfLines: 1, children: truncateWallet2(entry.player) }),
7760
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.Text, { style: styles21.playerWager, children: [
7761
+ entry.weightSol.toFixed(2),
7762
+ " SOL"
7763
+ ] }),
7764
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.Text, { style: styles21.playerOdds, children: [
7765
+ odds,
7766
+ "%"
7767
+ ] })
7768
+ ] }, `${entry.player}-${i}`);
7769
+ }),
7770
+ entries.length > 8 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.View, { style: styles21.playerCardMore, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native27.Text, { style: styles21.playerMoreText, children: [
7771
+ "+",
7772
+ entries.length - 8
7773
+ ] }) })
7774
+ ] })
7775
+ ] }),
7776
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7777
+ import_react_native27.TouchableOpacity,
7778
+ {
7779
+ style: styles21.placeBetButton,
7780
+ activeOpacity: 0.85,
7781
+ onPress,
7782
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native27.Text, { style: styles21.placeBetText, children: "Place Bet" })
7783
+ }
7784
+ )
7785
+ ] })
7786
+ ]
7787
+ }
7788
+ );
7789
+ }
7790
+ var styles21 = import_react_native27.StyleSheet.create({
7791
+ card: {
7792
+ borderRadius: 16,
7793
+ borderWidth: 1,
7794
+ borderColor: "rgba(34, 197, 94, 0.2)",
7795
+ backgroundColor: "#0c0c14",
7796
+ overflow: "hidden",
7797
+ position: "relative"
7798
+ },
7799
+ gradientBg: {
7800
+ ...import_react_native27.StyleSheet.absoluteFillObject,
7801
+ backgroundColor: "rgba(34, 197, 94, 0.04)"
7802
+ },
7803
+ shimmer: {
7804
+ position: "absolute",
7805
+ top: 0,
7806
+ bottom: 0,
7807
+ width: 120,
7808
+ backgroundColor: "rgba(34, 197, 94, 0.08)"
7809
+ },
7810
+ accentBar: {
7811
+ position: "absolute",
7812
+ bottom: 0,
7813
+ left: 0,
7814
+ right: "40%",
7815
+ height: 2,
7816
+ backgroundColor: "#22c55e"
7817
+ },
7818
+ content: {
7819
+ padding: 16,
7820
+ gap: 12
7821
+ },
7822
+ // Status row
7823
+ statusRow: {
7824
+ flexDirection: "row",
7825
+ alignItems: "center",
7826
+ gap: 8
7827
+ },
7828
+ statusBadge: {
7829
+ flexDirection: "row",
7830
+ alignItems: "center",
7831
+ gap: 6,
7832
+ paddingHorizontal: 10,
7833
+ paddingVertical: 4,
7834
+ borderRadius: 100
7835
+ },
7836
+ statusOpen: {
7837
+ backgroundColor: "rgba(34, 197, 94, 0.15)"
7838
+ },
7839
+ statusClosed: {
7840
+ backgroundColor: "rgba(156, 163, 175, 0.15)"
7841
+ },
7842
+ statusDot: {
7843
+ width: 6,
7844
+ height: 6,
7845
+ borderRadius: 3,
7846
+ backgroundColor: "#22c55e"
7847
+ },
7848
+ statusText: {
7849
+ fontSize: 12,
7850
+ fontWeight: "700"
7851
+ },
7852
+ entryCountText: {
7853
+ fontSize: 12,
7854
+ color: "#6b6b6b",
7855
+ fontWeight: "500"
7856
+ },
7857
+ // Hero pot
7858
+ heroSection: {
7859
+ flexDirection: "row",
7860
+ alignItems: "center",
7861
+ justifyContent: "space-between"
7862
+ },
7863
+ potInfo: {
7864
+ flex: 1
7865
+ },
7866
+ jackpotLabel: {
7867
+ fontSize: 10,
7868
+ fontWeight: "600",
7869
+ color: "#6b6b6b",
7870
+ letterSpacing: 3,
7871
+ textTransform: "uppercase",
7872
+ marginBottom: 4
7873
+ },
7874
+ potValue: {
7875
+ fontSize: 36,
7876
+ fontWeight: "900",
7877
+ color: "#4ade80",
7878
+ letterSpacing: -1
7879
+ },
7880
+ potEmoji: {
7881
+ fontSize: 40,
7882
+ opacity: 0.2
7883
+ },
7884
+ // Info grid
7885
+ infoGrid: {
7886
+ flexDirection: "row",
7887
+ gap: 8
7888
+ },
7889
+ infoCard: {
7890
+ flex: 1,
7891
+ borderRadius: 12,
7892
+ borderWidth: 1,
7893
+ borderColor: "#1e1e2a",
7894
+ backgroundColor: "#0c0c14",
7895
+ padding: 12
7896
+ },
7897
+ infoLabel: {
7898
+ fontSize: 9,
7899
+ fontWeight: "600",
7900
+ color: "#6b6b6b",
7901
+ letterSpacing: 2,
7902
+ textTransform: "uppercase",
7903
+ marginBottom: 4
7904
+ },
7905
+ infoValue: {
7906
+ fontSize: 18,
7907
+ fontWeight: "700",
7908
+ color: "#FFFFFF"
7909
+ },
7910
+ // Players section
7911
+ playersSection: {
7912
+ borderRadius: 12,
7913
+ borderWidth: 1,
7914
+ borderColor: "#1e1e2a",
7915
+ backgroundColor: "rgba(139, 92, 246, 0.04)",
7916
+ padding: 12,
7917
+ overflow: "hidden"
7918
+ },
7919
+ playersSectionHeader: {
7920
+ flexDirection: "row",
7921
+ alignItems: "center",
7922
+ justifyContent: "space-between",
7923
+ marginBottom: 10
7924
+ },
7925
+ playersSectionTitle: {
7926
+ fontSize: 13,
7927
+ fontWeight: "600",
7928
+ color: "#a0a0a0"
7929
+ },
7930
+ activeCountBadge: {
7931
+ backgroundColor: "rgba(34, 197, 94, 0.15)",
7932
+ paddingHorizontal: 8,
7933
+ paddingVertical: 2,
7934
+ borderRadius: 100
7935
+ },
7936
+ activeCountText: {
7937
+ fontSize: 11,
7938
+ fontWeight: "700",
7939
+ color: "#22c55e"
7940
+ },
7941
+ playersCarousel: {
7942
+ flexDirection: "row",
7943
+ gap: 10
7944
+ },
7945
+ playerCard: {
7946
+ width: 96,
7947
+ borderRadius: 12,
7948
+ borderWidth: 1.5,
7949
+ borderColor: "rgba(139, 92, 246, 0.4)",
7950
+ backgroundColor: "rgba(139, 92, 246, 0.08)",
7951
+ padding: 10,
7952
+ alignItems: "center",
7953
+ gap: 4
7954
+ },
7955
+ playerAvatar: {
7956
+ width: 40,
7957
+ height: 40,
7958
+ borderRadius: 20,
7959
+ borderWidth: 1.5,
7960
+ borderColor: "#8b5cf6",
7961
+ backgroundColor: "rgba(139, 92, 246, 0.2)",
7962
+ alignItems: "center",
7963
+ justifyContent: "center"
7964
+ },
7965
+ playerAvatarText: {
7966
+ fontSize: 14,
7967
+ fontWeight: "700",
7968
+ color: "#a78bfa"
7969
+ },
7970
+ playerWallet: {
7971
+ fontSize: 10,
7972
+ fontWeight: "500",
7973
+ color: "#a0a0a0",
7974
+ width: "100%",
7975
+ textAlign: "center"
7976
+ },
7977
+ playerWager: {
7978
+ fontSize: 12,
7979
+ fontWeight: "600",
7980
+ color: "#a78bfa"
7981
+ },
7982
+ playerOdds: {
7983
+ fontSize: 10,
7984
+ fontWeight: "700",
7985
+ color: "#22c55e"
7986
+ },
7987
+ playerCardMore: {
7988
+ width: 96,
7989
+ borderRadius: 12,
7990
+ borderWidth: 1.5,
7991
+ borderColor: "#1e1e2a",
7992
+ backgroundColor: "#14141e",
7993
+ alignItems: "center",
7994
+ justifyContent: "center"
7995
+ },
7996
+ playerMoreText: {
7997
+ fontSize: 16,
7998
+ fontWeight: "700",
7999
+ color: "#6b6b6b"
8000
+ },
8001
+ // Place bet CTA
8002
+ placeBetButton: {
8003
+ height: 52,
8004
+ borderRadius: 12,
8005
+ alignItems: "center",
8006
+ justifyContent: "center",
8007
+ backgroundColor: "#22c55e",
8008
+ shadowColor: "#22c55e",
8009
+ shadowOffset: { width: 0, height: 4 },
8010
+ shadowOpacity: 0.25,
8011
+ shadowRadius: 12,
8012
+ elevation: 6
8013
+ },
8014
+ placeBetText: {
8015
+ color: "#FFFFFF",
8016
+ fontSize: 16,
8017
+ fontWeight: "700"
8018
+ }
8019
+ });
8020
+
8021
+ // src/ui/jackpot/JackpotSheet.tsx
8022
+ var import_react47 = require("react");
8023
+ var import_react_native28 = require("react-native");
8024
+ var import_jsx_runtime25 = require("react/jsx-runtime");
8025
+ var STATUS_LABELS7 = {
8026
+ building: "Building transaction...",
8027
+ signing: "Approve in wallet...",
8028
+ confirming: "Confirming entry...",
8029
+ success: "You're in! \u{1F3C6}"
8030
+ };
8031
+ var QUICK_AMOUNTS = [0.1, 0.5, 1];
8032
+ function formatSOL2(lamports) {
8033
+ const val = typeof lamports === "string" ? parseInt(lamports, 10) : lamports;
8034
+ if (isNaN(val) || val === 0) return "0";
8035
+ const sol = val / 1e9;
8036
+ if (sol >= 100) return sol.toFixed(0);
8037
+ if (sol >= 1) return sol.toFixed(2);
8038
+ if (sol >= 0.01) return sol.toFixed(3);
8039
+ return sol.toFixed(4);
8040
+ }
8041
+ function truncateWallet3(addr) {
8042
+ if (!addr || addr.length < 8) return addr || "";
8043
+ return `${addr.slice(0, 4)}...${addr.slice(-4)}`;
8044
+ }
8045
+ function JackpotSheet({
8046
+ visible,
8047
+ onDismiss,
8048
+ onSuccess,
8049
+ onError,
8050
+ minEntry = 0.01,
8051
+ maxEntry = 10
8052
+ }) {
8053
+ const t = useDubsTheme();
8054
+ const { wallet, client } = useDubs();
8055
+ const { round, lastWinner, refetch } = useJackpot();
8056
+ const mutation = useEnterJackpot();
8057
+ const [betAmount, setBetAmount] = (0, import_react47.useState)("0.1");
8058
+ const [entries, setEntries] = (0, import_react47.useState)([]);
8059
+ const overlayOpacity = (0, import_react47.useRef)(new import_react_native28.Animated.Value(0)).current;
8060
+ (0, import_react47.useEffect)(() => {
8061
+ import_react_native28.Animated.timing(overlayOpacity, {
8062
+ toValue: visible ? 1 : 0,
8063
+ duration: 250,
8064
+ useNativeDriver: true
8065
+ }).start();
8066
+ }, [visible, overlayOpacity]);
8067
+ (0, import_react47.useEffect)(() => {
8068
+ if (visible) {
8069
+ mutation.reset();
8070
+ setBetAmount("0.1");
8071
+ refetch();
8072
+ client.getJackpotEntries().then((res) => setEntries(res.entries)).catch(() => {
8073
+ });
8074
+ }
8075
+ }, [visible]);
8076
+ (0, import_react47.useEffect)(() => {
8077
+ if (mutation.status === "success" && mutation.data) {
8078
+ onSuccess?.(mutation.data);
8079
+ refetch();
8080
+ client.getJackpotEntries().then((res) => setEntries(res.entries)).catch(() => {
8081
+ });
8082
+ const timer = setTimeout(() => onDismiss(), 2500);
8083
+ return () => clearTimeout(timer);
8084
+ }
8085
+ }, [mutation.status, mutation.data]);
8086
+ (0, import_react47.useEffect)(() => {
8087
+ if (mutation.status === "error" && mutation.error) {
8088
+ onError?.(mutation.error);
8089
+ }
8090
+ }, [mutation.status, mutation.error]);
8091
+ const potSol = round ? Number(BigInt(round.totalPotLamports || "0")) / 1e9 : 0;
8092
+ const totalWeight = round ? Number(BigInt(round.totalWeight || "0")) : 0;
8093
+ const betSol = parseFloat(betAmount) || 0;
8094
+ const entryLamports = Math.round(betSol * 1e9);
8095
+ const userOdds = totalWeight > 0 ? (entryLamports / (totalWeight + entryLamports) * 100).toFixed(1) : entries.length === 0 ? "100.0" : "0.0";
8096
+ const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
8097
+ const canEnter = !isMutating && mutation.status !== "success" && round?.status === "Open" && betSol >= minEntry;
8098
+ const handleQuickAdd = (0, import_react47.useCallback)((amount) => {
8099
+ setBetAmount((prev) => {
8100
+ const current = parseFloat(prev) || 0;
8101
+ const next = Math.min(current + amount, maxEntry);
8102
+ return next.toFixed(2);
8103
+ });
8104
+ }, [maxEntry]);
8105
+ const handleEnter = (0, import_react47.useCallback)(async () => {
8106
+ if (!wallet.publicKey || entryLamports < 1e4) return;
8107
+ try {
8108
+ await mutation.execute(entryLamports);
8109
+ } catch {
8110
+ }
8111
+ }, [wallet.publicKey, mutation.execute, entryLamports]);
8112
+ const statusLabel = STATUS_LABELS7[mutation.status] || "";
8113
+ const renderPlayerCard = ({ item, index }) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.playerCard, children: [
8114
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.playerAvatar, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.playerAvatarText, children: item.player.slice(0, 2).toUpperCase() }) }),
8115
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.Text, { style: styles22.playerUsername, numberOfLines: 1, children: [
8116
+ "@",
8117
+ truncateWallet3(item.player)
8118
+ ] }),
8119
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.playerWagerRow, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.Text, { style: styles22.playerWagerAmount, children: [
8120
+ item.weightSol.toFixed(2),
8121
+ " SOL"
8122
+ ] }) }),
8123
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.Text, { style: styles22.playerOdds, children: [
8124
+ item.oddsPercent,
8125
+ "%"
8126
+ ] })
8127
+ ] });
8128
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
8129
+ import_react_native28.Modal,
8130
+ {
8131
+ visible,
8132
+ animationType: "slide",
8133
+ transparent: true,
8134
+ onRequestClose: onDismiss,
8135
+ children: [
8136
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Animated.View, { style: [styles22.overlay, { opacity: overlayOpacity }], children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.TouchableOpacity, { style: styles22.overlayTap, activeOpacity: 1, onPress: onDismiss }) }),
8137
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.sheetPositioner, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.sheet, children: [
8138
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.handleRow, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.handle }) }),
8139
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
8140
+ import_react_native28.ScrollView,
8141
+ {
8142
+ style: styles22.scrollView,
8143
+ contentContainerStyle: styles22.scrollContent,
8144
+ showsVerticalScrollIndicator: false,
8145
+ bounces: true,
8146
+ children: [
8147
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.header, children: [
8148
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.headerTitle, children: "Jackpot" }),
8149
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.TouchableOpacity, { onPress: onDismiss, activeOpacity: 0.8, style: styles22.closeBtn, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.closeBtnText, children: "\u2715" }) })
8150
+ ] }),
8151
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.heroCard, children: [
8152
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.heroGradient }),
8153
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.heroLabel, children: "JACKPOT" }),
8154
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.heroPotRow, children: [
8155
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.Text, { style: styles22.heroPotValue, children: [
8156
+ potSol.toFixed(4),
8157
+ " SOL"
8158
+ ] }),
8159
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.heroEmoji, children: "\u{1F911}" })
8160
+ ] }),
8161
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.heroAccentBar })
8162
+ ] }),
8163
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.infoRow, children: [
8164
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.infoCard, children: [
8165
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.infoCardLabel, children: "YOUR WAGER" }),
8166
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.infoCardValue, children: betSol.toFixed(2) })
8167
+ ] }),
8168
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.infoCard, children: [
8169
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.infoCardLabel, children: "YOUR CHANCE" }),
8170
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.Text, { style: [styles22.infoCardValue, { color: "#22c55e" }], children: [
8171
+ userOdds,
8172
+ "%"
8173
+ ] })
8174
+ ] }),
8175
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.infoCard, children: [
8176
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.infoCardLabel, children: "PLAYERS" }),
8177
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.infoCardValue, children: entries.length })
8178
+ ] })
8179
+ ] }),
8180
+ entries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.playersSection, children: [
8181
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.playersSectionHeader, children: [
8182
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.playersSectionTitle, children: "Players in Round" }),
8183
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.playersBadge, children: [
8184
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.playersBadgeDot }),
8185
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.Text, { style: styles22.playersBadgeText, children: [
8186
+ entries.length,
8187
+ " active"
8188
+ ] })
8189
+ ] })
8190
+ ] }),
8191
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8192
+ import_react_native28.FlatList,
8193
+ {
8194
+ data: entries,
8195
+ renderItem: renderPlayerCard,
8196
+ keyExtractor: (item, i) => `${item.player}-${i}`,
8197
+ horizontal: true,
8198
+ showsHorizontalScrollIndicator: false,
8199
+ contentContainerStyle: styles22.playersListContent,
8200
+ ItemSeparatorComponent: () => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: { width: 10 } })
8201
+ }
8202
+ )
8203
+ ] }),
8204
+ entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.emptyState, children: [
8205
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.emptyEmoji, children: "\u{1F911}" }),
8206
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.emptyTitle, children: "No players yet" }),
8207
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.emptySubtitle, children: "Be the first to join!" })
8208
+ ] }),
8209
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.betSection, children: [
8210
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.betLabel, children: "Bet Amount" }),
8211
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.betInputRow, children: [
8212
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.solIcon, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.solIconText, children: "\u25CE" }) }),
8213
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8214
+ import_react_native28.TextInput,
8215
+ {
8216
+ style: styles22.betInput,
8217
+ value: betAmount,
8218
+ onChangeText: setBetAmount,
8219
+ keyboardType: "decimal-pad",
8220
+ placeholder: "0.00",
8221
+ placeholderTextColor: "#6b6b6b",
8222
+ selectTextOnFocus: true
8223
+ }
8224
+ ),
8225
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.betInputSuffix, children: "SOL" })
8226
+ ] }),
8227
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.quickBetRow, children: QUICK_AMOUNTS.map((amount) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8228
+ import_react_native28.TouchableOpacity,
8229
+ {
8230
+ style: styles22.quickBetBtn,
8231
+ onPress: () => handleQuickAdd(amount),
8232
+ activeOpacity: 0.7,
8233
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.Text, { style: styles22.quickBetText, children: [
8234
+ "+",
8235
+ amount,
8236
+ " SOL"
8237
+ ] })
8238
+ },
8239
+ amount
8240
+ )) })
8241
+ ] }),
8242
+ mutation.error && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.View, { style: styles22.errorBox, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.errorText, children: mutation.error.message }) }),
8243
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8244
+ import_react_native28.TouchableOpacity,
8245
+ {
8246
+ style: [
8247
+ styles22.placeBetBtn,
8248
+ !canEnter && styles22.placeBetBtnDisabled,
8249
+ mutation.status === "success" && styles22.placeBetBtnSuccess
8250
+ ],
8251
+ disabled: !canEnter,
8252
+ onPress: handleEnter,
8253
+ activeOpacity: 0.85,
8254
+ children: isMutating ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.placeBetLoading, children: [
8255
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.ActivityIndicator, { size: "small", color: "#FFFFFF" }),
8256
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.placeBetText, children: statusLabel })
8257
+ ] }) : mutation.status === "success" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.placeBetText, children: "You're in! \u{1F3C6}" }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.Text, { style: [styles22.placeBetText, !canEnter && { opacity: 0.5 }], children: [
8258
+ "Place Bet \u2014 ",
8259
+ betSol.toFixed(2),
8260
+ " SOL"
8261
+ ] })
8262
+ }
8263
+ ),
8264
+ lastWinner && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.lastWinnerSection, children: [
8265
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.lastWinnerLabel, children: "Last Winner" }),
8266
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.View, { style: styles22.lastWinnerRow, children: [
8267
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native28.Text, { style: styles22.lastWinnerWallet, children: truncateWallet3(lastWinner.winner) }),
8268
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native28.Text, { style: styles22.lastWinnerAmount, children: [
8269
+ "won ",
8270
+ formatSOL2(lastWinner.winAmount),
8271
+ " SOL"
8272
+ ] })
8273
+ ] })
8274
+ ] })
8275
+ ]
8276
+ }
8277
+ )
8278
+ ] }) })
8279
+ ]
8280
+ }
8281
+ );
8282
+ }
8283
+ var styles22 = import_react_native28.StyleSheet.create({
8284
+ overlay: {
8285
+ ...import_react_native28.StyleSheet.absoluteFillObject,
8286
+ backgroundColor: "rgba(0,0,0,0.65)"
8287
+ },
8288
+ overlayTap: { flex: 1 },
8289
+ sheetPositioner: {
8290
+ flex: 1,
8291
+ justifyContent: "flex-end"
8292
+ },
8293
+ sheet: {
8294
+ backgroundColor: "#08080e",
8295
+ borderTopLeftRadius: 24,
8296
+ borderTopRightRadius: 24,
8297
+ maxHeight: "92%",
8298
+ borderWidth: 1,
8299
+ borderColor: "#1e1e2a",
8300
+ borderBottomWidth: 0
8301
+ },
8302
+ handleRow: { alignItems: "center", paddingTop: 10, paddingBottom: 4 },
8303
+ handle: { width: 36, height: 4, borderRadius: 2, backgroundColor: "#2a2a3a" },
8304
+ scrollView: { flexGrow: 0 },
8305
+ scrollContent: {
8306
+ paddingHorizontal: 16,
8307
+ paddingBottom: import_react_native28.Platform.OS === "ios" ? 40 : 24
8308
+ },
8309
+ // Header
8310
+ header: {
8311
+ flexDirection: "row",
8312
+ alignItems: "center",
8313
+ justifyContent: "space-between",
8314
+ paddingVertical: 12
8315
+ },
8316
+ headerTitle: { fontSize: 20, fontWeight: "700", color: "#FFFFFF" },
8317
+ closeBtn: { padding: 4 },
8318
+ closeBtnText: { fontSize: 20, color: "#6b6b6b" },
8319
+ // Hero pot card
8320
+ heroCard: {
8321
+ borderRadius: 16,
8322
+ borderWidth: 1,
8323
+ borderColor: "rgba(34, 197, 94, 0.2)",
8324
+ padding: 16,
8325
+ overflow: "hidden",
8326
+ position: "relative"
8327
+ },
8328
+ heroGradient: {
8329
+ ...import_react_native28.StyleSheet.absoluteFillObject,
8330
+ backgroundColor: "rgba(34, 197, 94, 0.04)"
8331
+ },
8332
+ heroLabel: {
8333
+ fontSize: 10,
8334
+ fontWeight: "600",
8335
+ color: "#6b6b6b",
8336
+ letterSpacing: 3,
8337
+ marginBottom: 4
8338
+ },
8339
+ heroPotRow: {
8340
+ flexDirection: "row",
8341
+ alignItems: "center",
8342
+ justifyContent: "space-between"
8343
+ },
8344
+ heroPotValue: {
8345
+ fontSize: 32,
8346
+ fontWeight: "900",
8347
+ color: "#4ade80",
8348
+ letterSpacing: -1
8349
+ },
8350
+ heroEmoji: {
8351
+ fontSize: 36,
8352
+ opacity: 0.2
8353
+ },
8354
+ heroAccentBar: {
8355
+ position: "absolute",
8356
+ bottom: 0,
8357
+ left: 0,
8358
+ width: "60%",
8359
+ height: 2,
8360
+ backgroundColor: "#22c55e"
8361
+ },
8362
+ // Info row
8363
+ infoRow: {
8364
+ flexDirection: "row",
8365
+ gap: 8,
8366
+ marginTop: 12
8367
+ },
8368
+ infoCard: {
8369
+ flex: 1,
8370
+ borderRadius: 12,
8371
+ borderWidth: 1,
8372
+ borderColor: "#1e1e2a",
8373
+ backgroundColor: "#0c0c14",
8374
+ padding: 12
8375
+ },
8376
+ infoCardLabel: {
8377
+ fontSize: 9,
8378
+ fontWeight: "600",
8379
+ color: "#6b6b6b",
8380
+ letterSpacing: 2,
8381
+ marginBottom: 4
8382
+ },
8383
+ infoCardValue: {
8384
+ fontSize: 18,
8385
+ fontWeight: "700",
8386
+ color: "#FFFFFF"
8387
+ },
8388
+ // Players section
8389
+ playersSection: {
8390
+ marginTop: 16,
8391
+ borderRadius: 16,
8392
+ borderWidth: 1,
8393
+ borderColor: "#1e1e2a",
8394
+ backgroundColor: "rgba(139, 92, 246, 0.03)",
8395
+ padding: 12,
8396
+ overflow: "hidden"
8397
+ },
8398
+ playersSectionHeader: {
8399
+ flexDirection: "row",
8400
+ alignItems: "center",
8401
+ justifyContent: "space-between",
8402
+ marginBottom: 12
8403
+ },
8404
+ playersSectionTitle: {
8405
+ fontSize: 13,
8406
+ fontWeight: "600",
8407
+ color: "#a0a0a0"
8408
+ },
8409
+ playersBadge: {
8410
+ flexDirection: "row",
8411
+ alignItems: "center",
8412
+ gap: 6,
8413
+ backgroundColor: "rgba(34, 197, 94, 0.15)",
8414
+ paddingHorizontal: 8,
8415
+ paddingVertical: 3,
8416
+ borderRadius: 100
8417
+ },
8418
+ playersBadgeDot: {
8419
+ width: 6,
8420
+ height: 6,
8421
+ borderRadius: 3,
8422
+ backgroundColor: "#22c55e"
8423
+ },
8424
+ playersBadgeText: {
8425
+ fontSize: 11,
8426
+ fontWeight: "700",
8427
+ color: "#22c55e"
8428
+ },
8429
+ playersListContent: {
8430
+ paddingRight: 4
8431
+ },
8432
+ // Player cards (carousel items)
8433
+ playerCard: {
8434
+ width: 110,
8435
+ borderRadius: 12,
8436
+ borderWidth: 1.5,
8437
+ borderColor: "rgba(139, 92, 246, 0.4)",
8438
+ backgroundColor: "rgba(139, 92, 246, 0.08)",
8439
+ padding: 12,
8440
+ alignItems: "center",
8441
+ gap: 6
8442
+ },
8443
+ playerAvatar: {
8444
+ width: 48,
8445
+ height: 48,
8446
+ borderRadius: 24,
8447
+ borderWidth: 2,
8448
+ borderColor: "#8b5cf6",
8449
+ backgroundColor: "rgba(139, 92, 246, 0.15)",
8450
+ alignItems: "center",
8451
+ justifyContent: "center"
8452
+ },
8453
+ playerAvatarText: {
8454
+ fontSize: 16,
8455
+ fontWeight: "700",
8456
+ color: "#a78bfa"
8457
+ },
8458
+ playerUsername: {
8459
+ fontSize: 11,
8460
+ fontWeight: "500",
8461
+ color: "#a0a0a0",
8462
+ textAlign: "center"
8463
+ },
8464
+ playerWagerRow: {
8465
+ flexDirection: "row",
8466
+ alignItems: "center",
8467
+ gap: 4
8468
+ },
8469
+ playerWagerAmount: {
8470
+ fontSize: 13,
8471
+ fontWeight: "600",
8472
+ color: "#a78bfa"
8473
+ },
8474
+ playerOdds: {
8475
+ fontSize: 11,
8476
+ fontWeight: "700",
8477
+ color: "#22c55e"
8478
+ },
8479
+ // Empty state
8480
+ emptyState: {
8481
+ marginTop: 16,
8482
+ alignItems: "center",
8483
+ paddingVertical: 24,
8484
+ borderRadius: 16,
8485
+ borderWidth: 1,
8486
+ borderColor: "#1e1e2a",
8487
+ backgroundColor: "#0c0c14"
8488
+ },
8489
+ emptyEmoji: { fontSize: 40, marginBottom: 8 },
8490
+ emptyTitle: { fontSize: 16, fontWeight: "600", color: "#FFFFFF" },
8491
+ emptySubtitle: { fontSize: 13, color: "#6b6b6b", marginTop: 4 },
8492
+ // Bet section
8493
+ betSection: {
8494
+ marginTop: 16
8495
+ },
8496
+ betLabel: {
8497
+ fontSize: 13,
8498
+ fontWeight: "500",
8499
+ color: "#6b6b6b",
8500
+ marginBottom: 8
8501
+ },
8502
+ betInputRow: {
8503
+ flexDirection: "row",
8504
+ alignItems: "center",
8505
+ gap: 8,
8506
+ backgroundColor: "#08080e",
8507
+ borderWidth: 1,
8508
+ borderColor: "#2a2a3a",
8509
+ borderRadius: 12,
8510
+ paddingHorizontal: 14,
8511
+ paddingVertical: import_react_native28.Platform.OS === "ios" ? 14 : 10
8512
+ },
8513
+ solIcon: {
8514
+ width: 32,
8515
+ height: 32,
8516
+ borderRadius: 16,
8517
+ backgroundColor: "rgba(139, 92, 246, 0.15)",
8518
+ alignItems: "center",
8519
+ justifyContent: "center"
8520
+ },
8521
+ solIconText: {
8522
+ fontSize: 18,
8523
+ color: "#a78bfa",
8524
+ fontWeight: "700"
8525
+ },
8526
+ betInput: {
8527
+ flex: 1,
8528
+ fontSize: 24,
8529
+ fontWeight: "700",
8530
+ color: "#FFFFFF",
8531
+ padding: 0
8532
+ },
8533
+ betInputSuffix: {
8534
+ fontSize: 14,
8535
+ fontWeight: "500",
8536
+ color: "#6b6b6b"
8537
+ },
8538
+ quickBetRow: {
8539
+ flexDirection: "row",
8540
+ gap: 8,
8541
+ marginTop: 10
8542
+ },
8543
+ quickBetBtn: {
8544
+ flex: 1,
8545
+ paddingVertical: 12,
8546
+ borderRadius: 10,
8547
+ borderWidth: 1,
8548
+ borderColor: "#2a2a3a",
8549
+ backgroundColor: "#08080e",
8550
+ alignItems: "center"
8551
+ },
8552
+ quickBetText: {
8553
+ fontSize: 13,
8554
+ fontWeight: "600",
8555
+ color: "#FFFFFF"
8556
+ },
8557
+ // Error
8558
+ errorBox: {
8559
+ marginTop: 12,
8560
+ borderRadius: 12,
8561
+ borderWidth: 1,
8562
+ borderColor: "#3A1515",
8563
+ backgroundColor: "#1A0A0A",
8564
+ padding: 12
8565
+ },
8566
+ errorText: { fontSize: 13, fontWeight: "500", color: "#F87171" },
8567
+ // Place Bet CTA
8568
+ placeBetBtn: {
8569
+ marginTop: 16,
8570
+ height: 56,
8571
+ borderRadius: 14,
8572
+ justifyContent: "center",
8573
+ alignItems: "center",
8574
+ backgroundColor: "#22c55e",
8575
+ shadowColor: "#22c55e",
8576
+ shadowOffset: { width: 0, height: 4 },
8577
+ shadowOpacity: 0.25,
8578
+ shadowRadius: 12,
8579
+ elevation: 6
8580
+ },
8581
+ placeBetBtnDisabled: {
8582
+ backgroundColor: "#1e1e2a",
8583
+ shadowOpacity: 0,
8584
+ elevation: 0
8585
+ },
8586
+ placeBetBtnSuccess: {
8587
+ backgroundColor: "#16a34a"
8588
+ },
8589
+ placeBetText: { color: "#FFFFFF", fontSize: 16, fontWeight: "700" },
8590
+ placeBetLoading: { flexDirection: "row", alignItems: "center", gap: 10 },
8591
+ // Last winner
8592
+ lastWinnerSection: {
8593
+ marginTop: 14,
8594
+ paddingTop: 14,
8595
+ borderTopWidth: 1,
8596
+ borderTopColor: "#1e1e2a"
8597
+ },
8598
+ lastWinnerLabel: {
8599
+ fontSize: 11,
8600
+ fontWeight: "600",
8601
+ color: "#6b6b6b",
8602
+ letterSpacing: 1,
8603
+ textTransform: "uppercase",
8604
+ marginBottom: 4
8605
+ },
8606
+ lastWinnerRow: {
8607
+ flexDirection: "row",
8608
+ alignItems: "center",
8609
+ gap: 6
8610
+ },
8611
+ lastWinnerWallet: {
8612
+ fontSize: 13,
8613
+ fontWeight: "500",
8614
+ color: "#a0a0a0"
8615
+ },
8616
+ lastWinnerAmount: {
8617
+ fontSize: 13,
8618
+ fontWeight: "600",
8619
+ color: "#22c55e"
8620
+ }
8621
+ });
8622
+
8623
+ // src/ui/jackpot/JackpotWidget.tsx
8624
+ var import_react48 = require("react");
8625
+ var import_jsx_runtime26 = require("react/jsx-runtime");
8626
+ function JackpotWidget({
8627
+ style,
8628
+ minEntry,
8629
+ maxEntry,
8630
+ onEntry,
8631
+ onError
8632
+ }) {
8633
+ const [sheetVisible, setSheetVisible] = (0, import_react48.useState)(false);
8634
+ const { round, lastWinner } = useJackpot();
8635
+ const { client } = useDubs();
8636
+ const [entries, setEntries] = (0, import_react48.useState)([]);
8637
+ (0, import_react48.useEffect)(() => {
8638
+ client.getJackpotEntries().then((res) => setEntries(res.entries)).catch(() => {
8639
+ });
8640
+ }, [client, round?.entryCount]);
8641
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
8642
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
8643
+ JackpotCard,
8644
+ {
8645
+ round,
8646
+ lastWinner,
8647
+ entries,
8648
+ onPress: () => setSheetVisible(true),
8649
+ style
8650
+ }
8651
+ ),
8652
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
8653
+ JackpotSheet,
8654
+ {
8655
+ visible: sheetVisible,
8656
+ onDismiss: () => setSheetVisible(false),
8657
+ onSuccess: (result) => {
8658
+ onEntry?.(result);
8659
+ client.getJackpotEntries().then((res) => setEntries(res.entries)).catch(() => {
8660
+ });
8661
+ },
8662
+ onError,
8663
+ minEntry,
8664
+ maxEntry
8665
+ }
8666
+ )
8667
+ ] });
8668
+ }
8669
+
8670
+ // src/chat/provider.tsx
8671
+ var import_react49 = require("react");
8672
+ var import_react_native29 = require("react-native");
8673
+
8674
+ // src/chat/socket.ts
8675
+ var import_socket = require("socket.io-client");
8676
+ var ChatSocket = class {
8677
+ constructor() {
8678
+ this.socket = null;
8679
+ this.listeners = {};
8680
+ }
8681
+ /** Set event listeners. Call before or after connect. */
8682
+ setListeners(listeners) {
8683
+ this.listeners = listeners;
8684
+ }
8685
+ /** Connect to the /chat namespace */
8686
+ connect(config) {
8687
+ if (this.socket?.connected) {
8688
+ console.log("[Dubs:ChatSocket] Already connected");
8689
+ return;
8690
+ }
8691
+ this.listeners.onConnectionChange?.("connecting");
8692
+ console.log(`[Dubs:ChatSocket] Connecting to ${config.host}/chat`);
8693
+ this.socket = (0, import_socket.io)(`${config.host}/chat`, {
8694
+ auth: { token: config.token },
8695
+ transports: ["websocket"],
8696
+ reconnection: true,
8697
+ reconnectionDelay: 1e3,
8698
+ reconnectionAttempts: 10
8699
+ });
8700
+ this.socket.on("connect", () => {
8701
+ console.log("[Dubs:ChatSocket] Connected");
8702
+ this.listeners.onConnectionChange?.("connected");
8703
+ });
8704
+ this.socket.on("disconnect", (reason) => {
8705
+ console.log("[Dubs:ChatSocket] Disconnected:", reason);
8706
+ this.listeners.onConnectionChange?.("disconnected");
8707
+ });
8708
+ this.socket.on("connect_error", (error) => {
8709
+ console.error("[Dubs:ChatSocket] Connection error:", error.message);
8710
+ this.listeners.onConnectionChange?.("error");
8711
+ });
8712
+ this.socket.on("new_message", (msg) => this.listeners.onNewMessage?.(msg));
8713
+ this.socket.on("online_users", (users) => this.listeners.onOnlineUsers?.(users));
8714
+ this.socket.on("online_count", (count) => this.listeners.onOnlineCount?.(count));
8715
+ this.socket.on("user_typing", (data) => this.listeners.onTyping?.(data));
8716
+ this.socket.on("reaction_added", (data) => this.listeners.onReactionAdded?.(data));
8717
+ this.socket.on("reaction_removed", (data) => this.listeners.onReactionRemoved?.(data));
8718
+ this.socket.on("notification", (n) => this.listeners.onNotification?.(n));
8719
+ this.socket.on("unread_count", (count) => this.listeners.onUnreadCount?.(count));
8720
+ this.socket.on("dm:new_message", (msg) => this.listeners.onDMNewMessage?.(msg));
8721
+ this.socket.on("dm:message_sent", (msg) => this.listeners.onDMMessageSent?.(msg));
8722
+ this.socket.on("dm:notification", (data) => this.listeners.onDMNotification?.(data));
8723
+ this.socket.on("dm:messages_read", (data) => this.listeners.onDMMessagesRead?.(data));
8724
+ this.socket.on("friend_request_accepted", (data) => this.listeners.onFriendRequestAccepted?.(data));
8725
+ this.socket.on("friend_request_declined", (data) => this.listeners.onFriendRequestDeclined?.(data));
8726
+ this.socket.on("friend_removed", (data) => this.listeners.onFriendRemoved?.(data));
8727
+ this.socket.on("error", (err) => this.listeners.onError?.(err));
8728
+ }
8729
+ /** Disconnect from the chat namespace */
8730
+ disconnect() {
8731
+ if (this.socket) {
8732
+ console.log("[Dubs:ChatSocket] Disconnecting");
8733
+ this.socket.removeAllListeners();
8734
+ this.socket.disconnect();
8735
+ this.socket = null;
8736
+ }
8737
+ }
8738
+ /** Whether the socket is currently connected */
8739
+ isConnected() {
8740
+ return this.socket?.connected ?? false;
8741
+ }
8742
+ // ── Global Chat Actions ──
8743
+ /** Send a message to global chat */
8744
+ sendMessage(params) {
8745
+ this.socket?.emit("send_message", params);
8746
+ }
8747
+ /** Emit typing indicator */
8748
+ sendTyping(isTyping) {
8749
+ this.socket?.emit("typing", isTyping);
8750
+ }
8751
+ /** Add an emoji reaction to a message */
8752
+ addReaction(messageId, reaction) {
8753
+ this.socket?.emit("add_reaction", { messageId, reaction });
8754
+ }
8755
+ /** Remove an emoji reaction from a message */
8756
+ removeReaction(messageId, reaction) {
8757
+ this.socket?.emit("remove_reaction", { messageId, reaction });
8758
+ }
8759
+ // ── DM Actions ──
8760
+ /** Join a DM room to receive messages in real-time */
8761
+ joinDM(recipientWallet) {
8762
+ this.socket?.emit("dm:join", { recipientWallet });
8763
+ }
8764
+ /** Leave a DM room */
8765
+ leaveDM(recipientWallet) {
8766
+ this.socket?.emit("dm:leave", { recipientWallet });
8767
+ }
8768
+ /** Send a direct message via socket */
8769
+ sendDM(params) {
8770
+ this.socket?.emit("dm:send", params);
8771
+ }
8772
+ /** Mark DMs from a sender as read */
8773
+ markDMRead(senderWallet) {
8774
+ this.socket?.emit("dm:mark_read", { senderWallet });
8775
+ }
8776
+ };
8777
+
8778
+ // src/chat/provider.tsx
8779
+ var import_jsx_runtime27 = require("react/jsx-runtime");
8780
+ var ChatContext = (0, import_react49.createContext)(null);
8781
+ function ChatProvider({ children, autoConnect = true }) {
8782
+ const { client } = useDubs();
8783
+ const socketRef = (0, import_react49.useRef)(new ChatSocket());
8784
+ const [status, setStatus] = (0, import_react49.useState)("disconnected");
8785
+ const [messages, setMessages] = (0, import_react49.useState)([]);
8786
+ const [onlineUsers, setOnlineUsers] = (0, import_react49.useState)([]);
8787
+ const [onlineCount, setOnlineCount] = (0, import_react49.useState)(0);
8788
+ const [unreadCount, setUnreadCount] = (0, import_react49.useState)(0);
8789
+ const [conversations, setConversations] = (0, import_react49.useState)([]);
8790
+ const [friends, setFriends] = (0, import_react49.useState)([]);
8791
+ const [pendingRequests, setPendingRequests] = (0, import_react49.useState)([]);
8792
+ const refreshMessages = (0, import_react49.useCallback)(async () => {
8793
+ try {
8794
+ const res = await client.getChatMessages({ limit: 30 });
8795
+ setMessages(res.messages);
8796
+ } catch (err) {
8797
+ console.error("[Dubs:ChatProvider] Failed to load messages:", err);
8798
+ }
8799
+ }, [client]);
8800
+ const refreshConversations = (0, import_react49.useCallback)(async () => {
8801
+ try {
8802
+ const res = await client.getConversations();
8803
+ setConversations(res.conversations);
8804
+ } catch (_) {
8805
+ }
8806
+ }, [client]);
8807
+ const refreshFriends = (0, import_react49.useCallback)(async () => {
8808
+ try {
8809
+ const res = await client.getFriends();
8810
+ setFriends(res.friends);
8811
+ } catch (_) {
8812
+ }
8813
+ }, [client]);
8814
+ const refreshPendingRequests = (0, import_react49.useCallback)(async () => {
8815
+ try {
8816
+ const res = await client.getPendingFriendRequests();
8817
+ setPendingRequests(res.requests);
8818
+ } catch (_) {
8819
+ }
8820
+ }, [client]);
8821
+ (0, import_react49.useEffect)(() => {
8822
+ const token = client.getToken();
8823
+ if (!autoConnect || !token) return;
8824
+ const chatSocket = socketRef.current;
8825
+ const baseUrl = client.baseUrl;
8826
+ const host = new URL(baseUrl).origin;
8827
+ chatSocket.setListeners({
8828
+ onConnectionChange: setStatus,
8829
+ // Global chat
8830
+ onNewMessage: (msg) => {
8831
+ setMessages((prev) => {
8832
+ if (prev.some((m) => m.id === msg.id)) return prev;
8833
+ return [msg, ...prev];
8834
+ });
8835
+ },
8836
+ onOnlineUsers: setOnlineUsers,
8837
+ onOnlineCount: setOnlineCount,
8838
+ onUnreadCount: setUnreadCount,
8839
+ // Notifications trigger conversation refresh
8840
+ onDMNotification: () => {
8841
+ refreshConversations();
8842
+ },
8843
+ onNotification: (n) => {
8844
+ setUnreadCount((prev) => prev + 1);
8845
+ if (n.type === "friend_request") refreshPendingRequests();
8846
+ if (n.type === "friend_request_accepted") refreshFriends();
8847
+ },
8848
+ onFriendRequestAccepted: () => refreshFriends(),
8849
+ onFriendRemoved: () => refreshFriends()
8850
+ });
8851
+ chatSocket.connect({ host, token });
8852
+ refreshMessages();
8853
+ refreshFriends().catch(() => {
8854
+ });
8855
+ refreshPendingRequests().catch(() => {
8856
+ });
8857
+ return () => {
8858
+ chatSocket.disconnect();
8859
+ };
8860
+ }, [client, autoConnect, refreshMessages, refreshConversations, refreshFriends, refreshPendingRequests]);
8861
+ (0, import_react49.useEffect)(() => {
8862
+ const handleAppState = (nextState) => {
8863
+ if (nextState === "active") {
8864
+ const chatSocket = socketRef.current;
8865
+ if (!chatSocket.isConnected()) {
8866
+ const token = client.getToken();
8867
+ if (token) {
8868
+ const baseUrl = client.baseUrl;
8869
+ const host = new URL(baseUrl).origin;
8870
+ chatSocket.connect({ host, token });
8871
+ }
8872
+ }
8873
+ refreshMessages();
8874
+ }
8875
+ };
8876
+ const sub = import_react_native29.AppState.addEventListener("change", handleAppState);
8877
+ return () => sub.remove();
8878
+ }, [client, refreshMessages, refreshConversations]);
8879
+ const value = (0, import_react49.useMemo)(
8880
+ () => ({
8881
+ socket: socketRef.current,
8882
+ status,
8883
+ messages,
8884
+ onlineUsers,
8885
+ onlineCount,
8886
+ unreadCount,
8887
+ conversations,
8888
+ friends,
8889
+ pendingRequests,
8890
+ refreshMessages,
8891
+ refreshConversations,
8892
+ refreshFriends,
8893
+ refreshPendingRequests
8894
+ }),
8895
+ [status, messages, onlineUsers, onlineCount, unreadCount, conversations, friends, pendingRequests, refreshMessages, refreshConversations, refreshFriends, refreshPendingRequests]
8896
+ );
8897
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ChatContext.Provider, { value, children });
8898
+ }
8899
+ function useChatContext() {
8900
+ const ctx = (0, import_react49.useContext)(ChatContext);
8901
+ if (!ctx) {
8902
+ throw new Error("useChatContext must be used inside a <ChatProvider>");
8903
+ }
8904
+ return ctx;
8905
+ }
8906
+
8907
+ // src/chat/hooks.ts
8908
+ var import_react50 = require("react");
8909
+ function useChatStatus() {
8910
+ return useChatContext().status;
8911
+ }
8912
+ function useChatMessages() {
8913
+ const { messages, refreshMessages } = useChatContext();
8914
+ const [loading, setLoading] = (0, import_react50.useState)(false);
8915
+ const refetch = (0, import_react50.useCallback)(async () => {
8916
+ setLoading(true);
8917
+ await refreshMessages();
8918
+ setLoading(false);
8919
+ }, [refreshMessages]);
8920
+ return { messages, loading, refetch };
8921
+ }
8922
+ function useSendMessage() {
8923
+ const { socket } = useChatContext();
8924
+ const { client } = useDubs();
8925
+ const send = (0, import_react50.useCallback)(
8926
+ (params) => {
8927
+ socket.sendMessage(params);
8928
+ },
8929
+ [socket]
8930
+ );
8931
+ const sendViaREST = (0, import_react50.useCallback)(
8932
+ async (params) => {
8933
+ await client.sendChatMessage(params);
8934
+ },
8935
+ [client]
8936
+ );
8937
+ return { send, sendViaREST };
8938
+ }
8939
+ function useOnlineUsers() {
8940
+ const { onlineUsers, onlineCount } = useChatContext();
8941
+ return { users: onlineUsers, count: onlineCount };
8942
+ }
8943
+ function useUnreadCount() {
8944
+ return useChatContext().unreadCount;
8945
+ }
8946
+ function useConversations() {
8947
+ const { conversations, refreshConversations } = useChatContext();
8948
+ const [loading, setLoading] = (0, import_react50.useState)(false);
8949
+ const refetch = (0, import_react50.useCallback)(async () => {
8950
+ setLoading(true);
8951
+ await refreshConversations();
8952
+ setLoading(false);
8953
+ }, [refreshConversations]);
8954
+ return { conversations, loading, refetch };
8955
+ }
8956
+ function useDirectMessages(recipientWallet) {
8957
+ const { client } = useDubs();
8958
+ const { socket, refreshConversations } = useChatContext();
8959
+ const [messages, setMessages] = (0, import_react50.useState)([]);
8960
+ const [otherUser, setOtherUser] = (0, import_react50.useState)(null);
8961
+ const [loading, setLoading] = (0, import_react50.useState)(true);
8962
+ const refetch = (0, import_react50.useCallback)(async () => {
8963
+ try {
8964
+ setLoading(true);
8965
+ const res = await client.getConversation(recipientWallet);
8966
+ setMessages(res.messages);
8967
+ setOtherUser(res.otherUser);
8968
+ } catch (err) {
8969
+ console.error("[Dubs:useDirectMessages] Error loading:", err);
8970
+ } finally {
8971
+ setLoading(false);
8972
+ }
8973
+ }, [client, recipientWallet]);
8974
+ (0, import_react50.useEffect)(() => {
8975
+ refetch();
8976
+ socket.joinDM(recipientWallet);
8977
+ return () => {
8978
+ socket.leaveDM(recipientWallet);
8979
+ };
8980
+ }, [recipientWallet, refetch, socket]);
8981
+ const socketRef = (0, import_react50.useRef)(socket);
8982
+ socketRef.current = socket;
8983
+ (0, import_react50.useEffect)(() => {
8984
+ const currentSocket = socketRef.current;
8985
+ const prevListeners = currentSocket.listeners;
8986
+ const originalOnDMNew = prevListeners?.onDMNewMessage;
8987
+ currentSocket.setListeners({
8988
+ ...prevListeners,
8989
+ onDMNewMessage: (msg) => {
8990
+ originalOnDMNew?.(msg);
8991
+ if (msg.senderWallet === recipientWallet || msg.isOwn) {
8992
+ setMessages((prev) => {
8993
+ if (prev.some((m) => m.id === msg.id)) return prev;
8994
+ return [...prev, msg];
8995
+ });
8996
+ }
8997
+ },
8998
+ onDMMessageSent: (msg) => {
8999
+ setMessages((prev) => {
9000
+ if (prev.some((m) => m.id === msg.id)) return prev;
9001
+ return [...prev, { ...msg, isOwn: true }];
9002
+ });
9003
+ }
9004
+ });
9005
+ }, [recipientWallet]);
9006
+ const send = (0, import_react50.useCallback)(
9007
+ (message) => {
9008
+ socket.sendDM({ recipientWallet, message });
9009
+ },
9010
+ [socket, recipientWallet]
9011
+ );
9012
+ const sendViaREST = (0, import_react50.useCallback)(
9013
+ async (message) => {
9014
+ await client.sendDirectMessage({ recipientWallet, message });
9015
+ await refetch();
9016
+ await refreshConversations();
9017
+ },
9018
+ [client, recipientWallet, refetch, refreshConversations]
9019
+ );
9020
+ const markRead = (0, import_react50.useCallback)(() => {
9021
+ socket.markDMRead(recipientWallet);
9022
+ }, [socket, recipientWallet]);
9023
+ return { messages, loading, otherUser, send, sendViaREST, markRead, refetch };
9024
+ }
9025
+ function useFriends() {
9026
+ const { friends, refreshFriends } = useChatContext();
9027
+ const [loading, setLoading] = (0, import_react50.useState)(false);
9028
+ const refetch = (0, import_react50.useCallback)(async () => {
9029
+ setLoading(true);
9030
+ await refreshFriends();
9031
+ setLoading(false);
9032
+ }, [refreshFriends]);
9033
+ return { friends, loading, refetch };
9034
+ }
9035
+ function useFriendRequests() {
9036
+ const { pendingRequests, refreshPendingRequests } = useChatContext();
9037
+ const [loading, setLoading] = (0, import_react50.useState)(false);
9038
+ const refetch = (0, import_react50.useCallback)(async () => {
9039
+ setLoading(true);
9040
+ await refreshPendingRequests();
9041
+ setLoading(false);
9042
+ }, [refreshPendingRequests]);
9043
+ return { requests: pendingRequests, loading, refetch };
9044
+ }
9045
+ function useSearchUsers() {
9046
+ const { client } = useDubs();
9047
+ const [results, setResults] = (0, import_react50.useState)([]);
9048
+ const [loading, setLoading] = (0, import_react50.useState)(false);
9049
+ const search = (0, import_react50.useCallback)(
9050
+ async (query) => {
9051
+ setLoading(true);
9052
+ try {
9053
+ const res = await client.searchUsers(query);
9054
+ setResults(res.results);
9055
+ } catch (err) {
9056
+ console.error("[Dubs:useSearchUsers] Error:", err);
9057
+ } finally {
9058
+ setLoading(false);
9059
+ }
9060
+ },
9061
+ [client]
9062
+ );
9063
+ const clear = (0, import_react50.useCallback)(() => setResults([]), []);
9064
+ return { results, loading, search, clear };
9065
+ }
9066
+ function useSendFriendRequest() {
9067
+ const { client } = useDubs();
9068
+ const { refreshPendingRequests } = useChatContext();
9069
+ const [loading, setLoading] = (0, import_react50.useState)(false);
9070
+ const send = (0, import_react50.useCallback)(
9071
+ async (targetUserId) => {
9072
+ setLoading(true);
9073
+ try {
9074
+ await client.sendFriendRequest(targetUserId);
9075
+ } finally {
9076
+ setLoading(false);
9077
+ }
9078
+ },
9079
+ [client, refreshPendingRequests]
9080
+ );
9081
+ return { send, loading };
9082
+ }
9083
+ function useRespondToFriendRequest() {
9084
+ const { client } = useDubs();
9085
+ const { refreshFriends, refreshPendingRequests } = useChatContext();
9086
+ const [loading, setLoading] = (0, import_react50.useState)(false);
9087
+ const accept = (0, import_react50.useCallback)(
9088
+ async (requestId) => {
9089
+ setLoading(true);
9090
+ try {
9091
+ await client.acceptFriendRequest(requestId);
9092
+ await Promise.all([refreshFriends(), refreshPendingRequests()]);
9093
+ } finally {
9094
+ setLoading(false);
9095
+ }
9096
+ },
9097
+ [client, refreshFriends, refreshPendingRequests]
9098
+ );
9099
+ const reject = (0, import_react50.useCallback)(
9100
+ async (requestId) => {
9101
+ setLoading(true);
9102
+ try {
9103
+ await client.rejectFriendRequest(requestId);
9104
+ await refreshPendingRequests();
9105
+ } finally {
9106
+ setLoading(false);
9107
+ }
9108
+ },
9109
+ [client, refreshPendingRequests]
9110
+ );
9111
+ return { accept, reject, loading };
9112
+ }
7202
9113
  // Annotate the CommonJS export names for ESM import in node:
7203
9114
  0 && (module.exports = {
7204
9115
  ArcadeLeaderboardSheet,
7205
9116
  AuthGate,
9117
+ ChatProvider,
9118
+ ChatSocket,
7206
9119
  ClaimButton,
7207
9120
  ClaimPrizeSheet,
7208
9121
  ConnectWalletButton,
@@ -7216,6 +9129,9 @@ var styles20 = import_react_native26.StyleSheet.create({
7216
9129
  DubsProvider,
7217
9130
  EnterArcadePoolSheet,
7218
9131
  GamePoster,
9132
+ JackpotCard,
9133
+ JackpotSheet,
9134
+ JackpotWidget,
7219
9135
  JoinGameButton,
7220
9136
  JoinGameSheet,
7221
9137
  LivePoolsCard,
@@ -7244,22 +9160,38 @@ var styles20 = import_react_native26.StyleSheet.create({
7244
9160
  useArcadePool,
7245
9161
  useArcadePools,
7246
9162
  useAuth,
9163
+ useChatContext,
9164
+ useChatMessages,
9165
+ useChatStatus,
7247
9166
  useClaim,
9167
+ useConversations,
7248
9168
  useCreateCustomGame,
7249
9169
  useCreateGame,
9170
+ useDirectMessages,
7250
9171
  useDubs,
7251
9172
  useDubsTheme,
7252
9173
  useEnterArcadePool,
9174
+ useEnterJackpot,
7253
9175
  useEvents,
9176
+ useFriendRequests,
9177
+ useFriends,
7254
9178
  useGame,
7255
9179
  useGames,
7256
9180
  useHasClaimed,
7257
9181
  useHighlights,
9182
+ useJackpot,
9183
+ useJackpotHistory,
7258
9184
  useJoinGame,
7259
9185
  useNetworkGames,
9186
+ useOnlineUsers,
7260
9187
  usePushNotifications,
9188
+ useRespondToFriendRequest,
9189
+ useSearchUsers,
9190
+ useSendFriendRequest,
9191
+ useSendMessage,
7261
9192
  useShorts,
7262
9193
  useUFCFightCard,
7263
- useUFCFighterDetail
9194
+ useUFCFighterDetail,
9195
+ useUnreadCount
7264
9196
  });
7265
9197
  //# sourceMappingURL=index.js.map