@dubsdotapp/expo 0.5.16 → 0.5.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -594,6 +594,151 @@ var DubsClient = class {
594
594
  );
595
595
  return res.entry;
596
596
  }
597
+ // ── Jackpot ──
598
+ /** Get current jackpot round + last winner */
599
+ async getJackpotCurrent() {
600
+ const res = await this.request(
601
+ "GET",
602
+ "/jackpot/current"
603
+ );
604
+ return { round: res.round, lastWinner: res.lastWinner };
605
+ }
606
+ /** Get current round entries with odds */
607
+ async getJackpotEntries() {
608
+ const res = await this.request(
609
+ "GET",
610
+ "/jackpot/entries"
611
+ );
612
+ return { roundId: res.roundId, entries: res.entries, totalEntries: res.totalEntries };
613
+ }
614
+ /** Get recent jackpot round results */
615
+ async getJackpotHistory(limit) {
616
+ const qs = limit ? `?limit=${limit}` : "";
617
+ const res = await this.request(
618
+ "GET",
619
+ `/jackpot/history${qs}`
620
+ );
621
+ return res.rounds;
622
+ }
623
+ /** Get jackpot protocol config */
624
+ async getJackpotConfig() {
625
+ const res = await this.request(
626
+ "GET",
627
+ "/jackpot/config"
628
+ );
629
+ return res.config;
630
+ }
631
+ /** Build unsigned jackpot enter transaction */
632
+ async buildJackpotEnter(playerAddress, amount) {
633
+ const res = await this.request(
634
+ "POST",
635
+ "/jackpot/build-enter",
636
+ { playerAddress, amount }
637
+ );
638
+ return { transaction: res.transaction, roundId: res.roundId, amount: res.amount, amountSol: res.amountSol };
639
+ }
640
+ /** Confirm jackpot entry after wallet signs (creates developer attribution) */
641
+ async confirmJackpotEnter(params) {
642
+ const res = await this.request(
643
+ "POST",
644
+ "/jackpot/confirm-enter",
645
+ params
646
+ );
647
+ return { attributed: res.attributed, appId: res.appId, signature: res.signature };
648
+ }
649
+ // ── Chat ──
650
+ /** Get recent global chat messages */
651
+ async getChatMessages(params) {
652
+ const qs = new URLSearchParams();
653
+ if (params?.limit) qs.set("limit", String(params.limit));
654
+ if (params?.before) qs.set("before", String(params.before));
655
+ const query = qs.toString();
656
+ return this.request("GET", `/chat/messages${query ? `?${query}` : ""}`);
657
+ }
658
+ /** Send a message to global chat */
659
+ async sendChatMessage(params) {
660
+ return this.request("POST", "/chat/message", params);
661
+ }
662
+ /** Edit your own message */
663
+ async editChatMessage(id, message) {
664
+ return this.request("PUT", `/chat/message/${id}`, { message });
665
+ }
666
+ /** Delete your own message */
667
+ async deleteChatMessage(id) {
668
+ return this.request("DELETE", `/chat/message/${id}`);
669
+ }
670
+ /** Block a user */
671
+ async blockUser(targetUserId) {
672
+ await this.request("POST", `/chat/block/${targetUserId}`);
673
+ }
674
+ /** Unblock a user */
675
+ async unblockUser(targetUserId) {
676
+ await this.request("DELETE", `/chat/block/${targetUserId}`);
677
+ }
678
+ // ── DMs ──
679
+ /** Get DM conversations inbox */
680
+ async getConversations(limit) {
681
+ const qs = limit ? `?limit=${limit}` : "";
682
+ return this.request("GET", `/dm/conversations${qs}`);
683
+ }
684
+ /** Get conversation history with a specific user */
685
+ async getConversation(walletAddress, params) {
686
+ const qs = new URLSearchParams();
687
+ if (params?.limit) qs.set("limit", String(params.limit));
688
+ if (params?.beforeId) qs.set("beforeId", String(params.beforeId));
689
+ const query = qs.toString();
690
+ return this.request("GET", `/dm/conversation/${encodeURIComponent(walletAddress)}${query ? `?${query}` : ""}`);
691
+ }
692
+ /** Send a direct message */
693
+ async sendDirectMessage(params) {
694
+ return this.request("POST", "/dm/send", params);
695
+ }
696
+ /** Mark all DMs from a user as read */
697
+ async markDMRead(walletAddress) {
698
+ return this.request("POST", `/dm/read/${encodeURIComponent(walletAddress)}`);
699
+ }
700
+ /** Get unread DM count */
701
+ async getDMUnreadCount() {
702
+ return this.request("GET", "/dm/unread");
703
+ }
704
+ /** Delete a DM conversation (soft delete) */
705
+ async deleteConversation(walletAddress) {
706
+ await this.request("DELETE", `/dm/conversation/${encodeURIComponent(walletAddress)}`);
707
+ }
708
+ // ── Social ──
709
+ /** Search users by username */
710
+ async searchUsers(query) {
711
+ const qs = query ? `?q=${encodeURIComponent(query)}` : "";
712
+ return this.request("GET", `/social/search${qs}`);
713
+ }
714
+ /** Send a friend request */
715
+ async sendFriendRequest(targetUserId) {
716
+ return this.request("POST", `/social/friend-request/${targetUserId}`);
717
+ }
718
+ /** Get pending friend requests (received) */
719
+ async getPendingFriendRequests() {
720
+ return this.request("GET", "/social/friend-requests");
721
+ }
722
+ /** Accept a friend request */
723
+ async acceptFriendRequest(requestId) {
724
+ await this.request("POST", `/social/request/${requestId}/accept`);
725
+ }
726
+ /** Reject a friend request */
727
+ async rejectFriendRequest(requestId) {
728
+ await this.request("POST", `/social/request/${requestId}/reject`);
729
+ }
730
+ /** Get friends list */
731
+ async getFriends() {
732
+ return this.request("GET", "/social/friends");
733
+ }
734
+ /** Remove a friend */
735
+ async removeFriend(targetUserId) {
736
+ await this.request("DELETE", `/social/friend/${targetUserId}`);
737
+ }
738
+ /** Get blocked users list */
739
+ async getBlockedUsers() {
740
+ return this.request("GET", "/social/blocked");
741
+ }
597
742
  // ── App Config ──
598
743
  /** Fetch the app's UI customization config (accent color, icon, tagline, environment) */
