@dubsdotapp/expo 0.5.17 → 0.5.19

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({
@@ -6057,7 +6334,7 @@ function PickRow({
6057
6334
  ImageComponent,
6058
6335
  t
6059
6336
  }) {
6060
- const [imgFailed, setImgFailed] = (0, import_react37.useState)(false);
6337
+ const [imgFailed, setImgFailed] = (0, import_react40.useState)(false);
6061
6338
  const Img = ImageComponent || require("react-native").Image;
6062
6339
  const showImage = imageUrl && !imgFailed;
6063
6340
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
@@ -6350,7 +6627,7 @@ var styles15 = import_react_native21.StyleSheet.create({
6350
6627
  });
6351
6628
 
6352
6629
  // src/ui/game/ClaimPrizeSheet.tsx
6353
- var import_react38 = require("react");
6630
+ var import_react41 = require("react");
6354
6631
  var import_react_native22 = require("react-native");
6355
6632
  var import_jsx_runtime19 = require("react/jsx-runtime");
6356
6633
  var STATUS_LABELS4 = {
@@ -6371,18 +6648,18 @@ function ClaimPrizeSheet({
6371
6648
  const t = useDubsTheme();
6372
6649
  const { wallet } = useDubs();
6373
6650
  const mutation = useClaim();
6374
- const overlayOpacity = (0, import_react38.useRef)(new import_react_native22.Animated.Value(0)).current;
6375
- const celebrationScale = (0, import_react38.useRef)(new import_react_native22.Animated.Value(0)).current;
6376
- const celebrationOpacity = (0, import_react38.useRef)(new import_react_native22.Animated.Value(0)).current;
6377
- const [showCelebration, setShowCelebration] = (0, import_react38.useState)(false);
6378
- (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)(() => {
6379
6656
  import_react_native22.Animated.timing(overlayOpacity, {
6380
6657
  toValue: visible ? 1 : 0,
6381
6658
  duration: 250,
6382
6659
  useNativeDriver: true
6383
6660
  }).start();
6384
6661
  }, [visible, overlayOpacity]);
6385
- (0, import_react38.useEffect)(() => {
6662
+ (0, import_react41.useEffect)(() => {
6386
6663
  if (visible) {
6387
6664
  mutation.reset();
6388
6665
  setShowCelebration(false);
@@ -6390,7 +6667,7 @@ function ClaimPrizeSheet({
6390
6667
  celebrationOpacity.setValue(0);
6391
6668
  }
6392
6669
  }, [visible]);
6393
- (0, import_react38.useEffect)(() => {
6670
+ (0, import_react41.useEffect)(() => {
6394
6671
  if (mutation.status === "success" && mutation.data) {
6395
6672
  setShowCelebration(true);
6396
6673
  import_react_native22.Animated.parallel([
@@ -6413,14 +6690,14 @@ function ClaimPrizeSheet({
6413
6690
  return () => clearTimeout(timer);
6414
6691
  }
6415
6692
  }, [mutation.status, mutation.data]);
6416
- (0, import_react38.useEffect)(() => {
6693
+ (0, import_react41.useEffect)(() => {
6417
6694
  if (mutation.status === "error" && mutation.error) {
6418
6695
  onError?.(mutation.error);
6419
6696
  }
6420
6697
  }, [mutation.status, mutation.error]);
6421
6698
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
6422
6699
  const canClaim = !isMutating && mutation.status !== "success" && !!wallet.publicKey;
6423
- const handleClaim = (0, import_react38.useCallback)(async () => {
6700
+ const handleClaim = (0, import_react41.useCallback)(async () => {
6424
6701
  if (!wallet.publicKey) return;
6425
6702
  try {
6426
6703
  await mutation.execute({
@@ -6653,7 +6930,7 @@ var styles16 = import_react_native22.StyleSheet.create({
6653
6930
  });
6654
6931
 
6655
6932
  // src/ui/game/ClaimButton.tsx
6656
- var import_react39 = require("react");
6933
+ var import_react42 = require("react");
6657
6934
  var import_react_native23 = require("react-native");
6658
6935
  var import_jsx_runtime20 = require("react/jsx-runtime");
6659
6936
  function ClaimButton({ gameId, style, onSuccess, onError }) {
@@ -6661,9 +6938,9 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
6661
6938
  const { wallet } = useDubs();
6662
6939
  const game = useGame(gameId);
6663
6940
  const claimStatus = useHasClaimed(gameId);
6664
- const [sheetVisible, setSheetVisible] = (0, import_react39.useState)(false);
6941
+ const [sheetVisible, setSheetVisible] = (0, import_react42.useState)(false);
6665
6942
  const walletAddress = wallet.publicKey?.toBase58() ?? null;
6666
- const myBet = (0, import_react39.useMemo)(() => {
6943
+ const myBet = (0, import_react42.useMemo)(() => {
6667
6944
  if (!walletAddress || !game.data?.bettors) return null;
6668
6945
  return game.data.bettors.find((b) => b.wallet === walletAddress) ?? null;
6669
6946
  }, [walletAddress, game.data?.bettors]);
@@ -6672,7 +6949,7 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
6672
6949
  const isWinner = isResolved && myBet != null && myBet.team === game.data?.winnerSide;
6673
6950
  const isEligible = myBet != null && isResolved && (isWinner || isRefund);
6674
6951
  const prizeAmount = isRefund ? myBet?.amount ?? 0 : game.data?.totalPool ?? 0;
6675
- const handleSuccess = (0, import_react39.useCallback)(
6952
+ const handleSuccess = (0, import_react42.useCallback)(
6676
6953
  (result) => {
6677
6954
  claimStatus.refetch();
6678
6955
  onSuccess?.(result);
@@ -6759,7 +7036,7 @@ var styles17 = import_react_native23.StyleSheet.create({
6759
7036
  });
6760
7037
 
6761
7038
  // src/ui/game/EnterArcadePoolSheet.tsx
6762
- var import_react40 = require("react");
7039
+ var import_react43 = require("react");
6763
7040
  var import_react_native24 = require("react-native");
6764
7041
  var import_jsx_runtime21 = require("react/jsx-runtime");
6765
7042
  var STATUS_LABELS5 = {
@@ -6780,20 +7057,20 @@ function EnterArcadePoolSheet({
6780
7057
  const t = useDubsTheme();
6781
7058
  const { wallet } = useDubs();
6782
7059
  const mutation = useEnterArcadePool();
6783
- const overlayOpacity = (0, import_react40.useRef)(new import_react_native24.Animated.Value(0)).current;
6784
- (0, import_react40.useEffect)(() => {
7060
+ const overlayOpacity = (0, import_react43.useRef)(new import_react_native24.Animated.Value(0)).current;
7061
+ (0, import_react43.useEffect)(() => {
6785
7062
  import_react_native24.Animated.timing(overlayOpacity, {
6786
7063
  toValue: visible ? 1 : 0,
6787
7064
  duration: 250,
6788
7065
  useNativeDriver: true
6789
7066
  }).start();
6790
7067
  }, [visible, overlayOpacity]);
6791
- (0, import_react40.useEffect)(() => {
7068
+ (0, import_react43.useEffect)(() => {
6792
7069
  if (visible) {
6793
7070
  mutation.reset();
6794
7071
  }
6795
7072
  }, [visible]);
6796
- (0, import_react40.useEffect)(() => {
7073
+ (0, import_react43.useEffect)(() => {
6797
7074
  if (mutation.status === "success" && mutation.data) {
6798
7075
  onSuccess?.(mutation.data);
6799
7076
  const timer = setTimeout(() => {
@@ -6802,7 +7079,7 @@ function EnterArcadePoolSheet({
6802
7079
  return () => clearTimeout(timer);
6803
7080
  }
6804
7081
  }, [mutation.status, mutation.data]);
6805
- (0, import_react40.useEffect)(() => {
7082
+ (0, import_react43.useEffect)(() => {
6806
7083
  if (mutation.status === "error" && mutation.error) {
6807
7084
  onError?.(mutation.error);
6808
7085
  }
@@ -6814,7 +7091,7 @@ function EnterArcadePoolSheet({
6814
7091
  const potSol = (pool.buy_in_lamports * Number(totalBuyIns) / 1e9).toFixed(4);
6815
7092
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
6816
7093
  const canJoin = !isMutating && mutation.status !== "success";
6817
- const handleJoin = (0, import_react40.useCallback)(async () => {
7094
+ const handleJoin = (0, import_react43.useCallback)(async () => {
6818
7095
  if (!wallet.publicKey) return;
6819
7096
  try {
6820
7097
  await mutation.execute(pool.id);
@@ -6965,7 +7242,7 @@ var styles18 = import_react_native24.StyleSheet.create({
6965
7242
  });
6966
7243
 
6967
7244
  // src/ui/game/ArcadeLeaderboardSheet.tsx
6968
- var import_react41 = require("react");
7245
+ var import_react44 = require("react");
6969
7246
  var import_react_native25 = require("react-native");
6970
7247
  var import_jsx_runtime22 = require("react/jsx-runtime");
6971
7248
  function RankLabel({ index }) {
@@ -6982,15 +7259,15 @@ function ArcadeLeaderboardSheet({
6982
7259
  }) {
6983
7260
  const t = useDubsTheme();
6984
7261
  const { pool, leaderboard, stats, loading, refetch } = useArcadePool(poolId);
6985
- const overlayOpacity = (0, import_react41.useRef)(new import_react_native25.Animated.Value(0)).current;
6986
- (0, import_react41.useEffect)(() => {
7262
+ const overlayOpacity = (0, import_react44.useRef)(new import_react_native25.Animated.Value(0)).current;
7263
+ (0, import_react44.useEffect)(() => {
6987
7264
  import_react_native25.Animated.timing(overlayOpacity, {
6988
7265
  toValue: visible ? 1 : 0,
6989
7266
  duration: 250,
6990
7267
  useNativeDriver: true
6991
7268
  }).start();
6992
7269
  }, [visible, overlayOpacity]);
6993
- (0, import_react41.useEffect)(() => {
7270
+ (0, import_react44.useEffect)(() => {
6994
7271
  if (visible) refetch();
6995
7272
  }, [visible]);
6996
7273
  const renderItem = ({ item, index }) => {
@@ -7137,7 +7414,7 @@ var styles19 = import_react_native25.StyleSheet.create({
7137
7414
  });
7138
7415
 
7139
7416
  // src/ui/game/CreateGameSheet.tsx
7140
- var import_react42 = require("react");
7417
+ var import_react45 = require("react");
7141
7418
  var import_react_native26 = require("react-native");
7142
7419
  var import_jsx_runtime23 = require("react/jsx-runtime");
7143
7420
  var STATUS_LABELS6 = {
@@ -7166,20 +7443,20 @@ function CreateGameSheet({
7166
7443
  const t = useDubsTheme();
7167
7444
  const { wallet } = useDubs();
7168
7445
  const mutation = useCreateGame();
7169
- const [selectedTeam, setSelectedTeam] = (0, import_react42.useState)(null);
7170
- const [wager, setWager] = (0, import_react42.useState)(0.01);
7171
- const [showSuccess, setShowSuccess] = (0, import_react42.useState)(false);
7172
- const overlayOpacity = (0, import_react42.useRef)(new import_react_native26.Animated.Value(0)).current;
7173
- const successScale = (0, import_react42.useRef)(new import_react_native26.Animated.Value(0)).current;
7174
- const successOpacity = (0, import_react42.useRef)(new import_react_native26.Animated.Value(0)).current;
7175
- (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)(() => {
7176
7453
  import_react_native26.Animated.timing(overlayOpacity, {
7177
7454
  toValue: visible ? 1 : 0,
7178
7455
  duration: 250,
7179
7456
  useNativeDriver: true
7180
7457
  }).start();
7181
7458
  }, [visible]);
7182
- (0, import_react42.useEffect)(() => {
7459
+ (0, import_react45.useEffect)(() => {
7183
7460
  if (visible) {
7184
7461
  setSelectedTeam(null);
7185
7462
  setWager(0.01);
@@ -7189,7 +7466,7 @@ function CreateGameSheet({
7189
7466
  mutation.reset();
7190
7467
  }
7191
7468
  }, [visible]);
7192
- (0, import_react42.useEffect)(() => {
7469
+ (0, import_react45.useEffect)(() => {
7193
7470
  if (mutation.status === "success" && mutation.data) {
7194
7471
  setShowSuccess(true);
7195
7472
  onSuccess?.(mutation.data);
@@ -7206,7 +7483,7 @@ function CreateGameSheet({
7206
7483
  return () => clearTimeout(timer);
7207
7484
  }
7208
7485
  }, [mutation.status, mutation.data]);
7209
- (0, import_react42.useEffect)(() => {
7486
+ (0, import_react45.useEffect)(() => {
7210
7487
  if (mutation.status === "error" && mutation.error) {
7211
7488
  onError?.(mutation.error);
7212
7489
  }
@@ -7216,7 +7493,7 @@ function CreateGameSheet({
7216
7493
  const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
7217
7494
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
7218
7495
  const canCreate = selectedTeam !== null && !isMutating && mutation.status !== "success";
7219
- const handleCreate = (0, import_react42.useCallback)(async () => {
7496
+ const handleCreate = (0, import_react45.useCallback)(async () => {
7220
7497
  if (!selectedTeam || !wallet.publicKey) return;
7221
7498
  try {
7222
7499
  await mutation.execute({
@@ -7362,10 +7639,1483 @@ var styles20 = import_react_native26.StyleSheet.create({
7362
7639
  successTitle: { color: "#FFFFFF", fontSize: 28, fontWeight: "900" },
7363
7640
  successSub: { color: "#8E8E93", fontSize: 16 }
7364
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
+ }
7365
9113
  // Annotate the CommonJS export names for ESM import in node:
7366
9114
  0 && (module.exports = {
7367
9115
  ArcadeLeaderboardSheet,
7368
9116
  AuthGate,
9117
+ ChatProvider,
9118
+ ChatSocket,
7369
9119
  ClaimButton,
7370
9120
  ClaimPrizeSheet,
7371
9121
  ConnectWalletButton,
@@ -7379,6 +9129,9 @@ var styles20 = import_react_native26.StyleSheet.create({
7379
9129
  DubsProvider,
7380
9130
  EnterArcadePoolSheet,
7381
9131
  GamePoster,
9132
+ JackpotCard,
9133
+ JackpotSheet,
9134
+ JackpotWidget,
7382
9135
  JoinGameButton,
7383
9136
  JoinGameSheet,
7384
9137
  LivePoolsCard,
@@ -7407,22 +9160,38 @@ var styles20 = import_react_native26.StyleSheet.create({
7407
9160
  useArcadePool,
7408
9161
  useArcadePools,
7409
9162
  useAuth,
9163
+ useChatContext,
9164
+ useChatMessages,
9165
+ useChatStatus,
7410
9166
  useClaim,
9167
+ useConversations,
7411
9168
  useCreateCustomGame,
7412
9169
  useCreateGame,
9170
+ useDirectMessages,
7413
9171
  useDubs,
7414
9172
  useDubsTheme,
7415
9173
  useEnterArcadePool,
9174
+ useEnterJackpot,
7416
9175
  useEvents,
9176
+ useFriendRequests,
9177
+ useFriends,
7417
9178
  useGame,
7418
9179
  useGames,
7419
9180
  useHasClaimed,
7420
9181
  useHighlights,
9182
+ useJackpot,
9183
+ useJackpotHistory,
7421
9184
  useJoinGame,
7422
9185
  useNetworkGames,
9186
+ useOnlineUsers,
7423
9187
  usePushNotifications,
9188
+ useRespondToFriendRequest,
9189
+ useSearchUsers,
9190
+ useSendFriendRequest,
9191
+ useSendMessage,
7424
9192
  useShorts,
7425
9193
  useUFCFightCard,
7426
- useUFCFighterDetail
9194
+ useUFCFighterDetail,
9195
+ useUnreadCount
7427
9196
  });
7428
9197
  //# sourceMappingURL=index.js.map