599
744
  async getAppConfig() {
@@ -645,7 +790,7 @@ function createSecureStoreStorage() {
645
790
  }
646
791
 
647
792
  // src/provider.tsx
648
- import { createContext as createContext4, useContext as useContext4, useMemo as useMemo3, useCallback as useCallback22, useState as useState24, useEffect as useEffect16 } from "react";
793
+ import { createContext as createContext4, useContext as useContext4, useMemo as useMemo3, useCallback as useCallback25, useState as useState27, useEffect as useEffect18 } from "react";
649
794
 
650
795
  // src/ui/theme.ts
651
796
  import { createContext, useContext } from "react";
@@ -1710,7 +1855,7 @@ function ManagedWalletProvider({
1710
1855
  }
1711
1856
 
1712
1857
  // src/ui/AuthGate.tsx
1713
- import React2, { useState as useState23, useEffect as useEffect15, useRef as useRef6, useCallback as useCallback21 } from "react";
1858
+ import React2, { useState as useState26, useEffect as useEffect17, useRef as useRef6, useCallback as useCallback24 } from "react";
1714
1859
  import {
1715
1860
  View as View3,
1716
1861
  Text as Text3,
@@ -2934,6 +3079,117 @@ function useArcadeBridge({
2934
3079
  return { webviewRef, handleMessage, triggerPlay, lastResult, bridgeLoading };
2935
3080
  }
2936
3081
 
3082
+ // src/hooks/useJackpot.ts
3083
+ import { useState as useState23, useEffect as useEffect15, useCallback as useCallback21 } from "react";
3084
+ function useJackpot() {
3085
+ const { client } = useDubs();
3086
+ const [round, setRound] = useState23(null);
3087
+ const [lastWinner, setLastWinner] = useState23(null);
3088
+ const [loading, setLoading] = useState23(false);
3089
+ const [error, setError] = useState23(null);
3090
+ const fetch2 = useCallback21(async () => {
3091
+ setLoading(true);
3092
+ setError(null);
3093
+ try {
3094
+ const result = await client.getJackpotCurrent();
3095
+ setRound(result.round);
3096
+ setLastWinner(result.lastWinner);
3097
+ } catch (err) {
3098
+ setError(err instanceof Error ? err : new Error(String(err)));
3099
+ } finally {
3100
+ setLoading(false);
3101
+ }
3102
+ }, [client]);
3103
+ useEffect15(() => {
3104
+ fetch2();
3105
+ }, [fetch2]);
3106
+ return { round, lastWinner, loading, error, refetch: fetch2 };
3107
+ }
3108
+
3109
+ // src/hooks/useJackpotHistory.ts
3110
+ import { useState as useState24, useEffect as useEffect16, useCallback as useCallback22 } from "react";
3111
+ function useJackpotHistory(limit) {
3112
+ const { client } = useDubs();
3113
+ const [rounds, setRounds] = useState24([]);
3114
+ const [loading, setLoading] = useState24(false);
3115
+ const [error, setError] = useState24(null);
3116
+ const fetch2 = useCallback22(async () => {
3117
+ setLoading(true);
3118
+ setError(null);
3119
+ try {
3120
+ const result = await client.getJackpotHistory(limit);
3121
+ setRounds(result);
3122
+ } catch (err) {
3123
+ setError(err instanceof Error ? err : new Error(String(err)));
3124
+ } finally {
3125
+ setLoading(false);
3126
+ }
3127
+ }, [client, limit]);
3128
+ useEffect16(() => {
3129
+ fetch2();
3130
+ }, [fetch2]);
3131
+ return { rounds, loading, error, refetch: fetch2 };
3132
+ }
3133
+
3134
+ // src/hooks/useEnterJackpot.ts
3135
+ import { useState as useState25, useCallback as useCallback23 } from "react";
3136
+ function useEnterJackpot() {
3137
+ const { client, wallet, connection } = useDubs();
3138
+ const [status, setStatus] = useState25("idle");
3139
+ const [error, setError] = useState25(null);
3140
+ const [data, setData] = useState25(null);
3141
+ const reset = useCallback23(() => {
3142
+ setStatus("idle");
3143
+ setError(null);
3144
+ setData(null);
3145
+ }, []);
3146
+ const execute = useCallback23(async (amountLamports) => {
3147
+ if (!wallet.publicKey) throw new Error("Wallet not connected");
3148
+ const walletAddress = wallet.publicKey.toBase58();
3149
+ setStatus("building");
3150
+ setError(null);
3151
+ setData(null);
3152
+ try {
3153
+ console.log("[useEnterJackpot] Step 1: Building transaction...", { walletAddress, amountLamports });
3154
+ const buildResult = await client.buildJackpotEnter(walletAddress, amountLamports);
3155
+ console.log("[useEnterJackpot] Step 1 done:", { roundId: buildResult.roundId, amount: buildResult.amount });
3156
+ setStatus("signing");
3157
+ console.log("[useEnterJackpot] Step 2: Signing and sending...");
3158
+ const signature = await signAndSendBase64Transaction(
3159
+ buildResult.transaction,
3160
+ wallet,
3161
+ connection
3162
+ );
3163
+ console.log("[useEnterJackpot] Step 2 done. Signature:", signature);
3164
+ setStatus("confirming");
3165
+ console.log("[useEnterJackpot] Step 3: Confirming with backend...");
3166
+ await client.confirmJackpotEnter({
3167
+ playerAddress: walletAddress,
3168
+ roundId: buildResult.roundId,
3169
+ amount: amountLamports,
3170
+ signature
3171
+ });
3172
+ console.log("[useEnterJackpot] Step 3 done. Entry confirmed + attributed.");
3173
+ const result = {
3174
+ roundId: buildResult.roundId,
3175
+ amount: buildResult.amount,
3176
+ amountSol: buildResult.amountSol,
3177
+ signature
3178
+ };
3179
+ setData(result);
3180
+ setStatus("success");
3181
+ return result;
3182
+ } catch (err) {
3183
+ console.error("[useEnterJackpot] FAILED:", err);
3184
+ const e = err instanceof Error ? err : new Error(String(err));
3185
+ setError(e);
3186
+ setStatus("error");
3187
+ throw e;
3188
+ }
3189
+ }, [client, wallet, connection]);
3190
+ return { execute, status, error, data, reset };
3191
+ }
3192
+
2937
3193
  // src/ui/AvatarEditor.tsx
2938
3194
  import {
2939
3195
  View as View2,
@@ -3102,11 +3358,11 @@ function AuthGate({
3102
3358
  }) {
3103
3359
  const { client, pushEnabled } = useDubs();
3104
3360
  const auth = useAuth();
3105
- const [phase, setPhase] = useState23("init");
3106
- const [registrationPhase, setRegistrationPhase] = useState23(false);
3107
- const [showPushSetup, setShowPushSetup] = useState23(false);
3108
- const [isRestoredSession, setIsRestoredSession] = useState23(false);
3109
- useEffect15(() => {
3361
+ const [phase, setPhase] = useState26("init");
3362
+ const [registrationPhase, setRegistrationPhase] = useState26(false);
3363
+ const [showPushSetup, setShowPushSetup] = useState26(false);
3364
+ const [isRestoredSession, setIsRestoredSession] = useState26(false);
3365
+ useEffect17(() => {
3110
3366
  let cancelled = false;
3111
3367
  (async () => {
3112
3368
  try {
@@ -3133,23 +3389,23 @@ function AuthGate({
3133
3389
  cancelled = true;
3134
3390
  };
3135
3391
  }, []);
3136
- useEffect15(() => {
3392
+ useEffect17(() => {
3137
3393
  if (auth.status === "needsRegistration") setRegistrationPhase(true);
3138
3394
  }, [auth.status]);
3139
- useEffect15(() => {
3395
+ useEffect17(() => {
3140
3396
  if (pushEnabled && auth.status === "authenticated" && registrationPhase && !isRestoredSession) {
3141
3397
  setShowPushSetup(true);
3142
3398
  }
3143
3399
  }, [pushEnabled, auth.status, registrationPhase, isRestoredSession]);
3144
- useEffect15(() => {
3400
+ useEffect17(() => {
3145
3401
  if (auth.token) onSaveToken(auth.token);
3146
3402
  }, [auth.token]);
3147
- const retry = useCallback21(() => {
3403
+ const retry = useCallback24(() => {
3148
3404
  setRegistrationPhase(false);
3149
3405
  auth.reset();
3150
3406
  auth.authenticate();
3151
3407
  }, [auth]);
3152
- const handleRegister = useCallback21(
3408
+ const handleRegister = useCallback24(
3153
3409
  (username, referralCode, avatarUrl) => {
3154
3410
  auth.register(username, referralCode, avatarUrl);
3155
3411
  },
@@ -3273,20 +3529,20 @@ function DefaultRegistrationScreen({
3273
3529
  }) {
3274
3530
  const t = useDubsTheme();
3275
3531
  const accent = accentColor || t.accent;
3276
- const [step, setStep] = useState23(0);
3277
- const [avatarSeed, setAvatarSeed] = useState23(generateSeed);
3278
- const [avatarStyle, setAvatarStyle] = useState23("adventurer");
3279
- const [avatarBg, setAvatarBg] = useState23("1a1a2e");
3280
- const [showStyles, setShowStyles] = useState23(false);
3281
- const [username, setUsername] = useState23("");
3282
- const [referralCode, setReferralCode] = useState23("");
3283
- const [checking, setChecking] = useState23(false);
3284
- const [availability, setAvailability] = useState23(null);
3532
+ const [step, setStep] = useState26(0);
3533
+ const [avatarSeed, setAvatarSeed] = useState26(generateSeed);
3534
+ const [avatarStyle, setAvatarStyle] = useState26("adventurer");
3535
+ const [avatarBg, setAvatarBg] = useState26("1a1a2e");
3536
+ const [showStyles, setShowStyles] = useState26(false);
3537
+ const [username, setUsername] = useState26("");
3538
+ const [referralCode, setReferralCode] = useState26("");
3539
+ const [checking, setChecking] = useState26(false);
3540
+ const [availability, setAvailability] = useState26(null);
3285
3541
  const debounceRef = useRef6(null);
3286
3542
  const fadeAnim = useRef6(new Animated.Value(1)).current;
3287
3543
  const slideAnim = useRef6(new Animated.Value(0)).current;
3288
3544
  const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed, avatarBg);
3289
- useEffect15(() => {
3545
+ useEffect17(() => {
3290
3546
  if (debounceRef.current) clearTimeout(debounceRef.current);
3291
3547
  const trimmed = username.trim();
3292
3548
  if (trimmed.length < 3) {
@@ -3309,7 +3565,7 @@ function DefaultRegistrationScreen({
3309
3565
  if (debounceRef.current) clearTimeout(debounceRef.current);
3310
3566
  };
3311
3567
  }, [username, client]);
3312
- const animateToStep = useCallback21((newStep) => {
3568
+ const animateToStep = useCallback24((newStep) => {
3313
3569
  const dir = newStep > step ? 1 : -1;
3314
3570
  Keyboard.dismiss();
3315
3571
  Animated.parallel([
@@ -3549,7 +3805,7 @@ function DefaultRegistrationScreen({
3549
3805
  function PushTokenRestorer() {
3550
3806
  const push = usePushNotifications();
3551
3807
  const restored = useRef6(false);
3552
- useEffect15(() => {
3808
+ useEffect17(() => {
3553
3809
  if (restored.current) return;
3554
3810
  restored.current = true;
3555
3811
  push.restoreIfGranted();
@@ -3566,7 +3822,7 @@ function PushSetupScreen({
3566
3822
  const push = usePushNotifications();
3567
3823
  const fadeAnim = useRef6(new Animated.Value(0)).current;
3568
3824
  const slideAnim = useRef6(new Animated.Value(30)).current;
3569
- useEffect15(() => {
3825
+ useEffect17(() => {
3570
3826
  Animated.parallel([
3571
3827
  Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true }),
3572
3828
  Animated.timing(slideAnim, { toValue: 0, duration: 300, useNativeDriver: true })
@@ -3726,9 +3982,9 @@ function DubsProvider({
3726
3982
  const rpcUrl = rpcUrlOverride || config.rpcUrl;
3727
3983
  const client = useMemo3(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
3728
3984
  const storage = useMemo3(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
3729
- const [uiConfig, setUiConfig] = useState24(null);
3730
- const [resolvedNetwork, setResolvedNetwork] = useState24(network);
3731
- useEffect16(() => {
3985
+ const [uiConfig, setUiConfig] = useState27(null);
3986
+ const [resolvedNetwork, setResolvedNetwork] = useState27(network);
3987
+ useEffect18(() => {
3732
3988
  client.getAppConfig().then((cfg) => {
3733
3989
  console.log("[DubsProvider] UI config loaded:", JSON.stringify(cfg));
3734
3990
  setUiConfig(cfg);
@@ -3820,7 +4076,7 @@ function ManagedInner({
3820
4076
  children
3821
4077
  }) {
3822
4078
  const managedDisconnect = useDisconnect();
3823
- const disconnect = useCallback22(async () => {
4079
+ const disconnect = useCallback25(async () => {
3824
4080
  client.setToken(null);
3825
4081
  await managedDisconnect?.();
3826
4082
  }, [client, managedDisconnect]);
@@ -3861,7 +4117,7 @@ function ExternalWalletProvider({
3861
4117
  pushEnabled,
3862
4118
  children
3863
4119
  }) {
3864
- const disconnect = useCallback22(async () => {
4120
+ const disconnect = useCallback25(async () => {
3865
4121
  client.setToken(null);
3866
4122
  await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
3867
4123
  });
@@ -4182,7 +4438,7 @@ var styles5 = StyleSheet6.create({
4182
4438
  });
4183
4439
 
4184
4440
  // src/ui/UserProfileSheet.tsx
4185
- import { useState as useState25, useEffect as useEffect17, useRef as useRef7, useCallback as useCallback23, useMemo as useMemo5 } from "react";
4441
+ import { useState as useState28, useEffect as useEffect19, useRef as useRef7, useCallback as useCallback26, useMemo as useMemo5 } from "react";
4186
4442
  import {
4187
4443
  View as View7,
4188
4444
  Text as Text7,
@@ -4215,29 +4471,29 @@ function UserProfileSheet({
4215
4471
  const push = usePushNotifications();
4216
4472
  const overlayOpacity = useRef7(new Animated2.Value(0)).current;
4217
4473
  const parsed = useMemo5(() => parseAvatarUrl(user.avatar), [user.avatar]);
4218
- const [avatarStyle, setAvatarStyle] = useState25(parsed.style);
4219
- const [avatarSeed, setAvatarSeed] = useState25(parsed.seed);
4220
- const [bgColor, setBgColor] = useState25(parsed.bg);
4221
- const [saving, setSaving] = useState25(false);
4222
- const [error, setError] = useState25(null);
4223
- useEffect17(() => {
4474
+ const [avatarStyle, setAvatarStyle] = useState28(parsed.style);
4475
+ const [avatarSeed, setAvatarSeed] = useState28(parsed.seed);
4476
+ const [bgColor, setBgColor] = useState28(parsed.bg);
4477
+ const [saving, setSaving] = useState28(false);
4478
+ const [error, setError] = useState28(null);
4479
+ useEffect19(() => {
4224
4480
  const p = parseAvatarUrl(user.avatar);
4225
4481
  setAvatarStyle(p.style);
4226
4482
  setAvatarSeed(p.seed);
4227
4483
  setBgColor(p.bg);
4228
4484
  }, [user.avatar]);
4229
- useEffect17(() => {
4485
+ useEffect19(() => {
4230
4486
  Animated2.timing(overlayOpacity, {
4231
4487
  toValue: visible ? 1 : 0,
4232
4488
  duration: 250,
4233
4489
  useNativeDriver: true
4234
4490
  }).start();
4235
4491
  }, [visible, overlayOpacity]);
4236
- useEffect17(() => {
4492
+ useEffect19(() => {
4237
4493
  if (visible) setError(null);
4238
4494
  }, [visible]);
4239
4495
  const currentAvatarUrl = getAvatarUrl(avatarStyle, avatarSeed, bgColor);
4240
- const saveAvatar = useCallback23(async (newUrl) => {
4496
+ const saveAvatar = useCallback26(async (newUrl) => {
4241
4497
  setSaving(true);
4242
4498
  setError(null);
4243
4499
  try {
@@ -4250,16 +4506,16 @@ function UserProfileSheet({
4250
4506
  setSaving(false);
4251
4507
  }
4252
4508
  }, [client, refreshUser, onAvatarUpdated]);
4253
- const handleStyleChange = useCallback23((style) => {
4509
+ const handleStyleChange = useCallback26((style) => {
4254
4510
  setAvatarStyle(style);
4255
4511
  saveAvatar(getAvatarUrl(style, avatarSeed, bgColor));
4256
4512
  }, [avatarSeed, bgColor, saveAvatar]);
4257
- const handleShuffle = useCallback23(() => {
4513
+ const handleShuffle = useCallback26(() => {
4258
4514
  const newSeed = generateSeed();
4259
4515
  setAvatarSeed(newSeed);
4260
4516
  saveAvatar(getAvatarUrl(avatarStyle, newSeed, bgColor));
4261
4517
  }, [avatarStyle, bgColor, saveAvatar]);
4262
- const handleBgChange = useCallback23((color) => {
4518
+ const handleBgChange = useCallback26((color) => {
4263
4519
  setBgColor(color);
4264
4520
  saveAvatar(getAvatarUrl(avatarStyle, avatarSeed, color));
4265
4521
  }, [avatarStyle, avatarSeed, saveAvatar]);
@@ -4539,7 +4795,7 @@ var styles6 = StyleSheet7.create({
4539
4795
  });
4540
4796
 
4541
4797
  // src/ui/game/GamePoster.tsx
4542
- import { useState as useState26 } from "react";
4798
+ import { useState as useState29 } from "react";
4543
4799
  import { StyleSheet as StyleSheet8, View as View8, Text as Text8 } from "react-native";
4544
4800
  import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
4545
4801
  function computeCountdown(lockTimestamp) {
@@ -4589,7 +4845,7 @@ function GamePoster({ game, ImageComponent }) {
4589
4845
  ] });
4590
4846
  }
4591
4847
  function TeamLogoInternal({ url, size, Img }) {
4592
- const [failed, setFailed] = useState26(false);
4848
+ const [failed, setFailed] = useState29(false);
4593
4849
  if (!url || failed) {
4594
4850
  return /* @__PURE__ */ jsx10(View8, { style: [styles7.logoPlaceholder, { width: size, height: size, borderRadius: size / 2 }] });
4595
4851
  }
@@ -4769,7 +5025,7 @@ var styles8 = StyleSheet9.create({
4769
5025
  });
4770
5026
 
4771
5027
  // src/ui/game/PickWinnerCard.tsx
4772
- import { useState as useState27, useMemo as useMemo7 } from "react";
5028
+ import { useState as useState30, useMemo as useMemo7 } from "react";
4773
5029
  import { StyleSheet as StyleSheet10, View as View10, Text as Text10, TouchableOpacity as TouchableOpacity7 } from "react-native";
4774
5030
  import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
4775
5031
  function PickWinnerCard({
@@ -4840,7 +5096,7 @@ function TeamOption({
4840
5096
  ImageComponent,
4841
5097
  t
4842
5098
  }) {
4843
- const [imgFailed, setImgFailed] = useState27(false);
5099
+ const [imgFailed, setImgFailed] = useState30(false);
4844
5100
  const Img = ImageComponent || __require("react-native").Image;
4845
5101
  const showImage = imageUrl && !imgFailed;
4846
5102
  return /* @__PURE__ */ jsxs9(
@@ -4881,7 +5137,7 @@ var styles9 = StyleSheet10.create({
4881
5137
  });
4882
5138
 
4883
5139
  // src/ui/game/PlayersCard.tsx
4884
- import { useState as useState28 } from "react";
5140
+ import { useState as useState31 } from "react";
4885
5141
  import { StyleSheet as StyleSheet11, View as View11, Text as Text11 } from "react-native";
4886
5142
  import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
4887
5143
  function truncateWallet(addr, chars) {
@@ -4930,7 +5186,7 @@ function BettorRow({
4930
5186
  ImageComponent,
4931
5187
  t
4932
5188
  }) {
4933
- const [imgFailed, setImgFailed] = useState28(false);
5189
+ const [imgFailed, setImgFailed] = useState31(false);
4934
5190
  const Img = ImageComponent || __require("react-native").Image;
4935
5191
  const showAvatar = bettor.avatar && !imgFailed;
4936
5192
  return /* @__PURE__ */ jsxs10(View11, { style: [styles10.row, !isFirst && { borderTopColor: t.border, borderTopWidth: 1 }], children: [
@@ -5009,7 +5265,7 @@ var styles11 = StyleSheet12.create({
5009
5265
  });
5010
5266
 
5011
5267
  // src/ui/game/CreateCustomGameSheet.tsx
5012
- import { useState as useState29, useEffect as useEffect18, useRef as useRef8, useCallback as useCallback24 } from "react";
5268
+ import { useState as useState32, useEffect as useEffect20, useRef as useRef8, useCallback as useCallback27 } from "react";
5013
5269
  import {
5014
5270
  View as View13,
5015
5271
  Text as Text13,
@@ -5046,18 +5302,18 @@ function CreateCustomGameSheet({
5046
5302
  const t = useDubsTheme();
5047
5303
  const { wallet } = useDubs();
5048
5304
  const mutation = useCreateCustomGame();
5049
- const [selectedAmount, setSelectedAmount] = useState29(null);
5050
- const [customAmount, setCustomAmount] = useState29("");
5051
- const [isCustom, setIsCustom] = useState29(false);
5305
+ const [selectedAmount, setSelectedAmount] = useState32(null);
5306
+ const [customAmount, setCustomAmount] = useState32("");
5307
+ const [isCustom, setIsCustom] = useState32(false);
5052
5308
  const overlayOpacity = useRef8(new Animated3.Value(0)).current;
5053
- useEffect18(() => {
5309
+ useEffect20(() => {
5054
5310
  Animated3.timing(overlayOpacity, {
5055
5311
  toValue: visible ? 1 : 0,
5056
5312
  duration: 250,
5057
5313
  useNativeDriver: true
5058
5314
  }).start();
5059
5315
  }, [visible, overlayOpacity]);
5060
- useEffect18(() => {
5316
+ useEffect20(() => {
5061
5317
  if (visible) {
5062
5318
  setSelectedAmount(defaultAmount ?? null);
5063
5319
  setCustomAmount("");
@@ -5065,7 +5321,7 @@ function CreateCustomGameSheet({
5065
5321
  mutation.reset();
5066
5322
  }
5067
5323
  }, [visible]);
5068
- useEffect18(() => {
5324
+ useEffect20(() => {
5069
5325
  if (mutation.status === "success" && mutation.data) {
5070
5326
  onSuccess?.(mutation.data);
5071
5327
  const timer = setTimeout(() => {
@@ -5074,23 +5330,23 @@ function CreateCustomGameSheet({
5074
5330
  return () => clearTimeout(timer);
5075
5331
  }
5076
5332
  }, [mutation.status, mutation.data]);
5077
- useEffect18(() => {
5333
+ useEffect20(() => {
5078
5334
  if (mutation.status === "error" && mutation.error) {
5079
5335
  onError?.(mutation.error);
5080
5336
  }
5081
5337
  }, [mutation.status, mutation.error]);
5082
- const handlePresetSelect = useCallback24((amount) => {
5338
+ const handlePresetSelect = useCallback27((amount) => {
5083
5339
  setSelectedAmount(amount);
5084
5340
  setIsCustom(false);
5085
5341
  setCustomAmount("");
5086
5342
  onAmountChange?.(amount);
5087
5343
  }, [onAmountChange]);
5088
- const handleCustomSelect = useCallback24(() => {
5344
+ const handleCustomSelect = useCallback27(() => {
5089
5345
  setIsCustom(true);
5090
5346
  setSelectedAmount(null);
5091
5347
  onAmountChange?.(null);
5092
5348
  }, [onAmountChange]);
5093
- const handleCustomAmountChange = useCallback24((text) => {
5349
+ const handleCustomAmountChange = useCallback27((text) => {
5094
5350
  const cleaned = text.replace(/[^0-9.]/g, "").replace(/(\..*?)\..*/g, "$1");
5095
5351
  setCustomAmount(cleaned);
5096
5352
  const parsed = parseFloat(cleaned);
@@ -5105,7 +5361,7 @@ function CreateCustomGameSheet({
5105
5361
  const winnerTakes = pot * (1 - fee / 100);
5106
5362
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
5107
5363
  const canCreate = finalAmount !== null && finalAmount > 0 && !isMutating && mutation.status !== "success";
5108
- const handleCreate = useCallback24(async () => {
5364
+ const handleCreate = useCallback27(async () => {
5109
5365
  if (!finalAmount || !wallet.publicKey) return;
5110
5366
  try {
5111
5367
  await mutation.execute({
@@ -5374,7 +5630,7 @@ var styles12 = StyleSheet13.create({
5374
5630
  });
5375
5631
 
5376
5632
  // src/ui/game/JoinGameSheet.tsx
5377
- import { useState as useState31, useEffect as useEffect19, useRef as useRef10, useCallback as useCallback26, useMemo as useMemo9 } from "react";
5633
+ import { useState as useState34, useEffect as useEffect21, useRef as useRef10, useCallback as useCallback29, useMemo as useMemo9 } from "react";
5378
5634
  import {
5379
5635
  View as View16,
5380
5636
  Text as Text16,
@@ -5584,7 +5840,7 @@ var styles13 = StyleSheet14.create({
5584
5840
  });
5585
5841
 
5586
5842
  // src/ui/game/TeamButton.tsx
5587
- import { useState as useState30 } from "react";
5843
+ import { useState as useState33 } from "react";
5588
5844
  import { View as View15, Text as Text15, TouchableOpacity as TouchableOpacity10, StyleSheet as StyleSheet15 } from "react-native";
5589
5845
  import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
5590
5846
  function TeamButton({
@@ -5598,7 +5854,7 @@ function TeamButton({
5598
5854
  ImageComponent,
5599
5855
  t
5600
5856
  }) {
5601
- const [imgFailed, setImgFailed] = useState30(false);
5857
+ const [imgFailed, setImgFailed] = useState33(false);
5602
5858
  const Img = ImageComponent || __require("react-native").Image;
5603
5859
  const showImage = imageUrl && !imgFailed;
5604
5860
  return /* @__PURE__ */ jsxs14(
@@ -5702,20 +5958,20 @@ function JoinGameSheet({
5702
5958
  const { wallet } = useDubs();
5703
5959
  const mutation = useJoinGame();
5704
5960
  const isCustomGame = game.gameMode === CUSTOM_GAME_MODE;
5705
- const [selectedTeam, setSelectedTeam] = useState31(null);
5706
- const [wager, setWager] = useState31(game.buyIn);
5707
- const [showSuccess, setShowSuccess] = useState31(false);
5961
+ const [selectedTeam, setSelectedTeam] = useState34(null);
5962
+ const [wager, setWager] = useState34(game.buyIn);
5963
+ const [showSuccess, setShowSuccess] = useState34(false);
5708
5964
  const overlayOpacity = useRef10(new Animated4.Value(0)).current;
5709
5965
  const successScale = useRef10(new Animated4.Value(0)).current;
5710
5966
  const successOpacity = useRef10(new Animated4.Value(0)).current;
5711
- useEffect19(() => {
5967
+ useEffect21(() => {
5712
5968
  Animated4.timing(overlayOpacity, {
5713
5969
  toValue: visible ? 1 : 0,
5714
5970
  duration: 250,
5715
5971
  useNativeDriver: true
5716
5972
  }).start();
5717
5973
  }, [visible, overlayOpacity]);
5718
- useEffect19(() => {
5974
+ useEffect21(() => {
5719
5975
  if (visible) {
5720
5976
  setSelectedTeam(isPoolModeEnabled ? "home" : isCustomGame ? "away" : null);
5721
5977
  setWager(game.buyIn);
@@ -5725,7 +5981,7 @@ function JoinGameSheet({
5725
5981
  mutation.reset();
5726
5982
  }
5727
5983
  }, [visible]);
5728
- useEffect19(() => {
5984
+ useEffect21(() => {
5729
5985
  if (mutation.status === "success" && mutation.data) {
5730
5986
  setShowSuccess(true);
5731
5987
  onSuccess?.(mutation.data);
@@ -5742,7 +5998,7 @@ function JoinGameSheet({
5742
5998
  return () => clearTimeout(timer);
5743
5999
  }
5744
6000
  }, [mutation.status, mutation.data]);
5745
- useEffect19(() => {
6001
+ useEffect21(() => {
5746
6002
  if (mutation.status === "error" && mutation.error) {
5747
6003
  onError?.(mutation.error);
5748
6004
  }
@@ -5786,7 +6042,7 @@ function JoinGameSheet({
5786
6042
  const alreadyJoined = myBet !== null;
5787
6043
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
5788
6044
  const canJoin = selectedTeam !== null && !isMutating && mutation.status !== "success" && !alreadyJoined;
5789
- const handleJoin = useCallback26(async () => {
6045
+ const handleJoin = useCallback29(async () => {
5790
6046
  if (!selectedTeam || !wallet.publicKey) return;
5791
6047
  try {
5792
6048
  await mutation.execute({
@@ -5846,13 +6102,15 @@ function JoinGameSheet({
5846
6102
  ] }) })
5847
6103
  ] })
5848
6104
  ] }),
5849
- !isCustomGame && !isPoolModeEnabled && !alreadyJoined && /* @__PURE__ */ jsxs15(View16, { style: styles15.section, children: [
5850
- /* @__PURE__ */ jsx18(Text16, { style: [styles15.sectionLabel, { color: t.textSecondary }], children: "Pick Your Side" }),
5851
- /* @__PURE__ */ jsxs15(View16, { style: styles15.teamsRow, children: [
6105
+ !isCustomGame && !isPoolModeEnabled && !alreadyJoined && (hasDrawOption ? (
6106
+ /* ── 3-way layout: Home / VS / Away / OR / Draw ── */
6107
+ /* @__PURE__ */ jsxs15(View16, { style: styles15.section, children: [
6108
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.sectionLabel, { color: t.textSecondary }], children: "Who will win?" }),
5852
6109
  /* @__PURE__ */ jsx18(
5853
- TeamButton,
6110
+ PickRow,
5854
6111
  {
5855
6112
  name: homeName,
6113
+ subtitle: "Home Team",
5856
6114
  imageUrl: opponents[0]?.imageUrl,
5857
6115
  odds: homeOdds,
5858
6116
  bets: homeBets,
@@ -5866,10 +6124,16 @@ function JoinGameSheet({
5866
6124
  t
5867
6125
  }
5868
6126
  ),
6127
+ /* @__PURE__ */ jsxs15(View16, { style: styles15.dividerRow, children: [
6128
+ /* @__PURE__ */ jsx18(View16, { style: [styles15.dividerLine, { backgroundColor: t.border }] }),
6129
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.dividerText, { color: t.textMuted }], children: "VS" }),
6130
+ /* @__PURE__ */ jsx18(View16, { style: [styles15.dividerLine, { backgroundColor: t.border }] })
6131
+ ] }),
5869
6132
  /* @__PURE__ */ jsx18(
5870
- TeamButton,
6133
+ PickRow,
5871
6134
  {
5872
6135
  name: awayName,
6136
+ subtitle: "Away Team",
5873
6137
  imageUrl: opponents[1]?.imageUrl,
5874
6138
  odds: awayOdds,
5875
6139
  bets: awayBets,
@@ -5882,24 +6146,71 @@ function JoinGameSheet({
5882
6146
  ImageComponent,
5883
6147
  t
5884
6148
  }
6149
+ ),
6150
+ /* @__PURE__ */ jsxs15(View16, { style: styles15.dividerRow, children: [
6151
+ /* @__PURE__ */ jsx18(View16, { style: [styles15.dividerLine, { backgroundColor: t.border }] }),
6152
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.dividerText, { color: t.textMuted }], children: "OR" }),
6153
+ /* @__PURE__ */ jsx18(View16, { style: [styles15.dividerLine, { backgroundColor: t.border }] })
6154
+ ] }),
6155
+ /* @__PURE__ */ jsx18(
6156
+ PickRow,
6157
+ {
6158
+ name: "Draw",
6159
+ subtitle: "Match ends in a tie",
6160
+ odds: drawOdds,
6161
+ bets: drawBets,
6162
+ color: drawColor,
6163
+ selected: selectedTeam === "draw",
6164
+ onPress: () => {
6165
+ setSelectedTeam("draw");
6166
+ onTeamSelect?.("draw");
6167
+ },
6168
+ t
6169
+ }
5885
6170
  )
5886
- ] }),
5887
- hasDrawOption && /* @__PURE__ */ jsx18(View16, { style: styles15.drawRow, children: /* @__PURE__ */ jsx18(
5888
- TeamButton,
5889
- {
5890
- name: "Draw",
5891
- odds: drawOdds,
5892
- bets: drawBets,
5893
- color: drawColor,
5894
- selected: selectedTeam === "draw",
5895
- onPress: () => {
5896
- setSelectedTeam("draw");
5897
- onTeamSelect?.("draw");
5898
- },
5899
- t
5900
- }
5901
- ) })
5902
- ] }),
6171
+ ] })
6172
+ ) : (
6173
+ /* ── 2-way layout: side by side ── */
6174
+ /* @__PURE__ */ jsxs15(View16, { style: styles15.section, children: [
6175
+ /* @__PURE__ */ jsx18(Text16, { style: [styles15.sectionLabel, { color: t.textSecondary }], children: "Pick Your Side" }),
6176
+ /* @__PURE__ */ jsxs15(View16, { style: styles15.teamsRow, children: [
6177
+ /* @__PURE__ */ jsx18(
6178
+ TeamButton,
6179
+ {
6180
+ name: homeName,
6181
+ imageUrl: opponents[0]?.imageUrl,
6182
+ odds: homeOdds,
6183
+ bets: homeBets,
6184
+ color: homeColor,
6185
+ selected: selectedTeam === "home",
6186
+ onPress: () => {
6187
+ setSelectedTeam("home");
6188
+ onTeamSelect?.("home");
6189
+ },
6190
+ ImageComponent,
6191
+ t
6192
+ }
6193
+ ),
6194
+ /* @__PURE__ */ jsx18(
6195
+ TeamButton,
6196
+ {
6197
+ name: awayName,
6198
+ imageUrl: opponents[1]?.imageUrl,
6199
+ odds: awayOdds,
6200
+ bets: awayBets,
6201
+ color: awayColor,
6202
+ selected: selectedTeam === "away",
6203
+ onPress: () => {
6204
+ setSelectedTeam("away");
6205
+ onTeamSelect?.("away");
6206
+ },
6207
+ ImageComponent,
6208
+ t
6209
+ }
6210
+ )
6211
+ ] })
6212
+ ] })
6213
+ )),
5903
6214
  alreadyJoined && myBet && /* @__PURE__ */ jsxs15(View16, { style: [styles15.myBetCard, { backgroundColor: (myBet.team === "home" ? homeColor : myBet.team === "away" ? awayColor : drawColor) + "15", borderColor: myBet.team === "home" ? homeColor : myBet.team === "away" ? awayColor : drawColor }], children: [
5904
6215
  /* @__PURE__ */ jsx18(Text16, { style: [styles15.myBetLabel, { color: myBet.team === "home" ? homeColor : myBet.team === "away" ? awayColor : drawColor }], children: "YOUR BET" }),
5905
6216
  /* @__PURE__ */ jsx18(Text16, { style: [styles15.myBetTeam, { color: t.text }], children: myBet.team === "home" ? homeName : myBet.team === "away" ? awayName : "Draw" }),
@@ -5982,6 +6293,100 @@ function JoinGameSheet({
5982
6293
  }
5983
6294
  );
5984
6295
  }
6296
+ function PickRow({
6297
+ name,
6298
+ subtitle,
6299
+ imageUrl,
6300
+ odds,
6301
+ bets,
6302
+ color,
6303
+ selected,
6304
+ onPress,
6305
+ ImageComponent,
6306
+ t
6307
+ }) {
6308
+ const [imgFailed, setImgFailed] = useState34(false);
6309
+ const Img = ImageComponent || __require("react-native").Image;
6310
+ const showImage = imageUrl && !imgFailed;
6311
+ return /* @__PURE__ */ jsxs15(
6312
+ TouchableOpacity11,
6313
+ {
6314
+ style: [pickStyles.row, { borderColor: selected ? color : t.border, backgroundColor: selected ? color + "12" : t.background }],
6315
+ onPress,
6316
+ activeOpacity: 0.7,
6317
+ children: [
6318
+ showImage ? /* @__PURE__ */ jsx18(Img, { source: { uri: imageUrl }, style: pickStyles.logo, resizeMode: "contain", onError: () => setImgFailed(true) }) : /* @__PURE__ */ jsx18(View16, { style: [pickStyles.logoPlaceholder, { backgroundColor: color + "20" }], children: /* @__PURE__ */ jsx18(Text16, { style: [pickStyles.logoEmoji, { color }], children: name === "Draw" ? "\u{1F91D}" : name.charAt(0) }) }),
6319
+ /* @__PURE__ */ jsxs15(View16, { style: pickStyles.info, children: [
6320
+ /* @__PURE__ */ jsx18(Text16, { style: [pickStyles.name, { color: t.text }], children: name }),
6321
+ subtitle && /* @__PURE__ */ jsx18(Text16, { style: [pickStyles.subtitle, { color: t.textMuted }], children: subtitle })
6322
+ ] }),
6323
+ odds !== "\u2014" && /* @__PURE__ */ jsxs15(Text16, { style: [pickStyles.odds, { color }], children: [
6324
+ odds,
6325
+ "x"
6326
+ ] }),
6327
+ bets > 0 && /* @__PURE__ */ jsx18(Text16, { style: [pickStyles.bets, { color: t.textMuted }], children: bets }),
6328
+ selected && /* @__PURE__ */ jsx18(View16, { style: [pickStyles.check, { backgroundColor: color }], children: /* @__PURE__ */ jsx18(Text16, { style: pickStyles.checkText, children: "\u2713" }) })
6329
+ ]
6330
+ }
6331
+ );
6332
+ }
6333
+ var pickStyles = StyleSheet16.create({
6334
+ row: {
6335
+ flexDirection: "row",
6336
+ alignItems: "center",
6337
+ borderWidth: 1.5,
6338
+ borderRadius: 14,
6339
+ paddingVertical: 12,
6340
+ paddingHorizontal: 14,
6341
+ gap: 12
6342
+ },
6343
+ logo: {
6344
+ width: 36,
6345
+ height: 36,
6346
+ borderRadius: 18
6347
+ },
6348
+ logoPlaceholder: {
6349
+ width: 36,
6350
+ height: 36,
6351
+ borderRadius: 18,
6352
+ alignItems: "center",
6353
+ justifyContent: "center"
6354
+ },
6355
+ logoEmoji: {
6356
+ fontSize: 16,
6357
+ fontWeight: "800"
6358
+ },
6359
+ info: {
6360
+ flex: 1
6361
+ },
6362
+ name: {
6363
+ fontSize: 15,
6364
+ fontWeight: "700"
6365
+ },
6366
+ subtitle: {
6367
+ fontSize: 12,
6368
+ marginTop: 1
6369
+ },
6370
+ odds: {
6371
+ fontSize: 16,
6372
+ fontWeight: "800"
6373
+ },
6374
+ bets: {
6375
+ fontSize: 12
6376
+ },
6377
+ check: {
6378
+ width: 22,
6379
+ height: 22,
6380
+ borderRadius: 11,
6381
+ alignItems: "center",
6382
+ justifyContent: "center"
6383
+ },
6384
+ checkText: {
6385
+ color: "#FFF",
6386
+ fontSize: 13,
6387
+ fontWeight: "800"
6388
+ }
6389
+ });
5985
6390
  var styles15 = StyleSheet16.create({
5986
6391
  overlay: {
5987
6392
  ...StyleSheet16.absoluteFillObject,
@@ -6104,6 +6509,20 @@ var styles15 = StyleSheet16.create({
6104
6509
  drawRow: {
6105
6510
  marginTop: 8
6106
6511
  },
6512
+ dividerRow: {
6513
+ flexDirection: "row",
6514
+ alignItems: "center",
6515
+ gap: 12,
6516
+ marginVertical: 6
6517
+ },
6518
+ dividerLine: {
6519
+ flex: 1,
6520
+ height: 1
6521
+ },
6522
+ dividerText: {
6523
+ fontSize: 12,
6524
+ fontWeight: "700"
6525
+ },
6107
6526
  summaryCard: {
6108
6527
  marginTop: 20,
6109
6528
  borderRadius: 16,
@@ -6179,7 +6598,7 @@ var styles15 = StyleSheet16.create({
6179
6598
  });
6180
6599
 
6181
6600
  // src/ui/game/ClaimPrizeSheet.tsx
6182
- import { useState as useState32, useEffect as useEffect20, useRef as useRef11, useCallback as useCallback27 } from "react";
6601
+ import { useState as useState35, useEffect as useEffect22, useRef as useRef11, useCallback as useCallback30 } from "react";
6183
6602
  import {
6184
6603
  View as View17,
6185
6604
  Text as Text17,
@@ -6213,15 +6632,15 @@ function ClaimPrizeSheet({
6213
6632
  const overlayOpacity = useRef11(new Animated5.Value(0)).current;
6214
6633
  const celebrationScale = useRef11(new Animated5.Value(0)).current;
6215
6634
  const celebrationOpacity = useRef11(new Animated5.Value(0)).current;
6216
- const [showCelebration, setShowCelebration] = useState32(false);
6217
- useEffect20(() => {
6635
+ const [showCelebration, setShowCelebration] = useState35(false);
6636
+ useEffect22(() => {
6218
6637
  Animated5.timing(overlayOpacity, {
6219
6638
  toValue: visible ? 1 : 0,
6220
6639
  duration: 250,
6221
6640
  useNativeDriver: true
6222
6641
  }).start();
6223
6642
  }, [visible, overlayOpacity]);
6224
- useEffect20(() => {
6643
+ useEffect22(() => {
6225
6644
  if (visible) {
6226
6645
  mutation.reset();
6227
6646
  setShowCelebration(false);
@@ -6229,7 +6648,7 @@ function ClaimPrizeSheet({
6229
6648
  celebrationOpacity.setValue(0);
6230
6649
  }
6231
6650
  }, [visible]);
6232
- useEffect20(() => {
6651
+ useEffect22(() => {
6233
6652
  if (mutation.status === "success" && mutation.data) {
6234
6653
  setShowCelebration(true);
6235
6654
  Animated5.parallel([
@@ -6252,14 +6671,14 @@ function ClaimPrizeSheet({
6252
6671
  return () => clearTimeout(timer);
6253
6672
  }
6254
6673
  }, [mutation.status, mutation.data]);
6255
- useEffect20(() => {
6674
+ useEffect22(() => {
6256
6675
  if (mutation.status === "error" && mutation.error) {
6257
6676
  onError?.(mutation.error);
6258
6677
  }
6259
6678
  }, [mutation.status, mutation.error]);
6260
6679
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
6261
6680
  const canClaim = !isMutating && mutation.status !== "success" && !!wallet.publicKey;
6262
- const handleClaim = useCallback27(async () => {
6681
+ const handleClaim = useCallback30(async () => {
6263
6682
  if (!wallet.publicKey) return;
6264
6683
  try {
6265
6684
  await mutation.execute({
@@ -6492,7 +6911,7 @@ var styles16 = StyleSheet17.create({
6492
6911
  });
6493
6912
 
6494
6913
  // src/ui/game/ClaimButton.tsx
6495
- import { useState as useState33, useMemo as useMemo10, useCallback as useCallback28 } from "react";
6914
+ import { useState as useState36, useMemo as useMemo10, useCallback as useCallback31 } from "react";
6496
6915
  import { StyleSheet as StyleSheet18, Text as Text18, TouchableOpacity as TouchableOpacity13 } from "react-native";
6497
6916
  import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
6498
6917
  function ClaimButton({ gameId, style, onSuccess, onError }) {
@@ -6500,7 +6919,7 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
6500
6919
  const { wallet } = useDubs();
6501
6920
  const game = useGame(gameId);
6502
6921
  const claimStatus = useHasClaimed(gameId);
6503
- const [sheetVisible, setSheetVisible] = useState33(false);
6922
+ const [sheetVisible, setSheetVisible] = useState36(false);
6504
6923
  const walletAddress = wallet.publicKey?.toBase58() ?? null;
6505
6924
  const myBet = useMemo10(() => {
6506
6925
  if (!walletAddress || !game.data?.bettors) return null;
@@ -6511,7 +6930,7 @@ function ClaimButton({ gameId, style, onSuccess, onError }) {
6511
6930
  const isWinner = isResolved && myBet != null && myBet.team === game.data?.winnerSide;
6512
6931
  const isEligible = myBet != null && isResolved && (isWinner || isRefund);
6513
6932
  const prizeAmount = isRefund ? myBet?.amount ?? 0 : game.data?.totalPool ?? 0;
6514
- const handleSuccess = useCallback28(
6933
+ const handleSuccess = useCallback31(
6515
6934
  (result) => {
6516
6935
  claimStatus.refetch();
6517
6936
  onSuccess?.(result);
@@ -6598,7 +7017,7 @@ var styles17 = StyleSheet18.create({
6598
7017
  });
6599
7018
 
6600
7019
  // src/ui/game/EnterArcadePoolSheet.tsx
6601
- import { useEffect as useEffect21, useRef as useRef12, useCallback as useCallback29 } from "react";
7020
+ import { useEffect as useEffect23, useRef as useRef12, useCallback as useCallback32 } from "react";
6602
7021
  import {
6603
7022
  View as View18,
6604
7023
  Text as Text19,
@@ -6630,19 +7049,19 @@ function EnterArcadePoolSheet({
6630
7049
  const { wallet } = useDubs();
6631
7050
  const mutation = useEnterArcadePool();
6632
7051
  const overlayOpacity = useRef12(new Animated6.Value(0)).current;
6633
- useEffect21(() => {
7052
+ useEffect23(() => {
6634
7053
  Animated6.timing(overlayOpacity, {
6635
7054
  toValue: visible ? 1 : 0,
6636
7055
  duration: 250,
6637
7056
  useNativeDriver: true
6638
7057
  }).start();
6639
7058
  }, [visible, overlayOpacity]);
6640
- useEffect21(() => {
7059
+ useEffect23(() => {
6641
7060
  if (visible) {
6642
7061
  mutation.reset();
6643
7062
  }
6644
7063
  }, [visible]);
6645
- useEffect21(() => {
7064
+ useEffect23(() => {
6646
7065
  if (mutation.status === "success" && mutation.data) {
6647
7066
  onSuccess?.(mutation.data);
6648
7067
  const timer = setTimeout(() => {
@@ -6651,7 +7070,7 @@ function EnterArcadePoolSheet({
6651
7070
  return () => clearTimeout(timer);
6652
7071
  }
6653
7072
  }, [mutation.status, mutation.data]);
6654
- useEffect21(() => {
7073
+ useEffect23(() => {
6655
7074
  if (mutation.status === "error" && mutation.error) {
6656
7075
  onError?.(mutation.error);
6657
7076
  }
@@ -6663,7 +7082,7 @@ function EnterArcadePoolSheet({
6663
7082
  const potSol = (pool.buy_in_lamports * Number(totalBuyIns) / 1e9).toFixed(4);
6664
7083
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
6665
7084
  const canJoin = !isMutating && mutation.status !== "success";
6666
- const handleJoin = useCallback29(async () => {
7085
+ const handleJoin = useCallback32(async () => {
6667
7086
  if (!wallet.publicKey) return;
6668
7087
  try {
6669
7088
  await mutation.execute(pool.id);
@@ -6814,7 +7233,7 @@ var styles18 = StyleSheet19.create({
6814
7233
  });
6815
7234
 
6816
7235
  // src/ui/game/ArcadeLeaderboardSheet.tsx
6817
- import { useEffect as useEffect22, useRef as useRef13 } from "react";
7236
+ import { useEffect as useEffect24, useRef as useRef13 } from "react";
6818
7237
  import {
6819
7238
  View as View19,
6820
7239
  Text as Text20,
@@ -6843,14 +7262,14 @@ function ArcadeLeaderboardSheet({
6843
7262
  const t = useDubsTheme();
6844
7263
  const { pool, leaderboard, stats, loading, refetch } = useArcadePool(poolId);
6845
7264
  const overlayOpacity = useRef13(new Animated7.Value(0)).current;
6846
- useEffect22(() => {
7265
+ useEffect24(() => {
6847
7266
  Animated7.timing(overlayOpacity, {
6848
7267
  toValue: visible ? 1 : 0,
6849
7268
  duration: 250,
6850
7269
  useNativeDriver: true
6851
7270
  }).start();
6852
7271
  }, [visible, overlayOpacity]);
6853
- useEffect22(() => {
7272
+ useEffect24(() => {
6854
7273
  if (visible) refetch();
6855
7274
  }, [visible]);
6856
7275
  const renderItem = ({ item, index }) => {
@@ -6997,7 +7416,7 @@ var styles19 = StyleSheet20.create({
6997
7416
  });
6998
7417
 
6999
7418
  // src/ui/game/CreateGameSheet.tsx
7000
- import { useState as useState35, useEffect as useEffect23, useRef as useRef14, useCallback as useCallback30 } from "react";
7419
+ import { useState as useState38, useEffect as useEffect25, useRef as useRef14, useCallback as useCallback33 } from "react";
7001
7420
  import {
7002
7421
  View as View20,
7003
7422
  Text as Text21,
@@ -7036,20 +7455,20 @@ function CreateGameSheet({
7036
7455
  const t = useDubsTheme();
7037
7456
  const { wallet } = useDubs();
7038
7457
  const mutation = useCreateGame();
7039
- const [selectedTeam, setSelectedTeam] = useState35(null);
7040
- const [wager, setWager] = useState35(0.01);
7041
- const [showSuccess, setShowSuccess] = useState35(false);
7458
+ const [selectedTeam, setSelectedTeam] = useState38(null);
7459
+ const [wager, setWager] = useState38(0.01);
7460
+ const [showSuccess, setShowSuccess] = useState38(false);
7042
7461
  const overlayOpacity = useRef14(new Animated8.Value(0)).current;
7043
7462
  const successScale = useRef14(new Animated8.Value(0)).current;
7044
7463
  const successOpacity = useRef14(new Animated8.Value(0)).current;
7045
- useEffect23(() => {
7464
+ useEffect25(() => {
7046
7465
  Animated8.timing(overlayOpacity, {
7047
7466
  toValue: visible ? 1 : 0,
7048
7467
  duration: 250,
7049
7468
  useNativeDriver: true
7050
7469
  }).start();
7051
7470
  }, [visible]);
7052
- useEffect23(() => {
7471
+ useEffect25(() => {
7053
7472
  if (visible) {
7054
7473
  setSelectedTeam(null);
7055
7474
  setWager(0.01);
@@ -7059,7 +7478,7 @@ function CreateGameSheet({
7059
7478
  mutation.reset();
7060
7479
  }
7061
7480
  }, [visible]);
7062
- useEffect23(() => {
7481
+ useEffect25(() => {
7063
7482
  if (mutation.status === "success" && mutation.data) {
7064
7483
  setShowSuccess(true);
7065
7484
  onSuccess?.(mutation.data);
@@ -7076,7 +7495,7 @@ function CreateGameSheet({
7076
7495
  return () => clearTimeout(timer);
7077
7496
  }
7078
7497
  }, [mutation.status, mutation.data]);
7079
- useEffect23(() => {
7498
+ useEffect25(() => {
7080
7499
  if (mutation.status === "error" && mutation.error) {
7081
7500
  onError?.(mutation.error);
7082
7501
  }
@@ -7086,7 +7505,7 @@ function CreateGameSheet({
7086
7505
  const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
7087
7506
  const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
7088
7507
  const canCreate = selectedTeam !== null && !isMutating && mutation.status !== "success";
7089
- const handleCreate = useCallback30(async () => {
7508
+ const handleCreate = useCallback33(async () => {
7090
7509
  if (!selectedTeam || !wallet.publicKey) return;
7091
7510
  try {
7092
7511
  await mutation.execute({
@@ -7232,9 +7651,1500 @@ var styles20 = StyleSheet21.create({
7232
7651
  successTitle: { color: "#FFFFFF", fontSize: 28, fontWeight: "900" },
7233
7652
  successSub: { color: "#8E8E93", fontSize: 16 }
7234
7653
  });
7654
+
7655
+ // src/ui/jackpot/JackpotCard.tsx
7656
+ import { useEffect as useEffect26, useRef as useRef15 } from "react";
7657
+ import {
7658
+ View as View21,
7659
+ Text as Text22,
7660
+ TouchableOpacity as TouchableOpacity17,
7661
+ Animated as Animated9,
7662
+ StyleSheet as StyleSheet22
7663
+ } from "react-native";
7664
+ import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
7665
+ function formatSOL(lamports) {
7666
+ const val = typeof lamports === "string" ? parseInt(lamports, 10) : lamports;
7667
+ if (isNaN(val) || val === 0) return "0";
7668
+ const sol = val / 1e9;
7669
+ if (sol >= 100) return sol.toFixed(0);
7670
+ if (sol >= 1) return sol.toFixed(2);
7671
+ if (sol >= 0.01) return sol.toFixed(3);
7672
+ return sol.toFixed(4);
7673
+ }
7674
+ function truncateWallet2(addr) {
7675
+ if (!addr || addr.length < 8) return addr || "";
7676
+ return `${addr.slice(0, 4)}...${addr.slice(-4)}`;
7677
+ }
7678
+ function JackpotCard({ round, lastWinner, entries, onPress, style }) {
7679
+ const shimmerAnim = useRef15(new Animated9.Value(-1)).current;
7680
+ const pulseAnim = useRef15(new Animated9.Value(0.4)).current;
7681
+ useEffect26(() => {
7682
+ const shimmer = Animated9.loop(
7683
+ Animated9.sequence([
7684
+ Animated9.timing(shimmerAnim, { toValue: 1, duration: 4e3, useNativeDriver: true }),
7685
+ Animated9.delay(500),
7686
+ Animated9.timing(shimmerAnim, { toValue: -1, duration: 0, useNativeDriver: true })
7687
+ ])
7688
+ );
7689
+ shimmer.start();
7690
+ const pulse = Animated9.loop(
7691
+ Animated9.sequence([
7692
+ Animated9.timing(pulseAnim, { toValue: 1, duration: 1e3, useNativeDriver: true }),
7693
+ Animated9.timing(pulseAnim, { toValue: 0.4, duration: 1e3, useNativeDriver: true })
7694
+ ])
7695
+ );
7696
+ pulse.start();
7697
+ return () => {
7698
+ shimmer.stop();
7699
+ pulse.stop();
7700
+ };
7701
+ }, [shimmerAnim, pulseAnim]);
7702
+ const potSol = round ? formatSOL(round.totalPotLamports) : "0";
7703
+ const isOpen = round?.status === "Open";
7704
+ const entryCount = round?.entryCount ?? 0;
7705
+ const totalWeight = round ? Number(BigInt(round.totalWeight || "0")) : 0;
7706
+ return /* @__PURE__ */ jsxs21(
7707
+ TouchableOpacity17,
7708
+ {
7709
+ activeOpacity: 0.9,
7710
+ onPress,
7711
+ style: [styles21.card, style],
7712
+ children: [
7713
+ /* @__PURE__ */ jsx24(View21, { style: styles21.gradientBg }),
7714
+ /* @__PURE__ */ jsx24(
7715
+ Animated9.View,
7716
+ {
7717
+ style: [
7718
+ styles21.shimmer,
7719
+ {
7720
+ transform: [{
7721
+ translateX: shimmerAnim.interpolate({
7722
+ inputRange: [-1, 1],
7723
+ outputRange: [-400, 400]
7724
+ })
7725
+ }]
7726
+ }
7727
+ ]
7728
+ }
7729
+ ),
7730
+ /* @__PURE__ */ jsx24(View21, { style: styles21.accentBar }),
7731
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.content, children: [
7732
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.statusRow, children: [
7733
+ /* @__PURE__ */ jsxs21(View21, { style: [styles21.statusBadge, isOpen ? styles21.statusOpen : styles21.statusClosed], children: [
7734
+ isOpen && /* @__PURE__ */ jsx24(Animated9.View, { style: [styles21.statusDot, { opacity: pulseAnim }] }),
7735
+ /* @__PURE__ */ jsx24(Text22, { style: [styles21.statusText, { color: isOpen ? "#22c55e" : "#9ca3af" }], children: isOpen ? "Open" : round?.status ?? "Loading" })
7736
+ ] }),
7737
+ /* @__PURE__ */ jsxs21(Text22, { style: styles21.entryCountText, children: [
7738
+ entryCount,
7739
+ " player",
7740
+ entryCount !== 1 ? "s" : ""
7741
+ ] })
7742
+ ] }),
7743
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.heroSection, children: [
7744
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.potInfo, children: [
7745
+ /* @__PURE__ */ jsx24(Text22, { style: styles21.jackpotLabel, children: "JACKPOT" }),
7746
+ /* @__PURE__ */ jsxs21(Text22, { style: styles21.potValue, children: [
7747
+ potSol,
7748
+ " SOL"
7749
+ ] })
7750
+ ] }),
7751
+ /* @__PURE__ */ jsx24(Text22, { style: styles21.potEmoji, children: "\u{1F911}" })
7752
+ ] }),
7753
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.infoGrid, children: [
7754
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.infoCard, children: [
7755
+ /* @__PURE__ */ jsx24(Text22, { style: styles21.infoLabel, children: "PLAYERS" }),
7756
+ /* @__PURE__ */ jsx24(Text22, { style: styles21.infoValue, children: entryCount })
7757
+ ] }),
7758
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.infoCard, children: [
7759
+ /* @__PURE__ */ jsx24(Text22, { style: styles21.infoLabel, children: "TOTAL POT" }),
7760
+ /* @__PURE__ */ jsx24(Text22, { style: [styles21.infoValue, { color: "#4ade80" }], children: potSol })
7761
+ ] }),
7762
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.infoCard, children: [
7763
+ /* @__PURE__ */ jsx24(Text22, { style: styles21.infoLabel, children: "LAST WIN" }),
7764
+ /* @__PURE__ */ jsx24(Text22, { style: [styles21.infoValue, { color: "#22c55e" }], children: lastWinner ? formatSOL(lastWinner.winAmount) : "\u2014" })
7765
+ ] })
7766
+ ] }),
7767
+ entries && entries.length > 0 && /* @__PURE__ */ jsxs21(View21, { style: styles21.playersSection, children: [
7768
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.playersSectionHeader, children: [
7769
+ /* @__PURE__ */ jsx24(Text22, { style: styles21.playersSectionTitle, children: "Players in Round" }),
7770
+ /* @__PURE__ */ jsx24(View21, { style: styles21.activeCountBadge, children: /* @__PURE__ */ jsx24(Text22, { style: styles21.activeCountText, children: entries.length }) })
7771
+ ] }),
7772
+ /* @__PURE__ */ jsxs21(View21, { style: styles21.playersCarousel, children: [
7773
+ entries.slice(0, 8).map((entry, i) => {
7774
+ const odds = entry.oddsPercent;
7775
+ return /* @__PURE__ */ jsxs21(View21, { style: styles21.playerCard, children: [
7776
+ /* @__PURE__ */ jsx24(View21, { style: styles21.playerAvatar, children: /* @__PURE__ */ jsx24(Text22, { style: styles21.playerAvatarText, children: entry.player.slice(0, 2).toUpperCase() }) }),
7777
+ /* @__PURE__ */ jsx24(Text22, { style: styles21.playerWallet, numberOfLines: 1, children: truncateWallet2(entry.player) }),
7778
+ /* @__PURE__ */ jsxs21(Text22, { style: styles21.playerWager, children: [
7779
+ entry.weightSol.toFixed(2),
7780
+ " SOL"
7781
+ ] }),
7782
+ /* @__PURE__ */ jsxs21(Text22, { style: styles21.playerOdds, children: [
7783
+ odds,
7784
+ "%"
7785
+ ] })
7786
+ ] }, `${entry.player}-${i}`);
7787
+ }),
7788
+ entries.length > 8 && /* @__PURE__ */ jsx24(View21, { style: styles21.playerCardMore, children: /* @__PURE__ */ jsxs21(Text22, { style: styles21.playerMoreText, children: [
7789
+ "+",
7790
+ entries.length - 8
7791
+ ] }) })
7792
+ ] })
7793
+ ] }),
7794
+ /* @__PURE__ */ jsx24(
7795
+ TouchableOpacity17,
7796
+ {
7797
+ style: styles21.placeBetButton,
7798
+ activeOpacity: 0.85,
7799
+ onPress,
7800
+ children: /* @__PURE__ */ jsx24(Text22, { style: styles21.placeBetText, children: "Place Bet" })
7801
+ }
7802
+ )
7803
+ ] })
7804
+ ]
7805
+ }
7806
+ );
7807
+ }
7808
+ var styles21 = StyleSheet22.create({
7809
+ card: {
7810
+ borderRadius: 16,
7811
+ borderWidth: 1,
7812
+ borderColor: "rgba(34, 197, 94, 0.2)",
7813
+ backgroundColor: "#0c0c14",
7814
+ overflow: "hidden",
7815
+ position: "relative"
7816
+ },
7817
+ gradientBg: {
7818
+ ...StyleSheet22.absoluteFillObject,
7819
+ backgroundColor: "rgba(34, 197, 94, 0.04)"
7820
+ },
7821
+ shimmer: {
7822
+ position: "absolute",
7823
+ top: 0,
7824
+ bottom: 0,
7825
+ width: 120,
7826
+ backgroundColor: "rgba(34, 197, 94, 0.08)"
7827
+ },
7828
+ accentBar: {
7829
+ position: "absolute",
7830
+ bottom: 0,
7831
+ left: 0,
7832
+ right: "40%",
7833
+ height: 2,
7834
+ backgroundColor: "#22c55e"
7835
+ },
7836
+ content: {
7837
+ padding: 16,
7838
+ gap: 12
7839
+ },
7840
+ // Status row
7841
+ statusRow: {
7842
+ flexDirection: "row",
7843
+ alignItems: "center",
7844
+ gap: 8
7845
+ },
7846
+ statusBadge: {
7847
+ flexDirection: "row",
7848
+ alignItems: "center",
7849
+ gap: 6,
7850
+ paddingHorizontal: 10,
7851
+ paddingVertical: 4,
7852
+ borderRadius: 100
7853
+ },
7854
+ statusOpen: {
7855
+ backgroundColor: "rgba(34, 197, 94, 0.15)"
7856
+ },
7857
+ statusClosed: {
7858
+ backgroundColor: "rgba(156, 163, 175, 0.15)"
7859
+ },
7860
+ statusDot: {
7861
+ width: 6,
7862
+ height: 6,
7863
+ borderRadius: 3,
7864
+ backgroundColor: "#22c55e"
7865
+ },
7866
+ statusText: {
7867
+ fontSize: 12,
7868
+ fontWeight: "700"
7869
+ },
7870
+ entryCountText: {
7871
+ fontSize: 12,
7872
+ color: "#6b6b6b",
7873
+ fontWeight: "500"
7874
+ },
7875
+ // Hero pot
7876
+ heroSection: {
7877
+ flexDirection: "row",
7878
+ alignItems: "center",
7879
+ justifyContent: "space-between"
7880
+ },
7881
+ potInfo: {
7882
+ flex: 1
7883
+ },
7884
+ jackpotLabel: {
7885
+ fontSize: 10,
7886
+ fontWeight: "600",
7887
+ color: "#6b6b6b",
7888
+ letterSpacing: 3,
7889
+ textTransform: "uppercase",
7890
+ marginBottom: 4
7891
+ },
7892
+ potValue: {
7893
+ fontSize: 36,
7894
+ fontWeight: "900",
7895
+ color: "#4ade80",
7896
+ letterSpacing: -1
7897
+ },
7898
+ potEmoji: {
7899
+ fontSize: 40,
7900
+ opacity: 0.2
7901
+ },
7902
+ // Info grid
7903
+ infoGrid: {
7904
+ flexDirection: "row",
7905
+ gap: 8
7906
+ },
7907
+ infoCard: {
7908
+ flex: 1,
7909
+ borderRadius: 12,
7910
+ borderWidth: 1,
7911
+ borderColor: "#1e1e2a",
7912
+ backgroundColor: "#0c0c14",
7913
+ padding: 12
7914
+ },
7915
+ infoLabel: {
7916
+ fontSize: 9,
7917
+ fontWeight: "600",
7918
+ color: "#6b6b6b",
7919
+ letterSpacing: 2,
7920
+ textTransform: "uppercase",
7921
+ marginBottom: 4
7922
+ },
7923
+ infoValue: {
7924
+ fontSize: 18,
7925
+ fontWeight: "700",
7926
+ color: "#FFFFFF"
7927
+ },
7928
+ // Players section
7929
+ playersSection: {
7930
+ borderRadius: 12,
7931
+ borderWidth: 1,
7932
+ borderColor: "#1e1e2a",
7933
+ backgroundColor: "rgba(139, 92, 246, 0.04)",
7934
+ padding: 12,
7935
+ overflow: "hidden"
7936
+ },
7937
+ playersSectionHeader: {
7938
+ flexDirection: "row",
7939
+ alignItems: "center",
7940
+ justifyContent: "space-between",
7941
+ marginBottom: 10
7942
+ },
7943
+ playersSectionTitle: {
7944
+ fontSize: 13,
7945
+ fontWeight: "600",
7946
+ color: "#a0a0a0"
7947
+ },
7948
+ activeCountBadge: {
7949
+ backgroundColor: "rgba(34, 197, 94, 0.15)",
7950
+ paddingHorizontal: 8,
7951
+ paddingVertical: 2,
7952
+ borderRadius: 100
7953
+ },
7954
+ activeCountText: {
7955
+ fontSize: 11,
7956
+ fontWeight: "700",
7957
+ color: "#22c55e"
7958
+ },
7959
+ playersCarousel: {
7960
+ flexDirection: "row",
7961
+ gap: 10
7962
+ },
7963
+ playerCard: {
7964
+ width: 96,
7965
+ borderRadius: 12,
7966
+ borderWidth: 1.5,
7967
+ borderColor: "rgba(139, 92, 246, 0.4)",
7968
+ backgroundColor: "rgba(139, 92, 246, 0.08)",
7969
+ padding: 10,
7970
+ alignItems: "center",
7971
+ gap: 4
7972
+ },
7973
+ playerAvatar: {
7974
+ width: 40,
7975
+ height: 40,
7976
+ borderRadius: 20,
7977
+ borderWidth: 1.5,
7978
+ borderColor: "#8b5cf6",
7979
+ backgroundColor: "rgba(139, 92, 246, 0.2)",
7980
+ alignItems: "center",
7981
+ justifyContent: "center"
7982
+ },
7983
+ playerAvatarText: {
7984
+ fontSize: 14,
7985
+ fontWeight: "700",
7986
+ color: "#a78bfa"
7987
+ },
7988
+ playerWallet: {
7989
+ fontSize: 10,
7990
+ fontWeight: "500",
7991
+ color: "#a0a0a0",
7992
+ width: "100%",
7993
+ textAlign: "center"
7994
+ },
7995
+ playerWager: {
7996
+ fontSize: 12,
7997
+ fontWeight: "600",
7998
+ color: "#a78bfa"
7999
+ },
8000
+ playerOdds: {
8001
+ fontSize: 10,
8002
+ fontWeight: "700",
8003
+ color: "#22c55e"
8004
+ },
8005
+ playerCardMore: {
8006
+ width: 96,
8007
+ borderRadius: 12,
8008
+ borderWidth: 1.5,
8009
+ borderColor: "#1e1e2a",
8010
+ backgroundColor: "#14141e",
8011
+ alignItems: "center",
8012
+ justifyContent: "center"
8013
+ },
8014
+ playerMoreText: {
8015
+ fontSize: 16,
8016
+ fontWeight: "700",
8017
+ color: "#6b6b6b"
8018
+ },
8019
+ // Place bet CTA
8020
+ placeBetButton: {
8021
+ height: 52,
8022
+ borderRadius: 12,
8023
+ alignItems: "center",
8024
+ justifyContent: "center",
8025
+ backgroundColor: "#22c55e",
8026
+ shadowColor: "#22c55e",
8027
+ shadowOffset: { width: 0, height: 4 },
8028
+ shadowOpacity: 0.25,
8029
+ shadowRadius: 12,
8030
+ elevation: 6
8031
+ },
8032
+ placeBetText: {
8033
+ color: "#FFFFFF",
8034
+ fontSize: 16,
8035
+ fontWeight: "700"
8036
+ }
8037
+ });
8038
+
8039
+ // src/ui/jackpot/JackpotSheet.tsx
8040
+ import { useState as useState39, useEffect as useEffect27, useRef as useRef16, useCallback as useCallback34 } from "react";
8041
+ import {
8042
+ View as View22,
8043
+ Text as Text23,
8044
+ TouchableOpacity as TouchableOpacity18,
8045
+ ActivityIndicator as ActivityIndicator12,
8046
+ Modal as Modal8,
8047
+ Animated as Animated10,
8048
+ StyleSheet as StyleSheet23,
8049
+ ScrollView as ScrollView5,
8050
+ FlatList as FlatList2,
8051
+ TextInput as TextInput3,
8052
+ Platform as Platform13
8053
+ } from "react-native";
8054
+ import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
8055
+ var STATUS_LABELS7 = {
8056
+ building: "Building transaction...",
8057
+ signing: "Approve in wallet...",
8058
+ confirming: "Confirming entry...",
8059
+ success: "You're in! \u{1F3C6}"
8060
+ };
8061
+ var QUICK_AMOUNTS = [0.1, 0.5, 1];
8062
+ function formatSOL2(lamports) {
8063
+ const val = typeof lamports === "string" ? parseInt(lamports, 10) : lamports;
8064
+ if (isNaN(val) || val === 0) return "0";
8065
+ const sol = val / 1e9;
8066
+ if (sol >= 100) return sol.toFixed(0);
8067
+ if (sol >= 1) return sol.toFixed(2);
8068
+ if (sol >= 0.01) return sol.toFixed(3);
8069
+ return sol.toFixed(4);
8070
+ }
8071
+ function truncateWallet3(addr) {
8072
+ if (!addr || addr.length < 8) return addr || "";
8073
+ return `${addr.slice(0, 4)}...${addr.slice(-4)}`;
8074
+ }
8075
+ function JackpotSheet({
8076
+ visible,
8077
+ onDismiss,
8078
+ onSuccess,
8079
+ onError,
8080
+ minEntry = 0.01,
8081
+ maxEntry = 10
8082
+ }) {
8083
+ const t = useDubsTheme();
8084
+ const { wallet, client } = useDubs();
8085
+ const { round, lastWinner, refetch } = useJackpot();
8086
+ const mutation = useEnterJackpot();
8087
+ const [betAmount, setBetAmount] = useState39("0.1");
8088
+ const [entries, setEntries] = useState39([]);
8089
+ const overlayOpacity = useRef16(new Animated10.Value(0)).current;
8090
+ useEffect27(() => {
8091
+ Animated10.timing(overlayOpacity, {
8092
+ toValue: visible ? 1 : 0,
8093
+ duration: 250,
8094
+ useNativeDriver: true
8095
+ }).start();
8096
+ }, [visible, overlayOpacity]);
8097
+ useEffect27(() => {
8098
+ if (visible) {
8099
+ mutation.reset();
8100
+ setBetAmount("0.1");
8101
+ refetch();
8102
+ client.getJackpotEntries().then((res) => setEntries(res.entries)).catch(() => {
8103
+ });
8104
+ }
8105
+ }, [visible]);
8106
+ useEffect27(() => {
8107
+ if (mutation.status === "success" && mutation.data) {
8108
+ onSuccess?.(mutation.data);
8109
+ refetch();
8110
+ client.getJackpotEntries().then((res) => setEntries(res.entries)).catch(() => {
8111
+ });
8112
+ const timer = setTimeout(() => onDismiss(), 2500);
8113
+ return () => clearTimeout(timer);
8114
+ }
8115
+ }, [mutation.status, mutation.data]);
8116
+ useEffect27(() => {
8117
+ if (mutation.status === "error" && mutation.error) {
8118
+ onError?.(mutation.error);
8119
+ }
8120
+ }, [mutation.status, mutation.error]);
8121
+ const potSol = round ? Number(BigInt(round.totalPotLamports || "0")) / 1e9 : 0;
8122
+ const totalWeight = round ? Number(BigInt(round.totalWeight || "0")) : 0;
8123
+ const betSol = parseFloat(betAmount) || 0;
8124
+ const entryLamports = Math.round(betSol * 1e9);
8125
+ const userOdds = totalWeight > 0 ? (entryLamports / (totalWeight + entryLamports) * 100).toFixed(1) : entries.length === 0 ? "100.0" : "0.0";
8126
+ const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
8127
+ const canEnter = !isMutating && mutation.status !== "success" && round?.status === "Open" && betSol >= minEntry;
8128
+ const handleQuickAdd = useCallback34((amount) => {
8129
+ setBetAmount((prev) => {
8130
+ const current = parseFloat(prev) || 0;
8131
+ const next = Math.min(current + amount, maxEntry);
8132
+ return next.toFixed(2);
8133
+ });
8134
+ }, [maxEntry]);
8135
+ const handleEnter = useCallback34(async () => {
8136
+ if (!wallet.publicKey || entryLamports < 1e4) return;
8137
+ try {
8138
+ await mutation.execute(entryLamports);
8139
+ } catch {
8140
+ }
8141
+ }, [wallet.publicKey, mutation.execute, entryLamports]);
8142
+ const statusLabel = STATUS_LABELS7[mutation.status] || "";
8143
+ const renderPlayerCard = ({ item, index }) => /* @__PURE__ */ jsxs22(View22, { style: styles22.playerCard, children: [
8144
+ /* @__PURE__ */ jsx25(View22, { style: styles22.playerAvatar, children: /* @__PURE__ */ jsx25(Text23, { style: styles22.playerAvatarText, children: item.player.slice(0, 2).toUpperCase() }) }),
8145
+ /* @__PURE__ */ jsxs22(Text23, { style: styles22.playerUsername, numberOfLines: 1, children: [
8146
+ "@",
8147
+ truncateWallet3(item.player)
8148
+ ] }),
8149
+ /* @__PURE__ */ jsx25(View22, { style: styles22.playerWagerRow, children: /* @__PURE__ */ jsxs22(Text23, { style: styles22.playerWagerAmount, children: [
8150
+ item.weightSol.toFixed(2),
8151
+ " SOL"
8152
+ ] }) }),
8153
+ /* @__PURE__ */ jsxs22(Text23, { style: styles22.playerOdds, children: [
8154
+ item.oddsPercent,
8155
+ "%"
8156
+ ] })
8157
+ ] });
8158
+ return /* @__PURE__ */ jsxs22(
8159
+ Modal8,
8160
+ {
8161
+ visible,
8162
+ animationType: "slide",
8163
+ transparent: true,
8164
+ onRequestClose: onDismiss,
8165
+ children: [
8166
+ /* @__PURE__ */ jsx25(Animated10.View, { style: [styles22.overlay, { opacity: overlayOpacity }], children: /* @__PURE__ */ jsx25(TouchableOpacity18, { style: styles22.overlayTap, activeOpacity: 1, onPress: onDismiss }) }),
8167
+ /* @__PURE__ */ jsx25(View22, { style: styles22.sheetPositioner, children: /* @__PURE__ */ jsxs22(View22, { style: styles22.sheet, children: [
8168
+ /* @__PURE__ */ jsx25(View22, { style: styles22.handleRow, children: /* @__PURE__ */ jsx25(View22, { style: styles22.handle }) }),
8169
+ /* @__PURE__ */ jsxs22(
8170
+ ScrollView5,
8171
+ {
8172
+ style: styles22.scrollView,
8173
+ contentContainerStyle: styles22.scrollContent,
8174
+ showsVerticalScrollIndicator: false,
8175
+ bounces: true,
8176
+ children: [
8177
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.header, children: [
8178
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.headerTitle, children: "Jackpot" }),
8179
+ /* @__PURE__ */ jsx25(TouchableOpacity18, { onPress: onDismiss, activeOpacity: 0.8, style: styles22.closeBtn, children: /* @__PURE__ */ jsx25(Text23, { style: styles22.closeBtnText, children: "\u2715" }) })
8180
+ ] }),
8181
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.heroCard, children: [
8182
+ /* @__PURE__ */ jsx25(View22, { style: styles22.heroGradient }),
8183
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.heroLabel, children: "JACKPOT" }),
8184
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.heroPotRow, children: [
8185
+ /* @__PURE__ */ jsxs22(Text23, { style: styles22.heroPotValue, children: [
8186
+ potSol.toFixed(4),
8187
+ " SOL"
8188
+ ] }),
8189
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.heroEmoji, children: "\u{1F911}" })
8190
+ ] }),
8191
+ /* @__PURE__ */ jsx25(View22, { style: styles22.heroAccentBar })
8192
+ ] }),
8193
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.infoRow, children: [
8194
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.infoCard, children: [
8195
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.infoCardLabel, children: "YOUR WAGER" }),
8196
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.infoCardValue, children: betSol.toFixed(2) })
8197
+ ] }),
8198
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.infoCard, children: [
8199
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.infoCardLabel, children: "YOUR CHANCE" }),
8200
+ /* @__PURE__ */ jsxs22(Text23, { style: [styles22.infoCardValue, { color: "#22c55e" }], children: [
8201
+ userOdds,
8202
+ "%"
8203
+ ] })
8204
+ ] }),
8205
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.infoCard, children: [
8206
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.infoCardLabel, children: "PLAYERS" }),
8207
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.infoCardValue, children: entries.length })
8208
+ ] })
8209
+ ] }),
8210
+ entries.length > 0 && /* @__PURE__ */ jsxs22(View22, { style: styles22.playersSection, children: [
8211
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.playersSectionHeader, children: [
8212
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.playersSectionTitle, children: "Players in Round" }),
8213
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.playersBadge, children: [
8214
+ /* @__PURE__ */ jsx25(View22, { style: styles22.playersBadgeDot }),
8215
+ /* @__PURE__ */ jsxs22(Text23, { style: styles22.playersBadgeText, children: [
8216
+ entries.length,
8217
+ " active"
8218
+ ] })
8219
+ ] })
8220
+ ] }),
8221
+ /* @__PURE__ */ jsx25(
8222
+ FlatList2,
8223
+ {
8224
+ data: entries,
8225
+ renderItem: renderPlayerCard,
8226
+ keyExtractor: (item, i) => `${item.player}-${i}`,
8227
+ horizontal: true,
8228
+ showsHorizontalScrollIndicator: false,
8229
+ contentContainerStyle: styles22.playersListContent,
8230
+ ItemSeparatorComponent: () => /* @__PURE__ */ jsx25(View22, { style: { width: 10 } })
8231
+ }
8232
+ )
8233
+ ] }),
8234
+ entries.length === 0 && /* @__PURE__ */ jsxs22(View22, { style: styles22.emptyState, children: [
8235
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.emptyEmoji, children: "\u{1F911}" }),
8236
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.emptyTitle, children: "No players yet" }),
8237
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.emptySubtitle, children: "Be the first to join!" })
8238
+ ] }),
8239
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.betSection, children: [
8240
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.betLabel, children: "Bet Amount" }),
8241
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.betInputRow, children: [
8242
+ /* @__PURE__ */ jsx25(View22, { style: styles22.solIcon, children: /* @__PURE__ */ jsx25(Text23, { style: styles22.solIconText, children: "\u25CE" }) }),
8243
+ /* @__PURE__ */ jsx25(
8244
+ TextInput3,
8245
+ {
8246
+ style: styles22.betInput,
8247
+ value: betAmount,
8248
+ onChangeText: setBetAmount,
8249
+ keyboardType: "decimal-pad",
8250
+ placeholder: "0.00",
8251
+ placeholderTextColor: "#6b6b6b",
8252
+ selectTextOnFocus: true
8253
+ }
8254
+ ),
8255
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.betInputSuffix, children: "SOL" })
8256
+ ] }),
8257
+ /* @__PURE__ */ jsx25(View22, { style: styles22.quickBetRow, children: QUICK_AMOUNTS.map((amount) => /* @__PURE__ */ jsx25(
8258
+ TouchableOpacity18,
8259
+ {
8260
+ style: styles22.quickBetBtn,
8261
+ onPress: () => handleQuickAdd(amount),
8262
+ activeOpacity: 0.7,
8263
+ children: /* @__PURE__ */ jsxs22(Text23, { style: styles22.quickBetText, children: [
8264
+ "+",
8265
+ amount,
8266
+ " SOL"
8267
+ ] })
8268
+ },
8269
+ amount
8270
+ )) })
8271
+ ] }),
8272
+ mutation.error && /* @__PURE__ */ jsx25(View22, { style: styles22.errorBox, children: /* @__PURE__ */ jsx25(Text23, { style: styles22.errorText, children: mutation.error.message }) }),
8273
+ /* @__PURE__ */ jsx25(
8274
+ TouchableOpacity18,
8275
+ {
8276
+ style: [
8277
+ styles22.placeBetBtn,
8278
+ !canEnter && styles22.placeBetBtnDisabled,
8279
+ mutation.status === "success" && styles22.placeBetBtnSuccess
8280
+ ],
8281
+ disabled: !canEnter,
8282
+ onPress: handleEnter,
8283
+ activeOpacity: 0.85,
8284
+ children: isMutating ? /* @__PURE__ */ jsxs22(View22, { style: styles22.placeBetLoading, children: [
8285
+ /* @__PURE__ */ jsx25(ActivityIndicator12, { size: "small", color: "#FFFFFF" }),
8286
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.placeBetText, children: statusLabel })
8287
+ ] }) : mutation.status === "success" ? /* @__PURE__ */ jsx25(Text23, { style: styles22.placeBetText, children: "You're in! \u{1F3C6}" }) : /* @__PURE__ */ jsxs22(Text23, { style: [styles22.placeBetText, !canEnter && { opacity: 0.5 }], children: [
8288
+ "Place Bet \u2014 ",
8289
+ betSol.toFixed(2),
8290
+ " SOL"
8291
+ ] })
8292
+ }
8293
+ ),
8294
+ lastWinner && /* @__PURE__ */ jsxs22(View22, { style: styles22.lastWinnerSection, children: [
8295
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.lastWinnerLabel, children: "Last Winner" }),
8296
+ /* @__PURE__ */ jsxs22(View22, { style: styles22.lastWinnerRow, children: [
8297
+ /* @__PURE__ */ jsx25(Text23, { style: styles22.lastWinnerWallet, children: truncateWallet3(lastWinner.winner) }),
8298
+ /* @__PURE__ */ jsxs22(Text23, { style: styles22.lastWinnerAmount, children: [
8299
+ "won ",
8300
+ formatSOL2(lastWinner.winAmount),
8301
+ " SOL"
8302
+ ] })
8303
+ ] })
8304
+ ] })
8305
+ ]
8306
+ }
8307
+ )
8308
+ ] }) })
8309
+ ]
8310
+ }
8311
+ );
8312
+ }
8313
+ var styles22 = StyleSheet23.create({
8314
+ overlay: {
8315
+ ...StyleSheet23.absoluteFillObject,
8316
+ backgroundColor: "rgba(0,0,0,0.65)"
8317
+ },
8318
+ overlayTap: { flex: 1 },
8319
+ sheetPositioner: {
8320
+ flex: 1,
8321
+ justifyContent: "flex-end"
8322
+ },
8323
+ sheet: {
8324
+ backgroundColor: "#08080e",
8325
+ borderTopLeftRadius: 24,
8326
+ borderTopRightRadius: 24,
8327
+ maxHeight: "92%",
8328
+ borderWidth: 1,
8329
+ borderColor: "#1e1e2a",
8330
+ borderBottomWidth: 0
8331
+ },
8332
+ handleRow: { alignItems: "center", paddingTop: 10, paddingBottom: 4 },
8333
+ handle: { width: 36, height: 4, borderRadius: 2, backgroundColor: "#2a2a3a" },
8334
+ scrollView: { flexGrow: 0 },
8335
+ scrollContent: {
8336
+ paddingHorizontal: 16,
8337
+ paddingBottom: Platform13.OS === "ios" ? 40 : 24
8338
+ },
8339
+ // Header
8340
+ header: {
8341
+ flexDirection: "row",
8342
+ alignItems: "center",
8343
+ justifyContent: "space-between",
8344
+ paddingVertical: 12
8345
+ },
8346
+ headerTitle: { fontSize: 20, fontWeight: "700", color: "#FFFFFF" },
8347
+ closeBtn: { padding: 4 },
8348
+ closeBtnText: { fontSize: 20, color: "#6b6b6b" },
8349
+ // Hero pot card
8350
+ heroCard: {
8351
+ borderRadius: 16,
8352
+ borderWidth: 1,
8353
+ borderColor: "rgba(34, 197, 94, 0.2)",
8354
+ padding: 16,
8355
+ overflow: "hidden",
8356
+ position: "relative"
8357
+ },
8358
+ heroGradient: {
8359
+ ...StyleSheet23.absoluteFillObject,
8360
+ backgroundColor: "rgba(34, 197, 94, 0.04)"
8361
+ },
8362
+ heroLabel: {
8363
+ fontSize: 10,
8364
+ fontWeight: "600",
8365
+ color: "#6b6b6b",
8366
+ letterSpacing: 3,
8367
+ marginBottom: 4
8368
+ },
8369
+ heroPotRow: {
8370
+ flexDirection: "row",
8371
+ alignItems: "center",
8372
+ justifyContent: "space-between"
8373
+ },
8374
+ heroPotValue: {
8375
+ fontSize: 32,
8376
+ fontWeight: "900",
8377
+ color: "#4ade80",
8378
+ letterSpacing: -1
8379
+ },
8380
+ heroEmoji: {
8381
+ fontSize: 36,
8382
+ opacity: 0.2
8383
+ },
8384
+ heroAccentBar: {
8385
+ position: "absolute",
8386
+ bottom: 0,
8387
+ left: 0,
8388
+ width: "60%",
8389
+ height: 2,
8390
+ backgroundColor: "#22c55e"
8391
+ },
8392
+ // Info row
8393
+ infoRow: {
8394
+ flexDirection: "row",
8395
+ gap: 8,
8396
+ marginTop: 12
8397
+ },
8398
+ infoCard: {
8399
+ flex: 1,
8400
+ borderRadius: 12,
8401
+ borderWidth: 1,
8402
+ borderColor: "#1e1e2a",
8403
+ backgroundColor: "#0c0c14",
8404
+ padding: 12
8405
+ },
8406
+ infoCardLabel: {
8407
+ fontSize: 9,
8408
+ fontWeight: "600",
8409
+ color: "#6b6b6b",
8410
+ letterSpacing: 2,
8411
+ marginBottom: 4
8412
+ },
8413
+ infoCardValue: {
8414
+ fontSize: 18,
8415
+ fontWeight: "700",
8416
+ color: "#FFFFFF"
8417
+ },
8418
+ // Players section
8419
+ playersSection: {
8420
+ marginTop: 16,
8421
+ borderRadius: 16,
8422
+ borderWidth: 1,
8423
+ borderColor: "#1e1e2a",
8424
+ backgroundColor: "rgba(139, 92, 246, 0.03)",
8425
+ padding: 12,
8426
+ overflow: "hidden"
8427
+ },
8428
+ playersSectionHeader: {
8429
+ flexDirection: "row",
8430
+ alignItems: "center",
8431
+ justifyContent: "space-between",
8432
+ marginBottom: 12
8433
+ },
8434
+ playersSectionTitle: {
8435
+ fontSize: 13,
8436
+ fontWeight: "600",
8437
+ color: "#a0a0a0"
8438
+ },
8439
+ playersBadge: {
8440
+ flexDirection: "row",
8441
+ alignItems: "center",
8442
+ gap: 6,
8443
+ backgroundColor: "rgba(34, 197, 94, 0.15)",
8444
+ paddingHorizontal: 8,
8445
+ paddingVertical: 3,
8446
+ borderRadius: 100
8447
+ },
8448
+ playersBadgeDot: {
8449
+ width: 6,
8450
+ height: 6,
8451
+ borderRadius: 3,
8452
+ backgroundColor: "#22c55e"
8453
+ },
8454
+ playersBadgeText: {
8455
+ fontSize: 11,
8456
+ fontWeight: "700",
8457
+ color: "#22c55e"
8458
+ },
8459
+ playersListContent: {
8460
+ paddingRight: 4
8461
+ },
8462
+ // Player cards (carousel items)
8463
+ playerCard: {
8464
+ width: 110,
8465
+ borderRadius: 12,
8466
+ borderWidth: 1.5,
8467
+ borderColor: "rgba(139, 92, 246, 0.4)",
8468
+ backgroundColor: "rgba(139, 92, 246, 0.08)",
8469
+ padding: 12,
8470
+ alignItems: "center",
8471
+ gap: 6
8472
+ },
8473
+ playerAvatar: {
8474
+ width: 48,
8475
+ height: 48,
8476
+ borderRadius: 24,
8477
+ borderWidth: 2,
8478
+ borderColor: "#8b5cf6",
8479
+ backgroundColor: "rgba(139, 92, 246, 0.15)",
8480
+ alignItems: "center",
8481
+ justifyContent: "center"
8482
+ },
8483
+ playerAvatarText: {
8484
+ fontSize: 16,
8485
+ fontWeight: "700",
8486
+ color: "#a78bfa"
8487
+ },
8488
+ playerUsername: {
8489
+ fontSize: 11,
8490
+ fontWeight: "500",
8491
+ color: "#a0a0a0",
8492
+ textAlign: "center"
8493
+ },
8494
+ playerWagerRow: {
8495
+ flexDirection: "row",
8496
+ alignItems: "center",
8497
+ gap: 4
8498
+ },
8499
+ playerWagerAmount: {
8500
+ fontSize: 13,
8501
+ fontWeight: "600",
8502
+ color: "#a78bfa"
8503
+ },
8504
+ playerOdds: {
8505
+ fontSize: 11,
8506
+ fontWeight: "700",
8507
+ color: "#22c55e"
8508
+ },
8509
+ // Empty state
8510
+ emptyState: {
8511
+ marginTop: 16,
8512
+ alignItems: "center",
8513
+ paddingVertical: 24,
8514
+ borderRadius: 16,
8515
+ borderWidth: 1,
8516
+ borderColor: "#1e1e2a",
8517
+ backgroundColor: "#0c0c14"
8518
+ },
8519
+ emptyEmoji: { fontSize: 40, marginBottom: 8 },
8520
+ emptyTitle: { fontSize: 16, fontWeight: "600", color: "#FFFFFF" },
8521
+ emptySubtitle: { fontSize: 13, color: "#6b6b6b", marginTop: 4 },
8522
+ // Bet section
8523
+ betSection: {
8524
+ marginTop: 16
8525
+ },
8526
+ betLabel: {
8527
+ fontSize: 13,
8528
+ fontWeight: "500",
8529
+ color: "#6b6b6b",
8530
+ marginBottom: 8
8531
+ },
8532
+ betInputRow: {
8533
+ flexDirection: "row",
8534
+ alignItems: "center",
8535
+ gap: 8,
8536
+ backgroundColor: "#08080e",
8537
+ borderWidth: 1,
8538
+ borderColor: "#2a2a3a",
8539
+ borderRadius: 12,
8540
+ paddingHorizontal: 14,
8541
+ paddingVertical: Platform13.OS === "ios" ? 14 : 10
8542
+ },
8543
+ solIcon: {
8544
+ width: 32,
8545
+ height: 32,
8546
+ borderRadius: 16,
8547
+ backgroundColor: "rgba(139, 92, 246, 0.15)",
8548
+ alignItems: "center",
8549
+ justifyContent: "center"
8550
+ },
8551
+ solIconText: {
8552
+ fontSize: 18,
8553
+ color: "#a78bfa",
8554
+ fontWeight: "700"
8555
+ },
8556
+ betInput: {
8557
+ flex: 1,
8558
+ fontSize: 24,
8559
+ fontWeight: "700",
8560
+ color: "#FFFFFF",
8561
+ padding: 0
8562
+ },
8563
+ betInputSuffix: {
8564
+ fontSize: 14,
8565
+ fontWeight: "500",
8566
+ color: "#6b6b6b"
8567
+ },
8568
+ quickBetRow: {
8569
+ flexDirection: "row",
8570
+ gap: 8,
8571
+ marginTop: 10
8572
+ },
8573
+ quickBetBtn: {
8574
+ flex: 1,
8575
+ paddingVertical: 12,
8576
+ borderRadius: 10,
8577
+ borderWidth: 1,
8578
+ borderColor: "#2a2a3a",
8579
+ backgroundColor: "#08080e",
8580
+ alignItems: "center"
8581
+ },
8582
+ quickBetText: {
8583
+ fontSize: 13,
8584
+ fontWeight: "600",
8585
+ color: "#FFFFFF"
8586
+ },
8587
+ // Error
8588
+ errorBox: {
8589
+ marginTop: 12,
8590
+ borderRadius: 12,
8591
+ borderWidth: 1,
8592
+ borderColor: "#3A1515",
8593
+ backgroundColor: "#1A0A0A",
8594
+ padding: 12
8595
+ },
8596
+ errorText: { fontSize: 13, fontWeight: "500", color: "#F87171" },
8597
+ // Place Bet CTA
8598
+ placeBetBtn: {
8599
+ marginTop: 16,
8600
+ height: 56,
8601
+ borderRadius: 14,
8602
+ justifyContent: "center",
8603
+ alignItems: "center",
8604
+ backgroundColor: "#22c55e",
8605
+ shadowColor: "#22c55e",
8606
+ shadowOffset: { width: 0, height: 4 },
8607
+ shadowOpacity: 0.25,
8608
+ shadowRadius: 12,
8609
+ elevation: 6
8610
+ },
8611
+ placeBetBtnDisabled: {
8612
+ backgroundColor: "#1e1e2a",
8613
+ shadowOpacity: 0,
8614
+ elevation: 0
8615
+ },
8616
+ placeBetBtnSuccess: {
8617
+ backgroundColor: "#16a34a"
8618
+ },
8619
+ placeBetText: { color: "#FFFFFF", fontSize: 16, fontWeight: "700" },
8620
+ placeBetLoading: { flexDirection: "row", alignItems: "center", gap: 10 },
8621
+ // Last winner
8622
+ lastWinnerSection: {
8623
+ marginTop: 14,
8624
+ paddingTop: 14,
8625
+ borderTopWidth: 1,
8626
+ borderTopColor: "#1e1e2a"
8627
+ },
8628
+ lastWinnerLabel: {
8629
+ fontSize: 11,
8630
+ fontWeight: "600",
8631
+ color: "#6b6b6b",
8632
+ letterSpacing: 1,
8633
+ textTransform: "uppercase",
8634
+ marginBottom: 4
8635
+ },
8636
+ lastWinnerRow: {
8637
+ flexDirection: "row",
8638
+ alignItems: "center",
8639
+ gap: 6
8640
+ },
8641
+ lastWinnerWallet: {
8642
+ fontSize: 13,
8643
+ fontWeight: "500",
8644
+ color: "#a0a0a0"
8645
+ },
8646
+ lastWinnerAmount: {
8647
+ fontSize: 13,
8648
+ fontWeight: "600",
8649
+ color: "#22c55e"
8650
+ }
8651
+ });
8652
+
8653
+ // src/ui/jackpot/JackpotWidget.tsx
8654
+ import { useState as useState40, useEffect as useEffect28 } from "react";
8655
+ import { Fragment as Fragment7, jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
8656
+ function JackpotWidget({
8657
+ style,
8658
+ minEntry,
8659
+ maxEntry,
8660
+ onEntry,
8661
+ onError
8662
+ }) {
8663
+ const [sheetVisible, setSheetVisible] = useState40(false);
8664
+ const { round, lastWinner } = useJackpot();
8665
+ const { client } = useDubs();
8666
+ const [entries, setEntries] = useState40([]);
8667
+ useEffect28(() => {
8668
+ client.getJackpotEntries().then((res) => setEntries(res.entries)).catch(() => {
8669
+ });
8670
+ }, [client, round?.entryCount]);
8671
+ return /* @__PURE__ */ jsxs23(Fragment7, { children: [
8672
+ /* @__PURE__ */ jsx26(
8673
+ JackpotCard,
8674
+ {
8675
+ round,
8676
+ lastWinner,
8677
+ entries,
8678
+ onPress: () => setSheetVisible(true),
8679
+ style
8680
+ }
8681
+ ),
8682
+ /* @__PURE__ */ jsx26(
8683
+ JackpotSheet,
8684
+ {
8685
+ visible: sheetVisible,
8686
+ onDismiss: () => setSheetVisible(false),
8687
+ onSuccess: (result) => {
8688
+ onEntry?.(result);
8689
+ client.getJackpotEntries().then((res) => setEntries(res.entries)).catch(() => {
8690
+ });
8691
+ },
8692
+ onError,
8693
+ minEntry,
8694
+ maxEntry
8695
+ }
8696
+ )
8697
+ ] });
8698
+ }
8699
+
8700
+ // src/chat/provider.tsx
8701
+ import { createContext as createContext5, useContext as useContext5, useEffect as useEffect29, useRef as useRef17, useState as useState41, useCallback as useCallback35, useMemo as useMemo11 } from "react";
8702
+ import { AppState } from "react-native";
8703
+
8704
+ // src/chat/socket.ts
8705
+ import { io } from "socket.io-client";
8706
+ var ChatSocket = class {
8707
+ constructor() {
8708
+ this.socket = null;
8709
+ this.listeners = {};
8710
+ }
8711
+ /** Set event listeners. Call before or after connect. */
8712
+ setListeners(listeners) {
8713
+ this.listeners = listeners;
8714
+ }
8715
+ /** Connect to the /chat namespace */
8716
+ connect(config) {
8717
+ if (this.socket?.connected) {
8718
+ console.log("[Dubs:ChatSocket] Already connected");
8719
+ return;
8720
+ }
8721
+ this.listeners.onConnectionChange?.("connecting");
8722
+ console.log(`[Dubs:ChatSocket] Connecting to ${config.host}/chat`);
8723
+ this.socket = io(`${config.host}/chat`, {
8724
+ auth: { token: config.token },
8725
+ transports: ["websocket"],
8726
+ reconnection: true,
8727
+ reconnectionDelay: 1e3,
8728
+ reconnectionAttempts: 10
8729
+ });
8730
+ this.socket.on("connect", () => {
8731
+ console.log("[Dubs:ChatSocket] Connected");
8732
+ this.listeners.onConnectionChange?.("connected");
8733
+ });
8734
+ this.socket.on("disconnect", (reason) => {
8735
+ console.log("[Dubs:ChatSocket] Disconnected:", reason);
8736
+ this.listeners.onConnectionChange?.("disconnected");
8737
+ });
8738
+ this.socket.on("connect_error", (error) => {
8739
+ console.error("[Dubs:ChatSocket] Connection error:", error.message);
8740
+ this.listeners.onConnectionChange?.("error");
8741
+ });
8742
+ this.socket.on("new_message", (msg) => this.listeners.onNewMessage?.(msg));
8743
+ this.socket.on("online_users", (users) => this.listeners.onOnlineUsers?.(users));
8744
+ this.socket.on("online_count", (count) => this.listeners.onOnlineCount?.(count));
8745
+ this.socket.on("user_typing", (data) => this.listeners.onTyping?.(data));
8746
+ this.socket.on("reaction_added", (data) => this.listeners.onReactionAdded?.(data));
8747
+ this.socket.on("reaction_removed", (data) => this.listeners.onReactionRemoved?.(data));
8748
+ this.socket.on("notification", (n) => this.listeners.onNotification?.(n));
8749
+ this.socket.on("unread_count", (count) => this.listeners.onUnreadCount?.(count));
8750
+ this.socket.on("dm:new_message", (msg) => this.listeners.onDMNewMessage?.(msg));
8751
+ this.socket.on("dm:message_sent", (msg) => this.listeners.onDMMessageSent?.(msg));
8752
+ this.socket.on("dm:notification", (data) => this.listeners.onDMNotification?.(data));
8753
+ this.socket.on("dm:messages_read", (data) => this.listeners.onDMMessagesRead?.(data));
8754
+ this.socket.on("friend_request_accepted", (data) => this.listeners.onFriendRequestAccepted?.(data));
8755
+ this.socket.on("friend_request_declined", (data) => this.listeners.onFriendRequestDeclined?.(data));
8756
+ this.socket.on("friend_removed", (data) => this.listeners.onFriendRemoved?.(data));
8757
+ this.socket.on("error", (err) => this.listeners.onError?.(err));
8758
+ }
8759
+ /** Disconnect from the chat namespace */
8760
+ disconnect() {
8761
+ if (this.socket) {
8762
+ console.log("[Dubs:ChatSocket] Disconnecting");
8763
+ this.socket.removeAllListeners();
8764
+ this.socket.disconnect();
8765
+ this.socket = null;
8766
+ }
8767
+ }
8768
+ /** Whether the socket is currently connected */
8769
+ isConnected() {
8770
+ return this.socket?.connected ?? false;
8771
+ }
8772
+ // ── Global Chat Actions ──
8773
+ /** Send a message to global chat */
8774
+ sendMessage(params) {
8775
+ this.socket?.emit("send_message", params);
8776
+ }
8777
+ /** Emit typing indicator */
8778
+ sendTyping(isTyping) {
8779
+ this.socket?.emit("typing", isTyping);
8780
+ }
8781
+ /** Add an emoji reaction to a message */
8782
+ addReaction(messageId, reaction) {
8783
+ this.socket?.emit("add_reaction", { messageId, reaction });
8784
+ }
8785
+ /** Remove an emoji reaction from a message */
8786
+ removeReaction(messageId, reaction) {
8787
+ this.socket?.emit("remove_reaction", { messageId, reaction });
8788
+ }
8789
+ // ── DM Actions ──
8790
+ /** Join a DM room to receive messages in real-time */
8791
+ joinDM(recipientWallet) {
8792
+ this.socket?.emit("dm:join", { recipientWallet });
8793
+ }
8794
+ /** Leave a DM room */
8795
+ leaveDM(recipientWallet) {
8796
+ this.socket?.emit("dm:leave", { recipientWallet });
8797
+ }
8798
+ /** Send a direct message via socket */
8799
+ sendDM(params) {
8800
+ this.socket?.emit("dm:send", params);
8801
+ }
8802
+ /** Mark DMs from a sender as read */
8803
+ markDMRead(senderWallet) {
8804
+ this.socket?.emit("dm:mark_read", { senderWallet });
8805
+ }
8806
+ };
8807
+
8808
+ // src/chat/provider.tsx
8809
+ import { jsx as jsx27 } from "react/jsx-runtime";
8810
+ var ChatContext = createContext5(null);
8811
+ function ChatProvider({ children, autoConnect = true }) {
8812
+ const { client } = useDubs();
8813
+ const socketRef = useRef17(new ChatSocket());
8814
+ const [status, setStatus] = useState41("disconnected");
8815
+ const [messages, setMessages] = useState41([]);
8816
+ const [onlineUsers, setOnlineUsers] = useState41([]);
8817
+ const [onlineCount, setOnlineCount] = useState41(0);
8818
+ const [unreadCount, setUnreadCount] = useState41(0);
8819
+ const [conversations, setConversations] = useState41([]);
8820
+ const [friends, setFriends] = useState41([]);
8821
+ const [pendingRequests, setPendingRequests] = useState41([]);
8822
+ const refreshMessages = useCallback35(async () => {
8823
+ try {
8824
+ const res = await client.getChatMessages({ limit: 30 });
8825
+ setMessages(res.messages);
8826
+ } catch (err) {
8827
+ console.error("[Dubs:ChatProvider] Failed to load messages:", err);
8828
+ }
8829
+ }, [client]);
8830
+ const refreshConversations = useCallback35(async () => {
8831
+ try {
8832
+ const res = await client.getConversations();
8833
+ setConversations(res.conversations);
8834
+ } catch (_) {
8835
+ }
8836
+ }, [client]);
8837
+ const refreshFriends = useCallback35(async () => {
8838
+ try {
8839
+ const res = await client.getFriends();
8840
+ setFriends(res.friends);
8841
+ } catch (_) {
8842
+ }
8843
+ }, [client]);
8844
+ const refreshPendingRequests = useCallback35(async () => {
8845
+ try {
8846
+ const res = await client.getPendingFriendRequests();
8847
+ setPendingRequests(res.requests);
8848
+ } catch (_) {
8849
+ }
8850
+ }, [client]);
8851
+ useEffect29(() => {
8852
+ const token = client.getToken();
8853
+ if (!autoConnect || !token) return;
8854
+ const chatSocket = socketRef.current;
8855
+ const baseUrl = client.baseUrl;
8856
+ const host = new URL(baseUrl).origin;
8857
+ chatSocket.setListeners({
8858
+ onConnectionChange: setStatus,
8859
+ // Global chat
8860
+ onNewMessage: (msg) => {
8861
+ setMessages((prev) => {
8862
+ if (prev.some((m) => m.id === msg.id)) return prev;
8863
+ return [msg, ...prev];
8864
+ });
8865
+ },
8866
+ onOnlineUsers: setOnlineUsers,
8867
+ onOnlineCount: setOnlineCount,
8868
+ onUnreadCount: setUnreadCount,
8869
+ // Notifications trigger conversation refresh
8870
+ onDMNotification: () => {
8871
+ refreshConversations();
8872
+ },
8873
+ onNotification: (n) => {
8874
+ setUnreadCount((prev) => prev + 1);
8875
+ if (n.type === "friend_request") refreshPendingRequests();
8876
+ if (n.type === "friend_request_accepted") refreshFriends();
8877
+ },
8878
+ onFriendRequestAccepted: () => refreshFriends(),
8879
+ onFriendRemoved: () => refreshFriends()
8880
+ });
8881
+ chatSocket.connect({ host, token });
8882
+ refreshMessages();
8883
+ refreshFriends().catch(() => {
8884
+ });
8885
+ refreshPendingRequests().catch(() => {
8886
+ });
8887
+ return () => {
8888
+ chatSocket.disconnect();
8889
+ };
8890
+ }, [client, autoConnect, refreshMessages, refreshConversations, refreshFriends, refreshPendingRequests]);
8891
+ useEffect29(() => {
8892
+ const handleAppState = (nextState) => {
8893
+ if (nextState === "active") {
8894
+ const chatSocket = socketRef.current;
8895
+ if (!chatSocket.isConnected()) {
8896
+ const token = client.getToken();
8897
+ if (token) {
8898
+ const baseUrl = client.baseUrl;
8899
+ const host = new URL(baseUrl).origin;
8900
+ chatSocket.connect({ host, token });
8901
+ }
8902
+ }
8903
+ refreshMessages();
8904
+ }
8905
+ };
8906
+ const sub = AppState.addEventListener("change", handleAppState);
8907
+ return () => sub.remove();
8908
+ }, [client, refreshMessages, refreshConversations]);
8909
+ const value = useMemo11(
8910
+ () => ({
8911
+ socket: socketRef.current,
8912
+ status,
8913
+ messages,
8914
+ onlineUsers,
8915
+ onlineCount,
8916
+ unreadCount,
8917
+ conversations,
8918
+ friends,
8919
+ pendingRequests,
8920
+ refreshMessages,
8921
+ refreshConversations,
8922
+ refreshFriends,
8923
+ refreshPendingRequests
8924
+ }),
8925
+ [status, messages, onlineUsers, onlineCount, unreadCount, conversations, friends, pendingRequests, refreshMessages, refreshConversations, refreshFriends, refreshPendingRequests]
8926
+ );
8927
+ return /* @__PURE__ */ jsx27(ChatContext.Provider, { value, children });
8928
+ }
8929
+ function useChatContext() {
8930
+ const ctx = useContext5(ChatContext);
8931
+ if (!ctx) {
8932
+ throw new Error("useChatContext must be used inside a <ChatProvider>");
8933
+ }
8934
+ return ctx;
8935
+ }
8936
+
8937
+ // src/chat/hooks.ts
8938
+ import { useState as useState42, useCallback as useCallback36, useEffect as useEffect30, useRef as useRef18 } from "react";
8939
+ function useChatStatus() {
8940
+ return useChatContext().status;
8941
+ }
8942
+ function useChatMessages() {
8943
+ const { messages, refreshMessages } = useChatContext();
8944
+ const [loading, setLoading] = useState42(false);
8945
+ const refetch = useCallback36(async () => {
8946
+ setLoading(true);
8947
+ await refreshMessages();
8948
+ setLoading(false);
8949
+ }, [refreshMessages]);
8950
+ return { messages, loading, refetch };
8951
+ }
8952
+ function useSendMessage() {
8953
+ const { socket } = useChatContext();
8954
+ const { client } = useDubs();
8955
+ const send = useCallback36(
8956
+ (params) => {
8957
+ socket.sendMessage(params);
8958
+ },
8959
+ [socket]
8960
+ );
8961
+ const sendViaREST = useCallback36(
8962
+ async (params) => {
8963
+ await client.sendChatMessage(params);
8964
+ },
8965
+ [client]
8966
+ );
8967
+ return { send, sendViaREST };
8968
+ }
8969
+ function useOnlineUsers() {
8970
+ const { onlineUsers, onlineCount } = useChatContext();
8971
+ return { users: onlineUsers, count: onlineCount };
8972
+ }
8973
+ function useUnreadCount() {
8974
+ return useChatContext().unreadCount;
8975
+ }
8976
+ function useConversations() {
8977
+ const { conversations, refreshConversations } = useChatContext();
8978
+ const [loading, setLoading] = useState42(false);
8979
+ const refetch = useCallback36(async () => {
8980
+ setLoading(true);
8981
+ await refreshConversations();
8982
+ setLoading(false);
8983
+ }, [refreshConversations]);
8984
+ return { conversations, loading, refetch };
8985
+ }
8986
+ function useDirectMessages(recipientWallet) {
8987
+ const { client } = useDubs();
8988
+ const { socket, refreshConversations } = useChatContext();
8989
+ const [messages, setMessages] = useState42([]);
8990
+ const [otherUser, setOtherUser] = useState42(null);
8991
+ const [loading, setLoading] = useState42(true);
8992
+ const refetch = useCallback36(async () => {
8993
+ try {
8994
+ setLoading(true);
8995
+ const res = await client.getConversation(recipientWallet);
8996
+ setMessages(res.messages);
8997
+ setOtherUser(res.otherUser);
8998
+ } catch (err) {
8999
+ console.error("[Dubs:useDirectMessages] Error loading:", err);
9000
+ } finally {
9001
+ setLoading(false);
9002
+ }
9003
+ }, [client, recipientWallet]);
9004
+ useEffect30(() => {
9005
+ refetch();
9006
+ socket.joinDM(recipientWallet);
9007
+ return () => {
9008
+ socket.leaveDM(recipientWallet);
9009
+ };
9010
+ }, [recipientWallet, refetch, socket]);
9011
+ const socketRef = useRef18(socket);
9012
+ socketRef.current = socket;
9013
+ useEffect30(() => {
9014
+ const currentSocket = socketRef.current;
9015
+ const prevListeners = currentSocket.listeners;
9016
+ const originalOnDMNew = prevListeners?.onDMNewMessage;
9017
+ currentSocket.setListeners({
9018
+ ...prevListeners,
9019
+ onDMNewMessage: (msg) => {
9020
+ originalOnDMNew?.(msg);
9021
+ if (msg.senderWallet === recipientWallet || msg.isOwn) {
9022
+ setMessages((prev) => {
9023
+ if (prev.some((m) => m.id === msg.id)) return prev;
9024
+ return [...prev, msg];
9025
+ });
9026
+ }
9027
+ },
9028
+ onDMMessageSent: (msg) => {
9029
+ setMessages((prev) => {
9030
+ if (prev.some((m) => m.id === msg.id)) return prev;
9031
+ return [...prev, { ...msg, isOwn: true }];
9032
+ });
9033
+ }
9034
+ });
9035
+ }, [recipientWallet]);
9036
+ const send = useCallback36(
9037
+ (message) => {
9038
+ socket.sendDM({ recipientWallet, message });
9039
+ },
9040
+ [socket, recipientWallet]
9041
+ );
9042
+ const sendViaREST = useCallback36(
9043
+ async (message) => {
9044
+ await client.sendDirectMessage({ recipientWallet, message });
9045
+ await refetch();
9046
+ await refreshConversations();
9047
+ },
9048
+ [client, recipientWallet, refetch, refreshConversations]
9049
+ );
9050
+ const markRead = useCallback36(() => {
9051
+ socket.markDMRead(recipientWallet);
9052
+ }, [socket, recipientWallet]);
9053
+ return { messages, loading, otherUser, send, sendViaREST, markRead, refetch };
9054
+ }
9055
+ function useFriends() {
9056
+ const { friends, refreshFriends } = useChatContext();
9057
+ const [loading, setLoading] = useState42(false);
9058
+ const refetch = useCallback36(async () => {
9059
+ setLoading(true);
9060
+ await refreshFriends();
9061
+ setLoading(false);
9062
+ }, [refreshFriends]);
9063
+ return { friends, loading, refetch };
9064
+ }
9065
+ function useFriendRequests() {
9066
+ const { pendingRequests, refreshPendingRequests } = useChatContext();
9067
+ const [loading, setLoading] = useState42(false);
9068
+ const refetch = useCallback36(async () => {
9069
+ setLoading(true);
9070
+ await refreshPendingRequests();
9071
+ setLoading(false);
9072
+ }, [refreshPendingRequests]);
9073
+ return { requests: pendingRequests, loading, refetch };
9074
+ }
9075
+ function useSearchUsers() {
9076
+ const { client } = useDubs();
9077
+ const [results, setResults] = useState42([]);
9078
+ const [loading, setLoading] = useState42(false);
9079
+ const search = useCallback36(
9080
+ async (query) => {
9081
+ setLoading(true);
9082
+ try {
9083
+ const res = await client.searchUsers(query);
9084
+ setResults(res.results);
9085
+ } catch (err) {
9086
+ console.error("[Dubs:useSearchUsers] Error:", err);
9087
+ } finally {
9088
+ setLoading(false);
9089
+ }
9090
+ },
9091
+ [client]
9092
+ );
9093
+ const clear = useCallback36(() => setResults([]), []);
9094
+ return { results, loading, search, clear };
9095
+ }
9096
+ function useSendFriendRequest() {
9097
+ const { client } = useDubs();
9098
+ const { refreshPendingRequests } = useChatContext();
9099
+ const [loading, setLoading] = useState42(false);
9100
+ const send = useCallback36(
9101
+ async (targetUserId) => {
9102
+ setLoading(true);
9103
+ try {
9104
+ await client.sendFriendRequest(targetUserId);
9105
+ } finally {
9106
+ setLoading(false);
9107
+ }
9108
+ },
9109
+ [client, refreshPendingRequests]
9110
+ );
9111
+ return { send, loading };
9112
+ }
9113
+ function useRespondToFriendRequest() {
9114
+ const { client } = useDubs();
9115
+ const { refreshFriends, refreshPendingRequests } = useChatContext();
9116
+ const [loading, setLoading] = useState42(false);
9117
+ const accept = useCallback36(
9118
+ async (requestId) => {
9119
+ setLoading(true);
9120
+ try {
9121
+ await client.acceptFriendRequest(requestId);
9122
+ await Promise.all([refreshFriends(), refreshPendingRequests()]);
9123
+ } finally {
9124
+ setLoading(false);
9125
+ }
9126
+ },
9127
+ [client, refreshFriends, refreshPendingRequests]
9128
+ );
9129
+ const reject = useCallback36(
9130
+ async (requestId) => {
9131
+ setLoading(true);
9132
+ try {
9133
+ await client.rejectFriendRequest(requestId);
9134
+ await refreshPendingRequests();
9135
+ } finally {
9136
+ setLoading(false);
9137
+ }
9138
+ },
9139
+ [client, refreshPendingRequests]
9140
+ );
9141
+ return { accept, reject, loading };
9142
+ }
7235
9143
  export {
7236
9144
  ArcadeLeaderboardSheet,
7237
9145
  AuthGate,
9146
+ ChatProvider,
9147
+ ChatSocket,
7238
9148
  ClaimButton,
7239
9149
  ClaimPrizeSheet,
7240
9150
  ConnectWalletButton,
@@ -7248,6 +9158,9 @@ export {
7248
9158
  DubsProvider,
7249
9159
  EnterArcadePoolSheet,
7250
9160
  GamePoster,
9161
+ JackpotCard,
9162
+ JackpotSheet,
9163
+ JackpotWidget,
7251
9164
  JoinGameButton,
7252
9165
  JoinGameSheet,
7253
9166
  LivePoolsCard,
@@ -7276,22 +9189,38 @@ export {
7276
9189
  useArcadePool,
7277
9190
  useArcadePools,
7278
9191
  useAuth,
9192
+ useChatContext,
9193
+ useChatMessages,
9194
+ useChatStatus,
7279
9195
  useClaim,
9196
+ useConversations,
7280
9197
  useCreateCustomGame,
7281
9198
  useCreateGame,
9199
+ useDirectMessages,
7282
9200
  useDubs,
7283
9201
  useDubsTheme,
7284
9202
  useEnterArcadePool,
9203
+ useEnterJackpot,
7285
9204
  useEvents,
9205
+ useFriendRequests,
9206
+ useFriends,
7286
9207
  useGame,
7287
9208
  useGames,
7288
9209
  useHasClaimed,
7289
9210
  useHighlights,
9211
+ useJackpot,
9212
+ useJackpotHistory,
7290
9213
  useJoinGame,
7291
9214
  useNetworkGames,
9215
+ useOnlineUsers,
7292
9216
  usePushNotifications,
9217
+ useRespondToFriendRequest,
9218
+ useSearchUsers,
9219
+ useSendFriendRequest,
9220
+ useSendMessage,
7293
9221
  useShorts,
7294
9222
  useUFCFightCard,
7295
- useUFCFighterDetail
9223
+ useUFCFighterDetail,
9224
+ useUnreadCount
7296
9225
  };
7297
9226
  //# sourceMappingURL=index.mjs.map