@dubsdotapp/expo 0.1.3 → 0.2.1

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
@@ -1,6 +1,25 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/constants.ts
2
9
  var DEFAULT_BASE_URL = "https://dubs-server-prod-9c91d3f01199.herokuapp.com/api/developer/v1";
3
10
  var DEFAULT_RPC_URL = "https://api.mainnet-beta.solana.com";
11
+ var NETWORK_CONFIG = {
12
+ "mainnet-beta": {
13
+ baseUrl: DEFAULT_BASE_URL,
14
+ rpcUrl: DEFAULT_RPC_URL,
15
+ cluster: "mainnet-beta"
16
+ },
17
+ devnet: {
18
+ baseUrl: "https://dubs-server-dev-55d1fba09a97.herokuapp.com/api/developer/v1",
19
+ rpcUrl: "https://api.devnet.solana.com",
20
+ cluster: "devnet"
21
+ }
22
+ };
4
23
 
5
24
  // src/errors.ts
6
25
  var DubsApiError = class extends Error {
@@ -134,12 +153,20 @@ var DubsClient = class {
134
153
  if (this._token) {
135
154
  headers["Authorization"] = `Bearer ${this._token}`;
136
155
  }
156
+ console.log(`[DubsClient] ${method} ${url}`, body ? JSON.stringify(body).slice(0, 200) : "");
137
157
  const res = await fetch(url, {
138
158
  method,
139
159
  headers,
140
160
  body: body ? JSON.stringify(body) : void 0
141
161
  });
142
- const json = await res.json();
162
+ const text = await res.text();
163
+ console.log(`[DubsClient] ${method} ${path} \u2192 ${res.status}`, text.slice(0, 300));
164
+ let json;
165
+ try {
166
+ json = JSON.parse(text);
167
+ } catch {
168
+ throw new DubsApiError("parse_error", `Invalid JSON response: ${text.slice(0, 100)}`, res.status);
169
+ }
143
170
  if (!json.success) {
144
171
  const err = json.error;
145
172
  if (typeof err === "object" && err !== null) {
@@ -259,6 +286,13 @@ var DubsClient = class {
259
286
  );
260
287
  return res.game;
261
288
  }
289
+ async getLiveScore(gameId) {
290
+ const res = await this.request(
291
+ "GET",
292
+ `/games/${encodeURIComponent(gameId)}/live-score`
293
+ );
294
+ return res.liveScore;
295
+ }
262
296
  async getGames(params) {
263
297
  const qs = new URLSearchParams();
264
298
  if (params?.wallet) qs.set("wallet", params.wallet);
@@ -276,6 +310,7 @@ var DubsClient = class {
276
310
  async getNetworkGames(params) {
277
311
  const qs = new URLSearchParams();
278
312
  if (params?.league) qs.set("league", params.league);
313
+ if (params?.exclude_wallet) qs.set("exclude_wallet", params.exclude_wallet);
279
314
  if (params?.limit != null) qs.set("limit", String(params.limit));
280
315
  if (params?.offset != null) qs.set("offset", String(params.offset));
281
316
  const query = qs.toString();
@@ -382,29 +417,56 @@ var DubsClient = class {
382
417
  getErrorCodesLocal() {
383
418
  return { ...SOLANA_PROGRAM_ERRORS };
384
419
  }
420
+ // ── App Config ──
421
+ /** Fetch the app's UI customization config (accent color, icon, tagline) */
422
+ async getAppConfig() {
423
+ const res = await this.request("GET", "/apps/config");
424
+ return res.uiConfig || {};
425
+ }
385
426
  };
386
427
 
387
- // src/provider.tsx
388
- import { createContext, useContext, useMemo } from "react";
389
- import { Connection } from "@solana/web3.js";
390
- import { jsx } from "react/jsx-runtime";
391
- var DubsContext = createContext(null);
392
- function DubsProvider({ apiKey, baseUrl, rpcUrl, wallet, children }) {
393
- const value = useMemo(() => {
394
- const client = new DubsClient({ apiKey, baseUrl });
395
- const connection = new Connection(rpcUrl || DEFAULT_RPC_URL, { commitment: "confirmed" });
396
- return { client, wallet, connection };
397
- }, [apiKey, baseUrl, rpcUrl, wallet]);
398
- return /* @__PURE__ */ jsx(DubsContext.Provider, { value, children });
399
- }
400
- function useDubs() {
401
- const ctx = useContext(DubsContext);
402
- if (!ctx) {
403
- throw new Error("useDubs must be used within a <DubsProvider>");
428
+ // src/storage.ts
429
+ var STORAGE_KEYS = {
430
+ MWA_AUTH_TOKEN: "dubs_mwa_auth_token",
431
+ JWT_TOKEN: "dubs_jwt_token"
432
+ };
433
+ function createSecureStoreStorage() {
434
+ let SecureStore = null;
435
+ function getStore() {
436
+ if (!SecureStore) {
437
+ try {
438
+ SecureStore = __require("expo-secure-store");
439
+ } catch {
440
+ throw new Error(
441
+ "@dubsdotapp/expo: expo-secure-store is required for default token storage. Install it with: npx expo install expo-secure-store \u2014 or pass a custom tokenStorage prop to <DubsProvider>."
442
+ );
443
+ }
444
+ }
445
+ return SecureStore;
404
446
  }
405
- return ctx;
447
+ return {
448
+ async getItem(key) {
449
+ const store = getStore();
450
+ return store.getItemAsync(key);
451
+ },
452
+ async setItem(key, value) {
453
+ const store = getStore();
454
+ await store.setItemAsync(key, value);
455
+ },
456
+ async deleteItem(key) {
457
+ const store = getStore();
458
+ await store.deleteItemAsync(key);
459
+ }
460
+ };
406
461
  }
407
462
 
463
+ // src/provider.tsx
464
+ import { createContext as createContext3, useContext as useContext3, useMemo, useCallback as useCallback11, useState as useState11, useEffect as useEffect7 } from "react";
465
+ import { Connection } from "@solana/web3.js";
466
+
467
+ // src/managed-wallet.tsx
468
+ import { createContext, useContext, useState, useEffect, useRef, useCallback } from "react";
469
+
408
470
  // src/wallet/mwa-adapter.ts
409
471
  import { PublicKey } from "@solana/web3.js";
410
472
  function toPublicKey(address) {
@@ -428,6 +490,12 @@ var MwaWalletAdapter = class {
428
490
  get connected() {
429
491
  return this._connected;
430
492
  }
493
+ get authToken() {
494
+ return this._authToken;
495
+ }
496
+ setAuthToken(token) {
497
+ this._authToken = token;
498
+ }
431
499
  /**
432
500
  * Connect to a mobile wallet. Call this before any signing.
433
501
  */
@@ -491,26 +559,328 @@ var MwaWalletAdapter = class {
491
559
  return result[0];
492
560
  });
493
561
  if (signature instanceof Uint8Array) {
494
- const bs582 = await import("@solana/web3.js").then(() => {
495
- return new PublicKey(signature).toBase58();
496
- }).catch(() => {
497
- return Buffer.from(signature).toString("base64");
498
- });
499
- return bs582;
562
+ return new PublicKey(signature).toBase58();
500
563
  }
501
564
  return String(signature);
502
565
  }
503
566
  };
504
567
 
568
+ // src/ui/ConnectWalletScreen.tsx
569
+ import {
570
+ View,
571
+ Text,
572
+ TouchableOpacity,
573
+ ActivityIndicator,
574
+ StyleSheet,
575
+ Image
576
+ } from "react-native";
577
+
578
+ // src/ui/theme.ts
579
+ import { useColorScheme } from "react-native";
580
+ var dark = {
581
+ background: "#08080D",
582
+ surface: "#111118",
583
+ surfaceActive: "#7C3AED",
584
+ border: "#1A1A24",
585
+ text: "#FFFFFF",
586
+ textSecondary: "#E0E0EE",
587
+ textMuted: "#666666",
588
+ textDim: "#555555",
589
+ accent: "#7C3AED",
590
+ success: "#22C55E",
591
+ live: "#EF4444",
592
+ errorText: "#F87171",
593
+ errorBg: "#1A0A0A",
594
+ errorBorder: "#3A1515"
595
+ };
596
+ var light = {
597
+ background: "#FFFFFF",
598
+ surface: "#F0F0F5",
599
+ surfaceActive: "#7C3AED",
600
+ border: "#E0E0E8",
601
+ text: "#111118",
602
+ textSecondary: "#333333",
603
+ textMuted: "#888888",
604
+ textDim: "#999999",
605
+ accent: "#7C3AED",
606
+ success: "#16A34A",
607
+ live: "#DC2626",
608
+ errorText: "#DC2626",
609
+ errorBg: "#FEF2F2",
610
+ errorBorder: "#FECACA"
611
+ };
612
+ function useDubsTheme() {
613
+ const scheme = useColorScheme();
614
+ return scheme === "light" ? light : dark;
615
+ }
616
+ function mergeTheme(base, overrides) {
617
+ return { ...base, ...overrides };
618
+ }
619
+
620
+ // src/ui/ConnectWalletScreen.tsx
621
+ import { jsx, jsxs } from "react/jsx-runtime";
622
+ function ConnectWalletScreen({
623
+ onConnect,
624
+ connecting = false,
625
+ error = null,
626
+ appName = "Dubs",
627
+ accentColor,
628
+ appIcon,
629
+ tagline
630
+ }) {
631
+ const t = useDubsTheme();
632
+ const accent = accentColor || t.accent;
633
+ return /* @__PURE__ */ jsx(View, { style: [styles.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs(View, { style: styles.content, children: [
634
+ /* @__PURE__ */ jsxs(View, { style: styles.brandingSection, children: [
635
+ appIcon ? /* @__PURE__ */ jsx(
636
+ Image,
637
+ {
638
+ source: { uri: appIcon },
639
+ style: styles.logoImage
640
+ }
641
+ ) : /* @__PURE__ */ jsx(View, { style: [styles.logoCircle, { backgroundColor: accent }], children: /* @__PURE__ */ jsx(Text, { style: styles.logoText, children: appName.charAt(0).toUpperCase() }) }),
642
+ /* @__PURE__ */ jsx(Text, { style: [styles.appName, { color: t.text }], children: appName }),
643
+ /* @__PURE__ */ jsx(Text, { style: [styles.subtitle, { color: t.textMuted }], children: tagline || "Connect your Solana wallet to get started" })
644
+ ] }),
645
+ /* @__PURE__ */ jsxs(View, { style: styles.actionSection, children: [
646
+ error ? /* @__PURE__ */ jsx(
647
+ View,
648
+ {
649
+ style: [
650
+ styles.errorBox,
651
+ { backgroundColor: t.errorBg, borderColor: t.errorBorder }
652
+ ],
653
+ children: /* @__PURE__ */ jsx(Text, { style: [styles.errorText, { color: t.errorText }], children: error })
654
+ }
655
+ ) : null,
656
+ /* @__PURE__ */ jsx(
657
+ TouchableOpacity,
658
+ {
659
+ style: [styles.connectButton, { backgroundColor: accent }],
660
+ onPress: onConnect,
661
+ disabled: connecting,
662
+ activeOpacity: 0.8,
663
+ children: connecting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: "#FFFFFF", size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.connectButtonText, children: "Connect Wallet" })
664
+ }
665
+ ),
666
+ /* @__PURE__ */ jsx(Text, { style: [styles.hint, { color: t.textDim }], children: "Phantom, Solflare, or any Solana wallet" })
667
+ ] })
668
+ ] }) });
669
+ }
670
+ var styles = StyleSheet.create({
671
+ container: {
672
+ flex: 1,
673
+ justifyContent: "center"
674
+ },
675
+ content: {
676
+ flex: 1,
677
+ justifyContent: "space-between",
678
+ paddingHorizontal: 32,
679
+ paddingTop: 120,
680
+ paddingBottom: 80
681
+ },
682
+ brandingSection: {
683
+ alignItems: "center",
684
+ gap: 12
685
+ },
686
+ logoCircle: {
687
+ width: 80,
688
+ height: 80,
689
+ borderRadius: 40,
690
+ justifyContent: "center",
691
+ alignItems: "center",
692
+ marginBottom: 8
693
+ },
694
+ logoImage: {
695
+ width: 80,
696
+ height: 80,
697
+ borderRadius: 16,
698
+ marginBottom: 8
699
+ },
700
+ logoText: {
701
+ fontSize: 36,
702
+ fontWeight: "800",
703
+ color: "#FFFFFF"
704
+ },
705
+ appName: {
706
+ fontSize: 32,
707
+ fontWeight: "800"
708
+ },
709
+ subtitle: {
710
+ fontSize: 16,
711
+ textAlign: "center",
712
+ lineHeight: 22
713
+ },
714
+ actionSection: {
715
+ gap: 16
716
+ },
717
+ errorBox: {
718
+ borderWidth: 1,
719
+ borderRadius: 12,
720
+ paddingHorizontal: 16,
721
+ paddingVertical: 12
722
+ },
723
+ errorText: {
724
+ fontSize: 14,
725
+ textAlign: "center"
726
+ },
727
+ connectButton: {
728
+ height: 56,
729
+ borderRadius: 16,
730
+ justifyContent: "center",
731
+ alignItems: "center"
732
+ },
733
+ connectButtonText: {
734
+ color: "#FFFFFF",
735
+ fontSize: 18,
736
+ fontWeight: "700"
737
+ },
738
+ hint: {
739
+ fontSize: 13,
740
+ textAlign: "center"
741
+ }
742
+ });
743
+
744
+ // src/managed-wallet.tsx
745
+ import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
746
+ var DisconnectContext = createContext(null);
747
+ function useDisconnect() {
748
+ return useContext(DisconnectContext);
749
+ }
750
+ function ManagedWalletProvider({
751
+ appName,
752
+ cluster,
753
+ storage,
754
+ renderConnectScreen,
755
+ accentColor,
756
+ appIcon,
757
+ tagline,
758
+ children
759
+ }) {
760
+ const [connected, setConnected] = useState(false);
761
+ const [connecting, setConnecting] = useState(false);
762
+ const [isReady, setIsReady] = useState(false);
763
+ const [error, setError] = useState(null);
764
+ const adapterRef = useRef(null);
765
+ const transactRef = useRef(null);
766
+ if (!adapterRef.current) {
767
+ adapterRef.current = new MwaWalletAdapter({
768
+ transact: (...args) => {
769
+ if (!transactRef.current) {
770
+ throw new Error(
771
+ "@dubsdotapp/expo: @solana-mobile/mobile-wallet-adapter-protocol-web3js is required. Install it with: npm install @solana-mobile/mobile-wallet-adapter-protocol-web3js"
772
+ );
773
+ }
774
+ return transactRef.current(...args);
775
+ },
776
+ appIdentity: { name: appName },
777
+ cluster,
778
+ onAuthTokenChange: (token) => {
779
+ if (token) {
780
+ storage.setItem(STORAGE_KEYS.MWA_AUTH_TOKEN, token).catch(() => {
781
+ });
782
+ } else {
783
+ storage.deleteItem(STORAGE_KEYS.MWA_AUTH_TOKEN).catch(() => {
784
+ });
785
+ }
786
+ }
787
+ });
788
+ }
789
+ const adapter = adapterRef.current;
790
+ useEffect(() => {
791
+ let cancelled = false;
792
+ (async () => {
793
+ try {
794
+ const mwa = await import("@solana-mobile/mobile-wallet-adapter-protocol-web3js");
795
+ if (cancelled) return;
796
+ transactRef.current = mwa.transact;
797
+ } catch {
798
+ }
799
+ try {
800
+ const savedToken = await storage.getItem(STORAGE_KEYS.MWA_AUTH_TOKEN);
801
+ if (savedToken && !cancelled) {
802
+ adapter.setAuthToken(savedToken);
803
+ await adapter.connect();
804
+ if (!cancelled) setConnected(true);
805
+ }
806
+ } catch {
807
+ } finally {
808
+ if (!cancelled) setIsReady(true);
809
+ }
810
+ })();
811
+ return () => {
812
+ cancelled = true;
813
+ };
814
+ }, [adapter, storage]);
815
+ const handleConnect = useCallback(async () => {
816
+ setConnecting(true);
817
+ setError(null);
818
+ try {
819
+ await adapter.connect();
820
+ setConnected(true);
821
+ } catch (err) {
822
+ const message = err instanceof Error ? err.message : "Connection failed";
823
+ setError(message);
824
+ } finally {
825
+ setConnecting(false);
826
+ }
827
+ }, [adapter]);
828
+ const disconnect = useCallback(async () => {
829
+ adapter.disconnect();
830
+ await storage.deleteItem(STORAGE_KEYS.MWA_AUTH_TOKEN).catch(() => {
831
+ });
832
+ await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
833
+ });
834
+ setConnected(false);
835
+ }, [adapter, storage]);
836
+ if (!isReady) return null;
837
+ if (!connected) {
838
+ if (renderConnectScreen === false) {
839
+ return null;
840
+ }
841
+ const connectProps = {
842
+ onConnect: handleConnect,
843
+ connecting,
844
+ error,
845
+ appName,
846
+ accentColor,
847
+ appIcon,
848
+ tagline
849
+ };
850
+ if (renderConnectScreen) {
851
+ return /* @__PURE__ */ jsx2(Fragment, { children: renderConnectScreen(connectProps) });
852
+ }
853
+ return /* @__PURE__ */ jsx2(ConnectWalletScreen, { ...connectProps });
854
+ }
855
+ return /* @__PURE__ */ jsx2(DisconnectContext.Provider, { value: disconnect, children: children(adapter) });
856
+ }
857
+
858
+ // src/ui/AuthGate.tsx
859
+ import React2, { useState as useState10, useEffect as useEffect6, useRef as useRef3, useCallback as useCallback10 } from "react";
860
+ import {
861
+ View as View2,
862
+ Text as Text2,
863
+ TextInput,
864
+ TouchableOpacity as TouchableOpacity2,
865
+ ActivityIndicator as ActivityIndicator2,
866
+ StyleSheet as StyleSheet2,
867
+ Keyboard,
868
+ KeyboardAvoidingView,
869
+ Platform,
870
+ Image as Image2,
871
+ Animated,
872
+ ScrollView
873
+ } from "react-native";
874
+
505
875
  // src/hooks/useEvents.ts
506
- import { useState, useEffect, useCallback } from "react";
876
+ import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
507
877
  function useEvents(params) {
508
878
  const { client } = useDubs();
509
- const [data, setData] = useState(null);
510
- const [loading, setLoading] = useState(true);
511
- const [error, setError] = useState(null);
879
+ const [data, setData] = useState2(null);
880
+ const [loading, setLoading] = useState2(true);
881
+ const [error, setError] = useState2(null);
512
882
  const paramKey = JSON.stringify(params ?? {});
513
- const fetchData = useCallback(async () => {
883
+ const fetchData = useCallback2(async () => {
514
884
  setLoading(true);
515
885
  setError(null);
516
886
  try {
@@ -522,20 +892,20 @@ function useEvents(params) {
522
892
  setLoading(false);
523
893
  }
524
894
  }, [client, paramKey]);
525
- useEffect(() => {
895
+ useEffect2(() => {
526
896
  fetchData();
527
897
  }, [fetchData]);
528
898
  return { data, loading, error, refetch: fetchData };
529
899
  }
530
900
 
531
901
  // src/hooks/useGame.ts
532
- import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
902
+ import { useState as useState3, useEffect as useEffect3, useCallback as useCallback3 } from "react";
533
903
  function useGame(gameId) {
534
904
  const { client } = useDubs();
535
- const [data, setData] = useState2(null);
536
- const [loading, setLoading] = useState2(!!gameId);
537
- const [error, setError] = useState2(null);
538
- const fetchData = useCallback2(async () => {
905
+ const [data, setData] = useState3(null);
906
+ const [loading, setLoading] = useState3(!!gameId);
907
+ const [error, setError] = useState3(null);
908
+ const fetchData = useCallback3(async () => {
539
909
  if (!gameId) return;
540
910
  setLoading(true);
541
911
  setError(null);
@@ -548,21 +918,21 @@ function useGame(gameId) {
548
918
  setLoading(false);
549
919
  }
550
920
  }, [client, gameId]);
551
- useEffect2(() => {
921
+ useEffect3(() => {
552
922
  fetchData();
553
923
  }, [fetchData]);
554
924
  return { data, loading, error, refetch: fetchData };
555
925
  }
556
926
 
557
927
  // src/hooks/useGames.ts
558
- import { useState as useState3, useEffect as useEffect3, useCallback as useCallback3 } from "react";
928
+ import { useState as useState4, useEffect as useEffect4, useCallback as useCallback4 } from "react";
559
929
  function useGames(params) {
560
930
  const { client } = useDubs();
561
- const [data, setData] = useState3(null);
562
- const [loading, setLoading] = useState3(true);
563
- const [error, setError] = useState3(null);
931
+ const [data, setData] = useState4(null);
932
+ const [loading, setLoading] = useState4(true);
933
+ const [error, setError] = useState4(null);
564
934
  const paramKey = JSON.stringify(params ?? {});
565
- const fetchData = useCallback3(async () => {
935
+ const fetchData = useCallback4(async () => {
566
936
  setLoading(true);
567
937
  setError(null);
568
938
  try {
@@ -574,21 +944,21 @@ function useGames(params) {
574
944
  setLoading(false);
575
945
  }
576
946
  }, [client, paramKey]);
577
- useEffect3(() => {
947
+ useEffect4(() => {
578
948
  fetchData();
579
949
  }, [fetchData]);
580
950
  return { data, loading, error, refetch: fetchData };
581
951
  }
582
952
 
583
953
  // src/hooks/useNetworkGames.ts
584
- import { useState as useState4, useEffect as useEffect4, useCallback as useCallback4 } from "react";
954
+ import { useState as useState5, useEffect as useEffect5, useCallback as useCallback5 } from "react";
585
955
  function useNetworkGames(params) {
586
956
  const { client } = useDubs();
587
- const [data, setData] = useState4(null);
588
- const [loading, setLoading] = useState4(true);
589
- const [error, setError] = useState4(null);
957
+ const [data, setData] = useState5(null);
958
+ const [loading, setLoading] = useState5(true);
959
+ const [error, setError] = useState5(null);
590
960
  const paramKey = JSON.stringify(params ?? {});
591
- const fetchData = useCallback4(async () => {
961
+ const fetchData = useCallback5(async () => {
592
962
  setLoading(true);
593
963
  setError(null);
594
964
  try {
@@ -600,78 +970,59 @@ function useNetworkGames(params) {
600
970
  setLoading(false);
601
971
  }
602
972
  }, [client, paramKey]);
603
- useEffect4(() => {
973
+ useEffect5(() => {
604
974
  fetchData();
605
975
  }, [fetchData]);
606
976
  return { data, loading, error, refetch: fetchData };
607
977
  }
608
978
 
609
979
  // src/hooks/useCreateGame.ts
610
- import { useState as useState5, useCallback as useCallback5 } from "react";
980
+ import { useState as useState6, useCallback as useCallback6 } from "react";
611
981
 
612
982
  // src/utils/transaction.ts
613
983
  import { Transaction as Transaction2 } from "@solana/web3.js";
614
- async function signAndSendBase64Transaction(base64Tx, wallet, connection) {
984
+ async function signAndSendBase64Transaction(base64Tx, wallet) {
615
985
  if (!wallet.publicKey) throw new Error("Wallet not connected");
616
- const txBuffer = Buffer.from(base64Tx, "base64");
617
- const transaction = Transaction2.from(txBuffer);
986
+ const binaryStr = atob(base64Tx);
987
+ const bytes = new Uint8Array(binaryStr.length);
988
+ for (let i = 0; i < binaryStr.length; i++) {
989
+ bytes[i] = binaryStr.charCodeAt(i);
990
+ }
991
+ const transaction = Transaction2.from(bytes);
618
992
  if (wallet.signAndSendTransaction) {
619
993
  return wallet.signAndSendTransaction(transaction);
620
994
  }
621
- const signed = await wallet.signTransaction(transaction);
622
- const signature = await connection.sendRawTransaction(signed.serialize(), {
623
- skipPreflight: true
624
- });
625
- return signature;
626
- }
627
- async function pollTransactionConfirmation(signature, connection, commitment = "confirmed", timeout = 6e4, interval = 1500) {
628
- const start = Date.now();
629
- const confirmationOrder = ["processed", "confirmed", "finalized"];
630
- const targetIndex = confirmationOrder.indexOf(commitment);
631
- while (Date.now() - start < timeout) {
632
- const statuses = await connection.getSignatureStatuses([signature]);
633
- const status = statuses?.value?.[0];
634
- if (status?.err) {
635
- throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`);
636
- }
637
- if (status?.confirmationStatus) {
638
- const currentIndex = confirmationOrder.indexOf(status.confirmationStatus);
639
- if (currentIndex >= targetIndex) {
640
- return;
641
- }
642
- }
643
- await new Promise((resolve) => setTimeout(resolve, interval));
644
- }
645
- throw new Error(`Transaction confirmation timeout after ${timeout}ms`);
995
+ throw new Error("Wallet does not support signAndSendTransaction");
646
996
  }
647
997
 
648
998
  // src/hooks/useCreateGame.ts
649
999
  function useCreateGame() {
650
- const { client, wallet, connection } = useDubs();
651
- const [status, setStatus] = useState5("idle");
652
- const [error, setError] = useState5(null);
653
- const [data, setData] = useState5(null);
654
- const reset = useCallback5(() => {
1000
+ const { client, wallet } = useDubs();
1001
+ const [status, setStatus] = useState6("idle");
1002
+ const [error, setError] = useState6(null);
1003
+ const [data, setData] = useState6(null);
1004
+ const reset = useCallback6(() => {
655
1005
  setStatus("idle");
656
1006
  setError(null);
657
1007
  setData(null);
658
1008
  }, []);
659
- const execute = useCallback5(async (params) => {
1009
+ const execute = useCallback6(async (params) => {
660
1010
  setStatus("building");
661
1011
  setError(null);
662
1012
  setData(null);
663
1013
  try {
1014
+ console.log("[useCreateGame] Step 1: Building transaction...");
664
1015
  const createResult = await client.createGame(params);
1016
+ console.log("[useCreateGame] Step 1 done:", { gameId: createResult.gameId, gameAddress: createResult.gameAddress });
665
1017
  setStatus("signing");
1018
+ console.log("[useCreateGame] Step 2: Signing and sending...");
666
1019
  const signature = await signAndSendBase64Transaction(
667
1020
  createResult.transaction,
668
- wallet,
669
- connection
1021
+ wallet
670
1022
  );
1023
+ console.log("[useCreateGame] Step 2 done. Signature:", signature);
671
1024
  setStatus("confirming");
672
- await pollTransactionConfirmation(signature, connection);
673
- setStatus("saving");
674
- const explorerUrl = `https://solscan.io/tx/${signature}`;
1025
+ console.log("[useCreateGame] Step 3: Confirming with backend...");
675
1026
  await client.confirmGame({
676
1027
  gameId: createResult.gameId,
677
1028
  playerWallet: params.playerWallet,
@@ -681,6 +1032,8 @@ function useCreateGame() {
681
1032
  role: "creator",
682
1033
  gameAddress: createResult.gameAddress
683
1034
  });
1035
+ console.log("[useCreateGame] Step 3 done.");
1036
+ const explorerUrl = `https://solscan.io/tx/${signature}`;
684
1037
  const result = {
685
1038
  gameId: createResult.gameId,
686
1039
  gameAddress: createResult.gameAddress,
@@ -689,46 +1042,48 @@ function useCreateGame() {
689
1042
  };
690
1043
  setData(result);
691
1044
  setStatus("success");
1045
+ console.log("[useCreateGame] Complete!");
692
1046
  return result;
693
1047
  } catch (err) {
1048
+ console.error("[useCreateGame] FAILED:", err);
694
1049
  const error2 = err instanceof Error ? err : new Error(String(err));
695
1050
  setError(error2);
696
1051
  setStatus("error");
697
1052
  throw error2;
698
1053
  }
699
- }, [client, wallet, connection]);
1054
+ }, [client, wallet]);
700
1055
  return { execute, status, error, data, reset };
701
1056
  }
702
1057
 
703
1058
  // src/hooks/useJoinGame.ts
704
- import { useState as useState6, useCallback as useCallback6 } from "react";
1059
+ import { useState as useState7, useCallback as useCallback7 } from "react";
705
1060
  function useJoinGame() {
706
- const { client, wallet, connection } = useDubs();
707
- const [status, setStatus] = useState6("idle");
708
- const [error, setError] = useState6(null);
709
- const [data, setData] = useState6(null);
710
- const reset = useCallback6(() => {
1061
+ const { client, wallet } = useDubs();
1062
+ const [status, setStatus] = useState7("idle");
1063
+ const [error, setError] = useState7(null);
1064
+ const [data, setData] = useState7(null);
1065
+ const reset = useCallback7(() => {
711
1066
  setStatus("idle");
712
1067
  setError(null);
713
1068
  setData(null);
714
1069
  }, []);
715
- const execute = useCallback6(async (params) => {
1070
+ const execute = useCallback7(async (params) => {
716
1071
  setStatus("building");
717
1072
  setError(null);
718
1073
  setData(null);
719
1074
  try {
1075
+ console.log("[useJoinGame] Step 1: Building transaction...", { gameId: params.gameId, playerWallet: params.playerWallet, teamChoice: params.teamChoice, amount: params.amount });
720
1076
  const joinResult = await client.joinGame(params);
1077
+ console.log("[useJoinGame] Step 1 done:", { gameId: joinResult.gameId, gameAddress: joinResult.gameAddress, hasTx: !!joinResult.transaction });
721
1078
  setStatus("signing");
1079
+ console.log("[useJoinGame] Step 2: Signing and sending transaction...");
722
1080
  const signature = await signAndSendBase64Transaction(
723
1081
  joinResult.transaction,
724
- wallet,
725
- connection
1082
+ wallet
726
1083
  );
1084
+ console.log("[useJoinGame] Step 2 done. Signature:", signature);
727
1085
  setStatus("confirming");
728
- await pollTransactionConfirmation(signature, connection);
729
- setStatus("saving");
730
- const explorerUrl = `https://solscan.io/tx/${signature}`;
731
- await client.confirmGame({
1086
+ const confirmParams = {
732
1087
  gameId: params.gameId,
733
1088
  playerWallet: params.playerWallet,
734
1089
  signature,
@@ -736,7 +1091,11 @@ function useJoinGame() {
736
1091
  wagerAmount: params.amount,
737
1092
  role: "joiner",
738
1093
  gameAddress: joinResult.gameAddress
739
- });
1094
+ };
1095
+ console.log("[useJoinGame] Step 3: Confirming with backend...", confirmParams);
1096
+ await client.confirmGame(confirmParams);
1097
+ console.log("[useJoinGame] Step 3 done. Backend confirmed.");
1098
+ const explorerUrl = `https://solscan.io/tx/${signature}`;
740
1099
  const result = {
741
1100
  gameId: params.gameId,
742
1101
  gameAddress: joinResult.gameAddress,
@@ -745,43 +1104,46 @@ function useJoinGame() {
745
1104
  };
746
1105
  setData(result);
747
1106
  setStatus("success");
1107
+ console.log("[useJoinGame] Complete!");
748
1108
  return result;
749
1109
  } catch (err) {
1110
+ console.error("[useJoinGame] FAILED at status:", status, err);
750
1111
  const error2 = err instanceof Error ? err : new Error(String(err));
751
1112
  setError(error2);
752
1113
  setStatus("error");
753
1114
  throw error2;
754
1115
  }
755
- }, [client, wallet, connection]);
1116
+ }, [client, wallet]);
756
1117
  return { execute, status, error, data, reset };
757
1118
  }
758
1119
 
759
1120
  // src/hooks/useClaim.ts
760
- import { useState as useState7, useCallback as useCallback7 } from "react";
1121
+ import { useState as useState8, useCallback as useCallback8 } from "react";
761
1122
  function useClaim() {
762
- const { client, wallet, connection } = useDubs();
763
- const [status, setStatus] = useState7("idle");
764
- const [error, setError] = useState7(null);
765
- const [data, setData] = useState7(null);
766
- const reset = useCallback7(() => {
1123
+ const { client, wallet } = useDubs();
1124
+ const [status, setStatus] = useState8("idle");
1125
+ const [error, setError] = useState8(null);
1126
+ const [data, setData] = useState8(null);
1127
+ const reset = useCallback8(() => {
767
1128
  setStatus("idle");
768
1129
  setError(null);
769
1130
  setData(null);
770
1131
  }, []);
771
- const execute = useCallback7(async (params) => {
1132
+ const execute = useCallback8(async (params) => {
772
1133
  setStatus("building");
773
1134
  setError(null);
774
1135
  setData(null);
775
1136
  try {
1137
+ console.log("[useClaim] Step 1: Building claim transaction...");
776
1138
  const claimResult = await client.buildClaimTransaction(params);
1139
+ console.log("[useClaim] Step 1 done.");
777
1140
  setStatus("signing");
1141
+ console.log("[useClaim] Step 2: Signing and sending...");
778
1142
  const signature = await signAndSendBase64Transaction(
779
1143
  claimResult.transaction,
780
- wallet,
781
- connection
1144
+ wallet
782
1145
  );
783
- setStatus("confirming");
784
- await pollTransactionConfirmation(signature, connection);
1146
+ console.log("[useClaim] Step 2 done. Signature:", signature);
785
1147
  const explorerUrl = `https://solscan.io/tx/${signature}`;
786
1148
  const result = {
787
1149
  gameId: params.gameId,
@@ -790,28 +1152,37 @@ function useClaim() {
790
1152
  };
791
1153
  setData(result);
792
1154
  setStatus("success");
1155
+ console.log("[useClaim] Complete!");
793
1156
  return result;
794
1157
  } catch (err) {
1158
+ console.error("[useClaim] FAILED:", err);
795
1159
  const error2 = err instanceof Error ? err : new Error(String(err));
796
1160
  setError(error2);
797
1161
  setStatus("error");
798
1162
  throw error2;
799
1163
  }
800
- }, [client, wallet, connection]);
1164
+ }, [client, wallet]);
801
1165
  return { execute, status, error, data, reset };
802
1166
  }
803
1167
 
804
1168
  // src/hooks/useAuth.ts
805
- import { useState as useState8, useCallback as useCallback8, useRef } from "react";
1169
+ import { useState as useState9, useCallback as useCallback9, useRef as useRef2, useContext as useContext2 } from "react";
806
1170
  import bs58 from "bs58";
1171
+
1172
+ // src/auth-context.ts
1173
+ import { createContext as createContext2 } from "react";
1174
+ var AuthContext = createContext2(null);
1175
+
1176
+ // src/hooks/useAuth.ts
807
1177
  function useAuth() {
1178
+ const sharedAuth = useContext2(AuthContext);
808
1179
  const { client, wallet } = useDubs();
809
- const [status, setStatus] = useState8("idle");
810
- const [user, setUser] = useState8(null);
811
- const [token, setToken] = useState8(null);
812
- const [error, setError] = useState8(null);
813
- const pendingAuth = useRef(null);
814
- const reset = useCallback8(() => {
1180
+ const [status, setStatus] = useState9("idle");
1181
+ const [user, setUser] = useState9(null);
1182
+ const [token, setToken] = useState9(null);
1183
+ const [error, setError] = useState9(null);
1184
+ const pendingAuth = useRef2(null);
1185
+ const reset = useCallback9(() => {
815
1186
  setStatus("idle");
816
1187
  setUser(null);
817
1188
  setToken(null);
@@ -819,7 +1190,7 @@ function useAuth() {
819
1190
  pendingAuth.current = null;
820
1191
  client.setToken(null);
821
1192
  }, [client]);
822
- const authenticate = useCallback8(async () => {
1193
+ const authenticate = useCallback9(async () => {
823
1194
  try {
824
1195
  if (!wallet.publicKey) {
825
1196
  throw new Error("Wallet not connected");
@@ -850,7 +1221,7 @@ function useAuth() {
850
1221
  setStatus("error");
851
1222
  }
852
1223
  }, [client, wallet]);
853
- const register = useCallback8(async (username, referralCode, avatarUrl) => {
1224
+ const register = useCallback9(async (username, referralCode, avatarUrl) => {
854
1225
  try {
855
1226
  const pending = pendingAuth.current;
856
1227
  if (!pending) {
@@ -867,7 +1238,8 @@ function useAuth() {
867
1238
  avatarUrl
868
1239
  });
869
1240
  pendingAuth.current = null;
870
- setUser(result.user);
1241
+ const user2 = avatarUrl && !result.user.avatar ? { ...result.user, avatar: avatarUrl } : result.user;
1242
+ setUser(user2);
871
1243
  setToken(result.token);
872
1244
  setStatus("authenticated");
873
1245
  } catch (err) {
@@ -875,7 +1247,7 @@ function useAuth() {
875
1247
  setStatus("error");
876
1248
  }
877
1249
  }, [client]);
878
- const logout = useCallback8(async () => {
1250
+ const logout = useCallback9(async () => {
879
1251
  try {
880
1252
  await client.logout();
881
1253
  } catch {
@@ -886,7 +1258,7 @@ function useAuth() {
886
1258
  setError(null);
887
1259
  pendingAuth.current = null;
888
1260
  }, [client]);
889
- const restoreSession = useCallback8(async (savedToken) => {
1261
+ const restoreSession = useCallback9(async (savedToken) => {
890
1262
  try {
891
1263
  client.setToken(savedToken);
892
1264
  const me = await client.getMe();
@@ -902,6 +1274,7 @@ function useAuth() {
902
1274
  return false;
903
1275
  }
904
1276
  }, [client]);
1277
+ if (sharedAuth) return sharedAuth;
905
1278
  return {
906
1279
  status,
907
1280
  user,
@@ -917,63 +1290,7 @@ function useAuth() {
917
1290
  }
918
1291
 
919
1292
  // src/ui/AuthGate.tsx
920
- import React2, { useState as useState9, useEffect as useEffect5, useRef as useRef2, useCallback as useCallback9 } from "react";
921
- import {
922
- View,
923
- Text,
924
- TextInput,
925
- TouchableOpacity,
926
- ActivityIndicator,
927
- StyleSheet,
928
- Keyboard,
929
- KeyboardAvoidingView,
930
- Platform,
931
- Image,
932
- Animated,
933
- ScrollView
934
- } from "react-native";
935
-
936
- // src/ui/theme.ts
937
- import { useColorScheme } from "react-native";
938
- var dark = {
939
- background: "#08080D",
940
- surface: "#111118",
941
- surfaceActive: "#7C3AED",
942
- border: "#1A1A24",
943
- text: "#FFFFFF",
944
- textSecondary: "#E0E0EE",
945
- textMuted: "#666666",
946
- textDim: "#555555",
947
- accent: "#7C3AED",
948
- success: "#22C55E",
949
- live: "#EF4444",
950
- errorText: "#F87171",
951
- errorBg: "#1A0A0A",
952
- errorBorder: "#3A1515"
953
- };
954
- var light = {
955
- background: "#FFFFFF",
956
- surface: "#F0F0F5",
957
- surfaceActive: "#7C3AED",
958
- border: "#E0E0E8",
959
- text: "#111118",
960
- textSecondary: "#333333",
961
- textMuted: "#888888",
962
- textDim: "#999999",
963
- accent: "#7C3AED",
964
- success: "#16A34A",
965
- live: "#DC2626",
966
- errorText: "#DC2626",
967
- errorBg: "#FEF2F2",
968
- errorBorder: "#FECACA"
969
- };
970
- function useDubsTheme() {
971
- const scheme = useColorScheme();
972
- return scheme === "light" ? light : dark;
973
- }
974
-
975
- // src/ui/AuthGate.tsx
976
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
1293
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
977
1294
  var DICEBEAR_STYLES = [
978
1295
  "adventurer",
979
1296
  "avataaars",
@@ -995,13 +1312,14 @@ function AuthGate({
995
1312
  renderLoading,
996
1313
  renderError,
997
1314
  renderRegistration,
998
- appName = "Dubs"
1315
+ appName = "Dubs",
1316
+ accentColor
999
1317
  }) {
1000
1318
  const { client } = useDubs();
1001
1319
  const auth = useAuth();
1002
- const [phase, setPhase] = useState9("init");
1003
- const [registrationPhase, setRegistrationPhase] = useState9(false);
1004
- useEffect5(() => {
1320
+ const [phase, setPhase] = useState10("init");
1321
+ const [registrationPhase, setRegistrationPhase] = useState10(false);
1322
+ useEffect6(() => {
1005
1323
  let cancelled = false;
1006
1324
  (async () => {
1007
1325
  try {
@@ -1027,51 +1345,54 @@ function AuthGate({
1027
1345
  cancelled = true;
1028
1346
  };
1029
1347
  }, []);
1030
- useEffect5(() => {
1348
+ useEffect6(() => {
1031
1349
  if (auth.status === "needsRegistration") setRegistrationPhase(true);
1032
1350
  }, [auth.status]);
1033
- useEffect5(() => {
1351
+ useEffect6(() => {
1034
1352
  if (auth.token) onSaveToken(auth.token);
1035
1353
  }, [auth.token]);
1036
- const retry = useCallback9(() => {
1354
+ const retry = useCallback10(() => {
1037
1355
  setRegistrationPhase(false);
1038
1356
  auth.reset();
1039
1357
  auth.authenticate();
1040
1358
  }, [auth]);
1041
- const handleRegister = useCallback9(
1359
+ const handleRegister = useCallback10(
1042
1360
  (username, referralCode, avatarUrl) => {
1043
1361
  auth.register(username, referralCode, avatarUrl);
1044
1362
  },
1045
1363
  [auth]
1046
1364
  );
1047
1365
  if (phase === "init") {
1048
- if (renderLoading) return /* @__PURE__ */ jsx2(Fragment, { children: renderLoading("authenticating") });
1049
- return /* @__PURE__ */ jsx2(DefaultLoadingScreen, { status: "authenticating", appName });
1366
+ if (renderLoading) return /* @__PURE__ */ jsx3(Fragment2, { children: renderLoading("authenticating") });
1367
+ return /* @__PURE__ */ jsx3(DefaultLoadingScreen, { status: "authenticating", appName });
1368
+ }
1369
+ if (auth.status === "authenticated") {
1370
+ return /* @__PURE__ */ jsx3(AuthContext.Provider, { value: auth, children });
1050
1371
  }
1051
- if (auth.status === "authenticated") return /* @__PURE__ */ jsx2(Fragment, { children });
1052
1372
  if (registrationPhase) {
1053
1373
  const isRegistering = auth.status === "registering";
1054
1374
  const regError = auth.status === "error" ? auth.error : null;
1055
1375
  if (renderRegistration) {
1056
- return /* @__PURE__ */ jsx2(Fragment, { children: renderRegistration({ onRegister: handleRegister, registering: isRegistering, error: regError, client }) });
1376
+ return /* @__PURE__ */ jsx3(Fragment2, { children: renderRegistration({ onRegister: handleRegister, registering: isRegistering, error: regError, client }) });
1057
1377
  }
1058
- return /* @__PURE__ */ jsx2(
1378
+ return /* @__PURE__ */ jsx3(
1059
1379
  DefaultRegistrationScreen,
1060
1380
  {
1061
1381
  onRegister: handleRegister,
1062
1382
  registering: isRegistering,
1063
1383
  error: regError,
1064
1384
  client,
1065
- appName
1385
+ appName,
1386
+ accentColor
1066
1387
  }
1067
1388
  );
1068
1389
  }
1069
1390
  if (auth.status === "error" && auth.error) {
1070
- if (renderError) return /* @__PURE__ */ jsx2(Fragment, { children: renderError(auth.error, retry) });
1071
- return /* @__PURE__ */ jsx2(DefaultErrorScreen, { error: auth.error, onRetry: retry, appName });
1391
+ if (renderError) return /* @__PURE__ */ jsx3(Fragment2, { children: renderError(auth.error, retry) });
1392
+ return /* @__PURE__ */ jsx3(DefaultErrorScreen, { error: auth.error, onRetry: retry, appName });
1072
1393
  }
1073
- if (renderLoading) return /* @__PURE__ */ jsx2(Fragment, { children: renderLoading(auth.status) });
1074
- return /* @__PURE__ */ jsx2(DefaultLoadingScreen, { status: auth.status, appName });
1394
+ if (renderLoading) return /* @__PURE__ */ jsx3(Fragment2, { children: renderLoading(auth.status) });
1395
+ return /* @__PURE__ */ jsx3(DefaultLoadingScreen, { status: auth.status, appName });
1075
1396
  }
1076
1397
  function DefaultLoadingScreen({ status, appName }) {
1077
1398
  const t = useDubsTheme();
@@ -1085,43 +1406,43 @@ function DefaultLoadingScreen({ status, appName }) {
1085
1406
  authenticated: "Ready!",
1086
1407
  error: "Something went wrong"
1087
1408
  };
1088
- return /* @__PURE__ */ jsx2(View, { style: [s.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs(View, { style: s.centerContent, children: [
1089
- /* @__PURE__ */ jsxs(View, { style: s.brandingSection, children: [
1090
- /* @__PURE__ */ jsx2(View, { style: [s.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ jsx2(Text, { style: s.logoText, children: "D" }) }),
1091
- /* @__PURE__ */ jsx2(Text, { style: [s.appNameText, { color: t.text }], children: appName })
1409
+ return /* @__PURE__ */ jsx3(View2, { style: [s.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs2(View2, { style: s.centerContent, children: [
1410
+ /* @__PURE__ */ jsxs2(View2, { style: s.brandingSection, children: [
1411
+ /* @__PURE__ */ jsx3(View2, { style: [s.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ jsx3(Text2, { style: s.logoText, children: "D" }) }),
1412
+ /* @__PURE__ */ jsx3(Text2, { style: [s.appNameText, { color: t.text }], children: appName })
1092
1413
  ] }),
1093
- /* @__PURE__ */ jsxs(View, { style: s.loadingSection, children: [
1094
- /* @__PURE__ */ jsx2(ActivityIndicator, { size: "large", color: t.accent }),
1095
- /* @__PURE__ */ jsx2(Text, { style: [s.statusText, { color: t.textMuted }], children: statusText[status] || "Loading..." })
1414
+ /* @__PURE__ */ jsxs2(View2, { style: s.loadingSection, children: [
1415
+ /* @__PURE__ */ jsx3(ActivityIndicator2, { size: "large", color: t.accent }),
1416
+ /* @__PURE__ */ jsx3(Text2, { style: [s.statusText, { color: t.textMuted }], children: statusText[status] || "Loading..." })
1096
1417
  ] })
1097
1418
  ] }) });
1098
1419
  }
1099
1420
  function DefaultErrorScreen({ error, onRetry, appName }) {
1100
1421
  const t = useDubsTheme();
1101
- return /* @__PURE__ */ jsx2(View, { style: [s.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs(View, { style: s.spreadContent, children: [
1102
- /* @__PURE__ */ jsxs(View, { style: s.brandingSection, children: [
1103
- /* @__PURE__ */ jsx2(View, { style: [s.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ jsx2(Text, { style: s.logoText, children: "D" }) }),
1104
- /* @__PURE__ */ jsx2(Text, { style: [s.appNameText, { color: t.text }], children: appName })
1422
+ return /* @__PURE__ */ jsx3(View2, { style: [s.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs2(View2, { style: s.spreadContent, children: [
1423
+ /* @__PURE__ */ jsxs2(View2, { style: s.brandingSection, children: [
1424
+ /* @__PURE__ */ jsx3(View2, { style: [s.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ jsx3(Text2, { style: s.logoText, children: "D" }) }),
1425
+ /* @__PURE__ */ jsx3(Text2, { style: [s.appNameText, { color: t.text }], children: appName })
1105
1426
  ] }),
1106
- /* @__PURE__ */ jsxs(View, { style: { gap: 16 }, children: [
1107
- /* @__PURE__ */ jsx2(View, { style: [s.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ jsx2(Text, { style: [s.errorText, { color: t.errorText }], children: error.message }) }),
1108
- /* @__PURE__ */ jsx2(TouchableOpacity, { style: [s.primaryBtn, { backgroundColor: t.accent }], onPress: onRetry, activeOpacity: 0.8, children: /* @__PURE__ */ jsx2(Text, { style: s.primaryBtnText, children: "Try Again" }) })
1427
+ /* @__PURE__ */ jsxs2(View2, { style: { gap: 16 }, children: [
1428
+ /* @__PURE__ */ jsx3(View2, { style: [s.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ jsx3(Text2, { style: [s.errorText, { color: t.errorText }], children: error.message }) }),
1429
+ /* @__PURE__ */ jsx3(TouchableOpacity2, { style: [s.primaryBtn, { backgroundColor: t.accent }], onPress: onRetry, activeOpacity: 0.8, children: /* @__PURE__ */ jsx3(Text2, { style: s.primaryBtnText, children: "Try Again" }) })
1109
1430
  ] })
1110
1431
  ] }) });
1111
1432
  }
1112
1433
  function StepIndicator({ currentStep }) {
1113
1434
  const t = useDubsTheme();
1114
1435
  const steps = [0, 1, 2, 3];
1115
- return /* @__PURE__ */ jsx2(View, { style: s.stepRow, children: steps.map((i) => /* @__PURE__ */ jsxs(React2.Fragment, { children: [
1116
- i > 0 && /* @__PURE__ */ jsx2(View, { style: [s.stepLine, { backgroundColor: i <= currentStep ? t.success : t.border }] }),
1117
- /* @__PURE__ */ jsx2(
1118
- View,
1436
+ return /* @__PURE__ */ jsx3(View2, { style: s.stepRow, children: steps.map((i) => /* @__PURE__ */ jsxs2(React2.Fragment, { children: [
1437
+ i > 0 && /* @__PURE__ */ jsx3(View2, { style: [s.stepLine, { backgroundColor: i <= currentStep ? t.success : t.border }] }),
1438
+ /* @__PURE__ */ jsx3(
1439
+ View2,
1119
1440
  {
1120
1441
  style: [
1121
1442
  s.stepCircle,
1122
1443
  i < currentStep ? { backgroundColor: t.success } : i === currentStep ? { backgroundColor: t.accent } : { backgroundColor: "transparent", borderWidth: 2, borderColor: t.border }
1123
1444
  ],
1124
- children: i < currentStep ? /* @__PURE__ */ jsx2(Text, { style: s.stepCheck, children: "\u2713" }) : /* @__PURE__ */ jsx2(Text, { style: [s.stepNum, { color: i === currentStep ? "#FFF" : t.textMuted }], children: i + 1 })
1445
+ children: i < currentStep ? /* @__PURE__ */ jsx3(Text2, { style: s.stepCheck, children: "\u2713" }) : /* @__PURE__ */ jsx3(Text2, { style: [s.stepNum, { color: i === currentStep ? "#FFF" : t.textMuted }], children: i + 1 })
1125
1446
  }
1126
1447
  )
1127
1448
  ] }, i)) });
@@ -1131,22 +1452,24 @@ function DefaultRegistrationScreen({
1131
1452
  registering,
1132
1453
  error,
1133
1454
  client,
1134
- appName
1455
+ appName,
1456
+ accentColor
1135
1457
  }) {
1136
1458
  const t = useDubsTheme();
1137
- const [step, setStep] = useState9(0);
1138
- const [avatarSeed, setAvatarSeed] = useState9(generateSeed);
1139
- const [avatarStyle, setAvatarStyle] = useState9("adventurer");
1140
- const [showStyles, setShowStyles] = useState9(false);
1141
- const [username, setUsername] = useState9("");
1142
- const [referralCode, setReferralCode] = useState9("");
1143
- const [checking, setChecking] = useState9(false);
1144
- const [availability, setAvailability] = useState9(null);
1145
- const debounceRef = useRef2(null);
1146
- const fadeAnim = useRef2(new Animated.Value(1)).current;
1147
- const slideAnim = useRef2(new Animated.Value(0)).current;
1459
+ const accent = accentColor || t.accent;
1460
+ const [step, setStep] = useState10(0);
1461
+ const [avatarSeed, setAvatarSeed] = useState10(generateSeed);
1462
+ const [avatarStyle, setAvatarStyle] = useState10("adventurer");
1463
+ const [showStyles, setShowStyles] = useState10(false);
1464
+ const [username, setUsername] = useState10("");
1465
+ const [referralCode, setReferralCode] = useState10("");
1466
+ const [checking, setChecking] = useState10(false);
1467
+ const [availability, setAvailability] = useState10(null);
1468
+ const debounceRef = useRef3(null);
1469
+ const fadeAnim = useRef3(new Animated.Value(1)).current;
1470
+ const slideAnim = useRef3(new Animated.Value(0)).current;
1148
1471
  const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed);
1149
- useEffect5(() => {
1472
+ useEffect6(() => {
1150
1473
  if (debounceRef.current) clearTimeout(debounceRef.current);
1151
1474
  const trimmed = username.trim();
1152
1475
  if (trimmed.length < 3) {
@@ -1169,7 +1492,7 @@ function DefaultRegistrationScreen({
1169
1492
  if (debounceRef.current) clearTimeout(debounceRef.current);
1170
1493
  };
1171
1494
  }, [username, client]);
1172
- const animateToStep = useCallback9((newStep) => {
1495
+ const animateToStep = useCallback10((newStep) => {
1173
1496
  const dir = newStep > step ? 1 : -1;
1174
1497
  Keyboard.dismiss();
1175
1498
  Animated.parallel([
@@ -1189,76 +1512,76 @@ function DefaultRegistrationScreen({
1189
1512
  Keyboard.dismiss();
1190
1513
  onRegister(username.trim(), referralCode.trim() || void 0, avatarUrl);
1191
1514
  };
1192
- const renderAvatarStep = () => /* @__PURE__ */ jsxs(View, { style: s.stepContainer, children: [
1193
- /* @__PURE__ */ jsxs(View, { style: s.stepTop, children: [
1194
- /* @__PURE__ */ jsx2(Text, { style: [s.title, { color: t.text }], children: "Choose Your Avatar" }),
1195
- /* @__PURE__ */ jsx2(Text, { style: [s.subtitle, { color: t.textMuted }], children: "Pick a look that represents you" }),
1196
- /* @__PURE__ */ jsx2(StepIndicator, { currentStep: 0 }),
1197
- /* @__PURE__ */ jsx2(View, { style: s.avatarCenter, children: /* @__PURE__ */ jsxs(View, { style: [s.avatarFrame, { borderColor: t.accent }], children: [
1198
- /* @__PURE__ */ jsx2(Image, { source: { uri: avatarUrl }, style: s.avatarLarge }),
1199
- /* @__PURE__ */ jsx2(View, { style: [s.checkBadge, { backgroundColor: t.success }], children: /* @__PURE__ */ jsx2(Text, { style: s.checkBadgeText, children: "\u2713" }) })
1515
+ const renderAvatarStep = () => /* @__PURE__ */ jsxs2(View2, { style: s.stepContainer, children: [
1516
+ /* @__PURE__ */ jsxs2(View2, { style: s.stepTop, children: [
1517
+ /* @__PURE__ */ jsx3(Text2, { style: [s.title, { color: t.text }], children: "Choose Your Avatar" }),
1518
+ /* @__PURE__ */ jsx3(Text2, { style: [s.subtitle, { color: t.textMuted }], children: "Pick a look that represents you" }),
1519
+ /* @__PURE__ */ jsx3(StepIndicator, { currentStep: 0 }),
1520
+ /* @__PURE__ */ jsx3(View2, { style: s.avatarCenter, children: /* @__PURE__ */ jsxs2(View2, { style: [s.avatarFrame, { borderColor: accent }], children: [
1521
+ /* @__PURE__ */ jsx3(Image2, { source: { uri: avatarUrl }, style: s.avatarLarge }),
1522
+ /* @__PURE__ */ jsx3(View2, { style: [s.checkBadge, { backgroundColor: t.success }], children: /* @__PURE__ */ jsx3(Text2, { style: s.checkBadgeText, children: "\u2713" }) })
1200
1523
  ] }) }),
1201
- /* @__PURE__ */ jsxs(View, { style: s.avatarActions, children: [
1202
- /* @__PURE__ */ jsx2(
1203
- TouchableOpacity,
1524
+ /* @__PURE__ */ jsxs2(View2, { style: s.avatarActions, children: [
1525
+ /* @__PURE__ */ jsx3(
1526
+ TouchableOpacity2,
1204
1527
  {
1205
1528
  style: [s.outlineBtn, { borderColor: t.border }],
1206
1529
  onPress: () => setAvatarSeed(generateSeed()),
1207
1530
  activeOpacity: 0.7,
1208
- children: /* @__PURE__ */ jsx2(Text, { style: [s.outlineBtnText, { color: t.text }], children: "\u21BB Shuffle" })
1531
+ children: /* @__PURE__ */ jsx3(Text2, { style: [s.outlineBtnText, { color: t.text }], children: "\u21BB Shuffle" })
1209
1532
  }
1210
1533
  ),
1211
- /* @__PURE__ */ jsx2(
1212
- TouchableOpacity,
1534
+ /* @__PURE__ */ jsx3(
1535
+ TouchableOpacity2,
1213
1536
  {
1214
- style: [s.outlineBtn, { borderColor: t.accent, backgroundColor: t.accent + "15" }],
1537
+ style: [s.outlineBtn, { borderColor: accent, backgroundColor: accent + "15" }],
1215
1538
  onPress: () => setShowStyles(!showStyles),
1216
1539
  activeOpacity: 0.7,
1217
- children: /* @__PURE__ */ jsx2(Text, { style: [s.outlineBtnText, { color: t.accent }], children: "\u263A Customize" })
1540
+ children: /* @__PURE__ */ jsx3(Text2, { style: [s.outlineBtnText, { color: accent }], children: "\u263A Customize" })
1218
1541
  }
1219
1542
  )
1220
1543
  ] }),
1221
- showStyles && /* @__PURE__ */ jsx2(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: s.styleScroll, children: DICEBEAR_STYLES.map((st) => /* @__PURE__ */ jsx2(
1222
- TouchableOpacity,
1544
+ showStyles && /* @__PURE__ */ jsx3(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: s.styleScroll, children: DICEBEAR_STYLES.map((st) => /* @__PURE__ */ jsx3(
1545
+ TouchableOpacity2,
1223
1546
  {
1224
1547
  onPress: () => setAvatarStyle(st),
1225
- style: [s.styleThumbWrap, { borderColor: st === avatarStyle ? t.accent : t.border }],
1226
- children: /* @__PURE__ */ jsx2(Image, { source: { uri: getAvatarUrl(st, avatarSeed, 80) }, style: s.styleThumb })
1548
+ style: [s.styleThumbWrap, { borderColor: st === avatarStyle ? accent : t.border }],
1549
+ children: /* @__PURE__ */ jsx3(Image2, { source: { uri: getAvatarUrl(st, avatarSeed, 80) }, style: s.styleThumb })
1227
1550
  },
1228
1551
  st
1229
1552
  )) })
1230
1553
  ] }),
1231
- /* @__PURE__ */ jsx2(View, { style: s.bottomRow, children: /* @__PURE__ */ jsx2(
1232
- TouchableOpacity,
1554
+ /* @__PURE__ */ jsx3(View2, { style: s.bottomRow, children: /* @__PURE__ */ jsx3(
1555
+ TouchableOpacity2,
1233
1556
  {
1234
- style: [s.primaryBtn, { backgroundColor: t.accent, flex: 1 }],
1557
+ style: [s.primaryBtn, { backgroundColor: accent, flex: 1 }],
1235
1558
  onPress: () => animateToStep(1),
1236
1559
  activeOpacity: 0.8,
1237
- children: /* @__PURE__ */ jsx2(Text, { style: s.primaryBtnText, children: "Continue \u203A" })
1560
+ children: /* @__PURE__ */ jsx3(Text2, { style: s.primaryBtnText, children: "Continue \u203A" })
1238
1561
  }
1239
1562
  ) })
1240
1563
  ] });
1241
- const renderUsernameStep = () => /* @__PURE__ */ jsxs(View, { style: s.stepContainer, children: [
1242
- /* @__PURE__ */ jsxs(View, { style: s.stepTop, children: [
1243
- /* @__PURE__ */ jsxs(View, { style: s.headerRow, children: [
1244
- /* @__PURE__ */ jsx2(TouchableOpacity, { onPress: () => animateToStep(0), hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }, children: /* @__PURE__ */ jsx2(Text, { style: [s.backChevron, { color: t.text }], children: "\u2039" }) }),
1245
- /* @__PURE__ */ jsx2(Text, { style: [s.titleInline, { color: t.text }], children: "Pick a Username" })
1564
+ const renderUsernameStep = () => /* @__PURE__ */ jsxs2(View2, { style: s.stepContainer, children: [
1565
+ /* @__PURE__ */ jsxs2(View2, { style: s.stepTop, children: [
1566
+ /* @__PURE__ */ jsxs2(View2, { style: s.headerRow, children: [
1567
+ /* @__PURE__ */ jsx3(TouchableOpacity2, { onPress: () => animateToStep(0), hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }, children: /* @__PURE__ */ jsx3(Text2, { style: [s.backChevron, { color: t.text }], children: "\u2039" }) }),
1568
+ /* @__PURE__ */ jsx3(Text2, { style: [s.titleInline, { color: t.text }], children: "Pick a Username" })
1246
1569
  ] }),
1247
- /* @__PURE__ */ jsx2(Text, { style: [s.subtitle, { color: t.textMuted }], children: "This is how others will see you" }),
1248
- /* @__PURE__ */ jsx2(StepIndicator, { currentStep: 1 }),
1249
- /* @__PURE__ */ jsx2(View, { style: s.avatarCenter, children: /* @__PURE__ */ jsxs(View, { style: [s.avatarFrameSmall, { borderColor: t.accent }], children: [
1250
- /* @__PURE__ */ jsx2(Image, { source: { uri: avatarUrl }, style: s.avatarSmall }),
1251
- /* @__PURE__ */ jsx2(View, { style: [s.checkBadgeSm, { backgroundColor: t.success }], children: /* @__PURE__ */ jsx2(Text, { style: s.checkBadgeTextSm, children: "\u2713" }) })
1570
+ /* @__PURE__ */ jsx3(Text2, { style: [s.subtitle, { color: t.textMuted }], children: "This is how others will see you" }),
1571
+ /* @__PURE__ */ jsx3(StepIndicator, { currentStep: 1 }),
1572
+ /* @__PURE__ */ jsx3(View2, { style: s.avatarCenter, children: /* @__PURE__ */ jsxs2(View2, { style: [s.avatarFrameSmall, { borderColor: accent }], children: [
1573
+ /* @__PURE__ */ jsx3(Image2, { source: { uri: avatarUrl }, style: s.avatarSmall }),
1574
+ /* @__PURE__ */ jsx3(View2, { style: [s.checkBadgeSm, { backgroundColor: t.success }], children: /* @__PURE__ */ jsx3(Text2, { style: s.checkBadgeTextSm, children: "\u2713" }) })
1252
1575
  ] }) }),
1253
- /* @__PURE__ */ jsxs(View, { style: s.inputGroup, children: [
1254
- /* @__PURE__ */ jsxs(Text, { style: [s.inputLabel, { color: t.text }], children: [
1576
+ /* @__PURE__ */ jsxs2(View2, { style: s.inputGroup, children: [
1577
+ /* @__PURE__ */ jsxs2(Text2, { style: [s.inputLabel, { color: t.text }], children: [
1255
1578
  "Username ",
1256
- /* @__PURE__ */ jsx2(Text, { style: { color: t.errorText }, children: "*" })
1579
+ /* @__PURE__ */ jsx3(Text2, { style: { color: t.errorText }, children: "*" })
1257
1580
  ] }),
1258
- /* @__PURE__ */ jsx2(
1581
+ /* @__PURE__ */ jsx3(
1259
1582
  TextInput,
1260
1583
  {
1261
- style: [s.input, { backgroundColor: t.surface, color: t.text, borderColor: t.accent }],
1584
+ style: [s.input, { backgroundColor: t.surface, color: t.text, borderColor: accent }],
1262
1585
  placeholder: "Enter username",
1263
1586
  placeholderTextColor: t.textDim,
1264
1587
  value: username,
@@ -1268,62 +1591,62 @@ function DefaultRegistrationScreen({
1268
1591
  autoFocus: true
1269
1592
  }
1270
1593
  ),
1271
- checking ? /* @__PURE__ */ jsx2(Text, { style: [s.hint, { color: t.textDim }], children: "Checking..." }) : availability ? /* @__PURE__ */ jsx2(Text, { style: [s.hint, { color: availability.available ? t.success : t.errorText }], children: availability.available ? "\u2713 Available!" : availability.reason || "Username taken" }) : username.trim().length > 0 && username.trim().length < 3 ? /* @__PURE__ */ jsx2(Text, { style: [s.hint, { color: t.textDim }], children: "At least 3 characters" }) : null
1594
+ checking ? /* @__PURE__ */ jsx3(Text2, { style: [s.hint, { color: t.textDim }], children: "Checking..." }) : availability ? /* @__PURE__ */ jsx3(Text2, { style: [s.hint, { color: availability.available ? t.success : t.errorText }], children: availability.available ? "\u2713 Available!" : availability.reason || "Username taken" }) : username.trim().length > 0 && username.trim().length < 3 ? /* @__PURE__ */ jsx3(Text2, { style: [s.hint, { color: t.textDim }], children: "At least 3 characters" }) : null
1272
1595
  ] })
1273
1596
  ] }),
1274
- /* @__PURE__ */ jsxs(View, { style: s.bottomRow, children: [
1275
- /* @__PURE__ */ jsx2(
1276
- TouchableOpacity,
1597
+ /* @__PURE__ */ jsxs2(View2, { style: s.bottomRow, children: [
1598
+ /* @__PURE__ */ jsx3(
1599
+ TouchableOpacity2,
1277
1600
  {
1278
1601
  style: [s.secondaryBtn, { borderColor: t.border }],
1279
1602
  onPress: () => animateToStep(0),
1280
1603
  activeOpacity: 0.7,
1281
- children: /* @__PURE__ */ jsx2(Text, { style: [s.secondaryBtnText, { color: t.text }], children: "\u2039 Back" })
1604
+ children: /* @__PURE__ */ jsx3(Text2, { style: [s.secondaryBtnText, { color: t.text }], children: "\u2039 Back" })
1282
1605
  }
1283
1606
  ),
1284
- /* @__PURE__ */ jsx2(
1285
- TouchableOpacity,
1607
+ /* @__PURE__ */ jsx3(
1608
+ TouchableOpacity2,
1286
1609
  {
1287
- style: [s.primaryBtn, { backgroundColor: t.accent, flex: 1, opacity: canContinueUsername ? 1 : 0.4 }],
1610
+ style: [s.primaryBtn, { backgroundColor: accent, flex: 1, opacity: canContinueUsername ? 1 : 0.4 }],
1288
1611
  onPress: () => animateToStep(2),
1289
1612
  disabled: !canContinueUsername,
1290
1613
  activeOpacity: 0.8,
1291
- children: /* @__PURE__ */ jsx2(Text, { style: s.primaryBtnText, children: "Continue \u203A" })
1614
+ children: /* @__PURE__ */ jsx3(Text2, { style: s.primaryBtnText, children: "Continue \u203A" })
1292
1615
  }
1293
1616
  )
1294
1617
  ] })
1295
1618
  ] });
1296
- const renderReferralStep = () => /* @__PURE__ */ jsxs(View, { style: s.stepContainer, children: [
1297
- /* @__PURE__ */ jsxs(View, { style: s.stepTop, children: [
1298
- /* @__PURE__ */ jsxs(View, { style: s.headerRow, children: [
1299
- /* @__PURE__ */ jsx2(TouchableOpacity, { onPress: () => animateToStep(1), hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }, children: /* @__PURE__ */ jsx2(Text, { style: [s.backChevron, { color: t.text }], children: "\u2039" }) }),
1300
- /* @__PURE__ */ jsx2(Text, { style: [s.titleInline, { color: t.text }], children: "Almost There!" })
1619
+ const renderReferralStep = () => /* @__PURE__ */ jsxs2(View2, { style: s.stepContainer, children: [
1620
+ /* @__PURE__ */ jsxs2(View2, { style: s.stepTop, children: [
1621
+ /* @__PURE__ */ jsxs2(View2, { style: s.headerRow, children: [
1622
+ /* @__PURE__ */ jsx3(TouchableOpacity2, { onPress: () => animateToStep(1), hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }, children: /* @__PURE__ */ jsx3(Text2, { style: [s.backChevron, { color: t.text }], children: "\u2039" }) }),
1623
+ /* @__PURE__ */ jsx3(Text2, { style: [s.titleInline, { color: t.text }], children: "Almost There!" })
1301
1624
  ] }),
1302
- /* @__PURE__ */ jsx2(Text, { style: [s.subtitle, { color: t.textMuted }], children: "Got a referral code? (optional)" }),
1303
- /* @__PURE__ */ jsx2(StepIndicator, { currentStep: 2 }),
1304
- /* @__PURE__ */ jsxs(View, { style: [s.profileCard, { borderColor: t.border }], children: [
1305
- /* @__PURE__ */ jsx2(Text, { style: [s.profileLabel, { color: t.textMuted }], children: "Your Profile" }),
1306
- /* @__PURE__ */ jsxs(View, { style: s.profileRow, children: [
1307
- /* @__PURE__ */ jsx2(Image, { source: { uri: avatarUrl }, style: s.profileAvatar }),
1308
- /* @__PURE__ */ jsxs(View, { style: { gap: 4 }, children: [
1309
- /* @__PURE__ */ jsxs(Text, { style: [s.profileUsername, { color: t.text }], children: [
1625
+ /* @__PURE__ */ jsx3(Text2, { style: [s.subtitle, { color: t.textMuted }], children: "Got a referral code? (optional)" }),
1626
+ /* @__PURE__ */ jsx3(StepIndicator, { currentStep: 2 }),
1627
+ /* @__PURE__ */ jsxs2(View2, { style: [s.profileCard, { borderColor: t.border }], children: [
1628
+ /* @__PURE__ */ jsx3(Text2, { style: [s.profileLabel, { color: t.textMuted }], children: "Your Profile" }),
1629
+ /* @__PURE__ */ jsxs2(View2, { style: s.profileRow, children: [
1630
+ /* @__PURE__ */ jsx3(Image2, { source: { uri: avatarUrl }, style: s.profileAvatar }),
1631
+ /* @__PURE__ */ jsxs2(View2, { style: { gap: 4 }, children: [
1632
+ /* @__PURE__ */ jsxs2(Text2, { style: [s.profileUsername, { color: t.text }], children: [
1310
1633
  "@",
1311
1634
  username
1312
1635
  ] }),
1313
- /* @__PURE__ */ jsxs(Text, { style: [s.profileReady, { color: t.success }], children: [
1636
+ /* @__PURE__ */ jsxs2(Text2, { style: [s.profileReady, { color: t.success }], children: [
1314
1637
  "\u2713",
1315
1638
  " Ready to go!"
1316
1639
  ] })
1317
1640
  ] })
1318
1641
  ] })
1319
1642
  ] }),
1320
- error ? /* @__PURE__ */ jsx2(View, { style: [s.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ jsx2(Text, { style: [s.errorText, { color: t.errorText }], children: error.message }) }) : null,
1321
- /* @__PURE__ */ jsxs(View, { style: s.inputGroup, children: [
1322
- /* @__PURE__ */ jsxs(Text, { style: [s.inputLabel, { color: t.text }], children: [
1643
+ error ? /* @__PURE__ */ jsx3(View2, { style: [s.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ jsx3(Text2, { style: [s.errorText, { color: t.errorText }], children: error.message }) }) : null,
1644
+ /* @__PURE__ */ jsxs2(View2, { style: s.inputGroup, children: [
1645
+ /* @__PURE__ */ jsxs2(Text2, { style: [s.inputLabel, { color: t.text }], children: [
1323
1646
  "Referral Code ",
1324
- /* @__PURE__ */ jsx2(Text, { style: { color: t.textMuted }, children: "(optional)" })
1647
+ /* @__PURE__ */ jsx3(Text2, { style: { color: t.textMuted }, children: "(optional)" })
1325
1648
  ] }),
1326
- /* @__PURE__ */ jsx2(
1649
+ /* @__PURE__ */ jsx3(
1327
1650
  TextInput,
1328
1651
  {
1329
1652
  style: [s.input, { backgroundColor: t.surface, color: t.text, borderColor: t.border }],
@@ -1336,31 +1659,31 @@ function DefaultRegistrationScreen({
1336
1659
  editable: !registering
1337
1660
  }
1338
1661
  ),
1339
- /* @__PURE__ */ jsxs(Text, { style: [s.hint, { color: t.textMuted }], children: [
1662
+ /* @__PURE__ */ jsxs2(Text2, { style: [s.hint, { color: t.textMuted }], children: [
1340
1663
  "\u{1F381}",
1341
1664
  " If a friend invited you, enter their code to give them credit!"
1342
1665
  ] })
1343
1666
  ] })
1344
1667
  ] }),
1345
- /* @__PURE__ */ jsxs(View, { style: s.bottomRow, children: [
1346
- /* @__PURE__ */ jsx2(
1347
- TouchableOpacity,
1668
+ /* @__PURE__ */ jsxs2(View2, { style: s.bottomRow, children: [
1669
+ /* @__PURE__ */ jsx3(
1670
+ TouchableOpacity2,
1348
1671
  {
1349
1672
  style: [s.secondaryBtn, { borderColor: t.border }],
1350
1673
  onPress: () => animateToStep(1),
1351
1674
  disabled: registering,
1352
1675
  activeOpacity: 0.7,
1353
- children: /* @__PURE__ */ jsx2(Text, { style: [s.secondaryBtnText, { color: t.text }], children: "\u2039 Back" })
1676
+ children: /* @__PURE__ */ jsx3(Text2, { style: [s.secondaryBtnText, { color: t.text }], children: "\u2039 Back" })
1354
1677
  }
1355
1678
  ),
1356
- /* @__PURE__ */ jsx2(
1357
- TouchableOpacity,
1679
+ /* @__PURE__ */ jsx3(
1680
+ TouchableOpacity2,
1358
1681
  {
1359
- style: [s.primaryBtn, { backgroundColor: t.accent, flex: 1, opacity: registering ? 0.7 : 1 }],
1682
+ style: [s.primaryBtn, { backgroundColor: accent, flex: 1, opacity: registering ? 0.7 : 1 }],
1360
1683
  onPress: handleSubmit,
1361
1684
  disabled: registering,
1362
1685
  activeOpacity: 0.8,
1363
- children: registering ? /* @__PURE__ */ jsx2(ActivityIndicator, { color: "#FFFFFF", size: "small" }) : /* @__PURE__ */ jsx2(Text, { style: s.primaryBtnText, children: "Create Account" })
1686
+ children: registering ? /* @__PURE__ */ jsx3(ActivityIndicator2, { color: "#FFFFFF", size: "small" }) : /* @__PURE__ */ jsx3(Text2, { style: s.primaryBtnText, children: "Create Account" })
1364
1687
  }
1365
1688
  )
1366
1689
  ] })
@@ -1377,18 +1700,18 @@ function DefaultRegistrationScreen({
1377
1700
  return null;
1378
1701
  }
1379
1702
  };
1380
- return /* @__PURE__ */ jsx2(
1703
+ return /* @__PURE__ */ jsx3(
1381
1704
  KeyboardAvoidingView,
1382
1705
  {
1383
1706
  style: [s.container, { backgroundColor: t.background }],
1384
1707
  behavior: Platform.OS === "ios" ? "padding" : void 0,
1385
- children: /* @__PURE__ */ jsx2(
1708
+ children: /* @__PURE__ */ jsx3(
1386
1709
  ScrollView,
1387
1710
  {
1388
1711
  contentContainerStyle: { flexGrow: 1 },
1389
1712
  keyboardShouldPersistTaps: "handled",
1390
1713
  bounces: false,
1391
- children: /* @__PURE__ */ jsx2(
1714
+ children: /* @__PURE__ */ jsx3(
1392
1715
  Animated.View,
1393
1716
  {
1394
1717
  style: [
@@ -1403,7 +1726,7 @@ function DefaultRegistrationScreen({
1403
1726
  }
1404
1727
  );
1405
1728
  }
1406
- var s = StyleSheet.create({
1729
+ var s = StyleSheet2.create({
1407
1730
  container: { flex: 1 },
1408
1731
  // Loading / Error
1409
1732
  centerContent: { flex: 1, justifyContent: "center", alignItems: "center", paddingHorizontal: 32, gap: 48 },
@@ -1466,125 +1789,179 @@ var s = StyleSheet.create({
1466
1789
  secondaryBtnText: { fontSize: 16, fontWeight: "600" }
1467
1790
  });
1468
1791
 
1469
- // src/ui/ConnectWalletScreen.tsx
1470
- import {
1471
- View as View2,
1472
- Text as Text2,
1473
- TouchableOpacity as TouchableOpacity2,
1474
- ActivityIndicator as ActivityIndicator2,
1475
- StyleSheet as StyleSheet2
1476
- } from "react-native";
1477
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1478
- function ConnectWalletScreen({
1479
- onConnect,
1480
- connecting = false,
1481
- error = null,
1482
- appName = "Dubs"
1792
+ // src/provider.tsx
1793
+ import { jsx as jsx4 } from "react/jsx-runtime";
1794
+ var DubsContext = createContext3(null);
1795
+ function DubsProvider({
1796
+ apiKey,
1797
+ children,
1798
+ appName = "Dubs",
1799
+ network = "mainnet-beta",
1800
+ wallet: externalWallet,
1801
+ tokenStorage,
1802
+ baseUrl: baseUrlOverride,
1803
+ rpcUrl: rpcUrlOverride,
1804
+ renderConnectScreen,
1805
+ renderLoading,
1806
+ renderError,
1807
+ renderRegistration,
1808
+ managed = true
1483
1809
  }) {
1484
- const t = useDubsTheme();
1485
- return /* @__PURE__ */ jsx3(View2, { style: [styles.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs2(View2, { style: styles.content, children: [
1486
- /* @__PURE__ */ jsxs2(View2, { style: styles.brandingSection, children: [
1487
- /* @__PURE__ */ jsx3(View2, { style: [styles.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ jsx3(Text2, { style: styles.logoText, children: "D" }) }),
1488
- /* @__PURE__ */ jsx3(Text2, { style: [styles.appName, { color: t.text }], children: appName }),
1489
- /* @__PURE__ */ jsx3(Text2, { style: [styles.subtitle, { color: t.textMuted }], children: "Connect your Solana wallet to get started" })
1490
- ] }),
1491
- /* @__PURE__ */ jsxs2(View2, { style: styles.actionSection, children: [
1492
- error ? /* @__PURE__ */ jsx3(
1493
- View2,
1494
- {
1495
- style: [
1496
- styles.errorBox,
1497
- { backgroundColor: t.errorBg, borderColor: t.errorBorder }
1498
- ],
1499
- children: /* @__PURE__ */ jsx3(Text2, { style: [styles.errorText, { color: t.errorText }], children: error })
1500
- }
1501
- ) : null,
1502
- /* @__PURE__ */ jsx3(
1503
- TouchableOpacity2,
1810
+ const config = NETWORK_CONFIG[network];
1811
+ const baseUrl = baseUrlOverride || config.baseUrl;
1812
+ const rpcUrl = rpcUrlOverride || config.rpcUrl;
1813
+ const cluster = config.cluster;
1814
+ const client = useMemo(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
1815
+ const connection = useMemo(() => new Connection(rpcUrl, { commitment: "confirmed" }), [rpcUrl]);
1816
+ const storage = useMemo(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
1817
+ const [uiConfig, setUiConfig] = useState11({});
1818
+ useEffect7(() => {
1819
+ client.getAppConfig().then(setUiConfig).catch(() => {
1820
+ });
1821
+ }, [client]);
1822
+ if (externalWallet) {
1823
+ return /* @__PURE__ */ jsx4(
1824
+ ExternalWalletProvider,
1825
+ {
1826
+ client,
1827
+ connection,
1828
+ wallet: externalWallet,
1829
+ appName: uiConfig.appName || appName,
1830
+ network,
1831
+ storage,
1832
+ managed,
1833
+ renderLoading,
1834
+ renderError,
1835
+ renderRegistration,
1836
+ accentColor: uiConfig.accentColor,
1837
+ children
1838
+ }
1839
+ );
1840
+ }
1841
+ return /* @__PURE__ */ jsx4(
1842
+ ManagedWalletProvider,
1843
+ {
1844
+ appName: uiConfig.appName || appName,
1845
+ cluster,
1846
+ storage,
1847
+ renderConnectScreen,
1848
+ accentColor: uiConfig.accentColor,
1849
+ appIcon: uiConfig.appIcon,
1850
+ tagline: uiConfig.tagline,
1851
+ children: (adapter) => /* @__PURE__ */ jsx4(
1852
+ ManagedInner,
1504
1853
  {
1505
- style: [styles.connectButton, { backgroundColor: t.accent }],
1506
- onPress: onConnect,
1507
- disabled: connecting,
1508
- activeOpacity: 0.8,
1509
- children: connecting ? /* @__PURE__ */ jsx3(ActivityIndicator2, { color: "#FFFFFF", size: "small" }) : /* @__PURE__ */ jsx3(Text2, { style: styles.connectButtonText, children: "Connect Wallet" })
1854
+ client,
1855
+ connection,
1856
+ wallet: adapter,
1857
+ appName: uiConfig.appName || appName,
1858
+ network,
1859
+ storage,
1860
+ renderLoading,
1861
+ renderError,
1862
+ renderRegistration,
1863
+ accentColor: uiConfig.accentColor,
1864
+ children
1510
1865
  }
1511
- ),
1512
- /* @__PURE__ */ jsx3(Text2, { style: [styles.hint, { color: t.textDim }], children: "Phantom, Solflare, or any Solana wallet" })
1513
- ] })
1514
- ] }) });
1866
+ )
1867
+ }
1868
+ );
1515
1869
  }
1516
- var styles = StyleSheet2.create({
1517
- container: {
1518
- flex: 1,
1519
- justifyContent: "center"
1520
- },
1521
- content: {
1522
- flex: 1,
1523
- justifyContent: "space-between",
1524
- paddingHorizontal: 32,
1525
- paddingTop: 120,
1526
- paddingBottom: 80
1527
- },
1528
- brandingSection: {
1529
- alignItems: "center",
1530
- gap: 12
1531
- },
1532
- logoCircle: {
1533
- width: 80,
1534
- height: 80,
1535
- borderRadius: 40,
1536
- justifyContent: "center",
1537
- alignItems: "center",
1538
- marginBottom: 8
1539
- },
1540
- logoText: {
1541
- fontSize: 36,
1542
- fontWeight: "800",
1543
- color: "#FFFFFF"
1544
- },
1545
- appName: {
1546
- fontSize: 32,
1547
- fontWeight: "800"
1548
- },
1549
- subtitle: {
1550
- fontSize: 16,
1551
- textAlign: "center",
1552
- lineHeight: 22
1553
- },
1554
- actionSection: {
1555
- gap: 16
1556
- },
1557
- errorBox: {
1558
- borderWidth: 1,
1559
- borderRadius: 12,
1560
- paddingHorizontal: 16,
1561
- paddingVertical: 12
1562
- },
1563
- errorText: {
1564
- fontSize: 14,
1565
- textAlign: "center"
1566
- },
1567
- connectButton: {
1568
- height: 56,
1569
- borderRadius: 16,
1570
- justifyContent: "center",
1571
- alignItems: "center"
1572
- },
1573
- connectButtonText: {
1574
- color: "#FFFFFF",
1575
- fontSize: 18,
1576
- fontWeight: "700"
1577
- },
1578
- hint: {
1579
- fontSize: 13,
1580
- textAlign: "center"
1870
+ function ManagedInner({
1871
+ client,
1872
+ connection,
1873
+ wallet,
1874
+ appName,
1875
+ network,
1876
+ storage,
1877
+ renderLoading,
1878
+ renderError,
1879
+ renderRegistration,
1880
+ accentColor,
1881
+ children
1882
+ }) {
1883
+ const managedDisconnect = useDisconnect();
1884
+ const disconnect = useCallback11(async () => {
1885
+ client.setToken(null);
1886
+ await managedDisconnect?.();
1887
+ }, [client, managedDisconnect]);
1888
+ const value = useMemo(
1889
+ () => ({ client, wallet, connection, appName, network, disconnect }),
1890
+ [client, wallet, connection, appName, network, disconnect]
1891
+ );
1892
+ return /* @__PURE__ */ jsx4(DubsContext.Provider, { value, children: /* @__PURE__ */ jsx4(
1893
+ AuthGate,
1894
+ {
1895
+ onSaveToken: (token) => {
1896
+ if (token) return storage.setItem(STORAGE_KEYS.JWT_TOKEN, token);
1897
+ return storage.deleteItem(STORAGE_KEYS.JWT_TOKEN);
1898
+ },
1899
+ onLoadToken: () => storage.getItem(STORAGE_KEYS.JWT_TOKEN),
1900
+ renderLoading,
1901
+ renderError,
1902
+ renderRegistration,
1903
+ appName,
1904
+ accentColor,
1905
+ children
1906
+ }
1907
+ ) });
1908
+ }
1909
+ function ExternalWalletProvider({
1910
+ client,
1911
+ connection,
1912
+ wallet,
1913
+ appName,
1914
+ network,
1915
+ storage,
1916
+ managed,
1917
+ renderLoading,
1918
+ renderError,
1919
+ renderRegistration,
1920
+ accentColor,
1921
+ children
1922
+ }) {
1923
+ const disconnect = useCallback11(async () => {
1924
+ client.setToken(null);
1925
+ await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
1926
+ });
1927
+ await wallet.disconnect?.();
1928
+ }, [client, storage, wallet]);
1929
+ const value = useMemo(
1930
+ () => ({ client, wallet, connection, appName, network, disconnect }),
1931
+ [client, wallet, connection, appName, network, disconnect]
1932
+ );
1933
+ if (!managed) {
1934
+ return /* @__PURE__ */ jsx4(DubsContext.Provider, { value, children });
1581
1935
  }
1582
- });
1936
+ return /* @__PURE__ */ jsx4(DubsContext.Provider, { value, children: /* @__PURE__ */ jsx4(
1937
+ AuthGate,
1938
+ {
1939
+ onSaveToken: (token) => {
1940
+ if (token) return storage.setItem(STORAGE_KEYS.JWT_TOKEN, token);
1941
+ return storage.deleteItem(STORAGE_KEYS.JWT_TOKEN);
1942
+ },
1943
+ onLoadToken: () => storage.getItem(STORAGE_KEYS.JWT_TOKEN),
1944
+ renderLoading,
1945
+ renderError,
1946
+ renderRegistration,
1947
+ appName,
1948
+ accentColor,
1949
+ children
1950
+ }
1951
+ ) });
1952
+ }
1953
+ function useDubs() {
1954
+ const ctx = useContext3(DubsContext);
1955
+ if (!ctx) {
1956
+ throw new Error("useDubs must be used within a <DubsProvider>");
1957
+ }
1958
+ return ctx;
1959
+ }
1583
1960
 
1584
1961
  // src/ui/UserProfileCard.tsx
1585
1962
  import { useMemo as useMemo2 } from "react";
1586
- import { View as View3, Text as Text3, Image as Image2, StyleSheet as StyleSheet3 } from "react-native";
1587
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1963
+ import { View as View3, Text as Text3, Image as Image3, StyleSheet as StyleSheet3 } from "react-native";
1964
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1588
1965
  function truncateAddress(address, chars = 4) {
1589
1966
  if (address.length <= chars * 2 + 3) return address;
1590
1967
  return `${address.slice(0, chars)}...${address.slice(-chars)}`;
@@ -1607,11 +1984,11 @@ function UserProfileCard({
1607
1984
  [avatarUrl, walletAddress]
1608
1985
  );
1609
1986
  return /* @__PURE__ */ jsxs3(View3, { style: [styles2.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
1610
- /* @__PURE__ */ jsx4(Image2, { source: { uri: imageUri }, style: styles2.avatar }),
1987
+ /* @__PURE__ */ jsx5(Image3, { source: { uri: imageUri }, style: styles2.avatar }),
1611
1988
  /* @__PURE__ */ jsxs3(View3, { style: styles2.info, children: [
1612
- username ? /* @__PURE__ */ jsx4(Text3, { style: [styles2.username, { color: t.text }], children: username }) : null,
1613
- /* @__PURE__ */ jsx4(Text3, { style: [styles2.address, { color: t.textMuted }], children: truncateAddress(walletAddress) }),
1614
- memberSince ? /* @__PURE__ */ jsx4(Text3, { style: [styles2.memberSince, { color: t.textDim }], children: formatMemberSince(memberSince) }) : null
1989
+ username ? /* @__PURE__ */ jsx5(Text3, { style: [styles2.username, { color: t.text }], children: username }) : null,
1990
+ /* @__PURE__ */ jsx5(Text3, { style: [styles2.address, { color: t.textMuted }], children: truncateAddress(walletAddress) }),
1991
+ memberSince ? /* @__PURE__ */ jsx5(Text3, { style: [styles2.memberSince, { color: t.textDim }], children: formatMemberSince(memberSince) }) : null
1615
1992
  ] })
1616
1993
  ] });
1617
1994
  }
@@ -1657,7 +2034,7 @@ import {
1657
2034
  ActivityIndicator as ActivityIndicator3,
1658
2035
  StyleSheet as StyleSheet4
1659
2036
  } from "react-native";
1660
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
2037
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1661
2038
  function truncateAddress2(address, chars = 4) {
1662
2039
  if (address.length <= chars * 2 + 3) return address;
1663
2040
  return `${address.slice(0, chars)}...${address.slice(-chars)}`;
@@ -1680,7 +2057,7 @@ function SettingsSheet({
1680
2057
  style: [styles3.container, { backgroundColor: t.background }],
1681
2058
  contentContainerStyle: styles3.content,
1682
2059
  children: [
1683
- /* @__PURE__ */ jsx5(
2060
+ /* @__PURE__ */ jsx6(
1684
2061
  UserProfileCard,
1685
2062
  {
1686
2063
  walletAddress,
@@ -1698,15 +2075,15 @@ function SettingsSheet({
1698
2075
  activeOpacity: 0.7,
1699
2076
  children: [
1700
2077
  /* @__PURE__ */ jsxs4(View4, { style: styles3.actionRowLeft, children: [
1701
- /* @__PURE__ */ jsx5(Text4, { style: [styles3.actionLabel, { color: t.text }], children: "Wallet Address" }),
1702
- /* @__PURE__ */ jsx5(Text4, { style: [styles3.actionValue, { color: t.textMuted }], children: truncateAddress2(walletAddress) })
2078
+ /* @__PURE__ */ jsx6(Text4, { style: [styles3.actionLabel, { color: t.text }], children: "Wallet Address" }),
2079
+ /* @__PURE__ */ jsx6(Text4, { style: [styles3.actionValue, { color: t.textMuted }], children: truncateAddress2(walletAddress) })
1703
2080
  ] }),
1704
- /* @__PURE__ */ jsx5(Text4, { style: [styles3.copyLabel, { color: t.accent }], children: "Copy" })
2081
+ /* @__PURE__ */ jsx6(Text4, { style: [styles3.copyLabel, { color: t.accent }], children: "Copy" })
1705
2082
  ]
1706
2083
  }
1707
2084
  ) : null,
1708
- onSupport ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
1709
- onCopyAddress ? /* @__PURE__ */ jsx5(View4, { style: [styles3.separator, { backgroundColor: t.border }] }) : null,
2085
+ onSupport ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
2086
+ onCopyAddress ? /* @__PURE__ */ jsx6(View4, { style: [styles3.separator, { backgroundColor: t.border }] }) : null,
1710
2087
  /* @__PURE__ */ jsxs4(
1711
2088
  TouchableOpacity3,
1712
2089
  {
@@ -1714,21 +2091,21 @@ function SettingsSheet({
1714
2091
  onPress: onSupport,
1715
2092
  activeOpacity: 0.7,
1716
2093
  children: [
1717
- /* @__PURE__ */ jsx5(Text4, { style: [styles3.actionLabel, { color: t.text }], children: "Help & Support" }),
1718
- /* @__PURE__ */ jsx5(Text4, { style: [styles3.chevron, { color: t.textMuted }], children: "\u203A" })
2094
+ /* @__PURE__ */ jsx6(Text4, { style: [styles3.actionLabel, { color: t.text }], children: "Help & Support" }),
2095
+ /* @__PURE__ */ jsx6(Text4, { style: [styles3.chevron, { color: t.textMuted }], children: "\u203A" })
1719
2096
  ]
1720
2097
  }
1721
2098
  )
1722
2099
  ] }) : null
1723
2100
  ] }),
1724
- /* @__PURE__ */ jsx5(
2101
+ /* @__PURE__ */ jsx6(
1725
2102
  TouchableOpacity3,
1726
2103
  {
1727
2104
  style: [styles3.logoutButton, { borderColor: t.live }],
1728
2105
  onPress: onLogout,
1729
2106
  disabled: loggingOut,
1730
2107
  activeOpacity: 0.7,
1731
- children: loggingOut ? /* @__PURE__ */ jsx5(ActivityIndicator3, { color: t.live, size: "small" }) : /* @__PURE__ */ jsx5(Text4, { style: [styles3.logoutText, { color: t.live }], children: "Log Out" })
2108
+ children: loggingOut ? /* @__PURE__ */ jsx6(ActivityIndicator3, { color: t.live, size: "small" }) : /* @__PURE__ */ jsx6(Text4, { style: [styles3.logoutText, { color: t.live }], children: "Log Out" })
1732
2109
  }
1733
2110
  ),
1734
2111
  appVersion ? /* @__PURE__ */ jsxs4(Text4, { style: [styles3.version, { color: t.textDim }], children: [
@@ -1800,6 +2177,476 @@ var styles3 = StyleSheet4.create({
1800
2177
  textAlign: "center"
1801
2178
  }
1802
2179
  });
2180
+
2181
+ // src/ui/game/GamePoster.tsx
2182
+ import { useState as useState12 } from "react";
2183
+ import { StyleSheet as StyleSheet5, View as View5, Text as Text5 } from "react-native";
2184
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2185
+ function computeCountdown(lockTimestamp) {
2186
+ if (!lockTimestamp) return "";
2187
+ const ts = typeof lockTimestamp === "string" ? parseInt(lockTimestamp) : lockTimestamp;
2188
+ const diff = ts * 1e3 - Date.now();
2189
+ if (diff <= 0) return "LIVE";
2190
+ const days = Math.floor(diff / 864e5);
2191
+ const hours = Math.floor(diff % 864e5 / 36e5);
2192
+ const mins = Math.floor(diff % 36e5 / 6e4);
2193
+ if (days > 0) return `${days}d ${hours}h`;
2194
+ if (hours > 0) return `${hours}h ${mins}m`;
2195
+ return `${mins}m`;
2196
+ }
2197
+ function GamePoster({ game, ImageComponent }) {
2198
+ const t = useDubsTheme();
2199
+ const Img = ImageComponent || __require("react-native").Image;
2200
+ const opponents = game.opponents || [];
2201
+ const home = opponents[0];
2202
+ const away = opponents[1];
2203
+ const countdown = computeCountdown(game.lockTimestamp);
2204
+ const isLive = countdown === "LIVE";
2205
+ return /* @__PURE__ */ jsxs5(View5, { style: styles4.container, children: [
2206
+ game.media?.poster ? /* @__PURE__ */ jsx7(
2207
+ Img,
2208
+ {
2209
+ source: { uri: game.media.poster },
2210
+ style: styles4.image,
2211
+ resizeMode: "cover"
2212
+ }
2213
+ ) : /* @__PURE__ */ jsx7(View5, { style: [styles4.image, { backgroundColor: t.surface }], children: /* @__PURE__ */ jsxs5(View5, { style: styles4.fallback, children: [
2214
+ /* @__PURE__ */ jsx7(TeamLogoInternal, { url: home?.imageUrl, size: 56, Img }),
2215
+ /* @__PURE__ */ jsx7(Text5, { style: styles4.vs, children: "VS" }),
2216
+ /* @__PURE__ */ jsx7(TeamLogoInternal, { url: away?.imageUrl, size: 56, Img })
2217
+ ] }) }),
2218
+ /* @__PURE__ */ jsx7(View5, { style: styles4.overlay }),
2219
+ /* @__PURE__ */ jsxs5(View5, { style: styles4.teamNames, children: [
2220
+ /* @__PURE__ */ jsx7(Text5, { style: styles4.teamNameText, numberOfLines: 1, children: home?.name || "Home" }),
2221
+ /* @__PURE__ */ jsx7(Text5, { style: styles4.teamNameVs, children: "vs" }),
2222
+ /* @__PURE__ */ jsx7(Text5, { style: styles4.teamNameText, numberOfLines: 1, children: away?.name || "Away" })
2223
+ ] }),
2224
+ countdown ? /* @__PURE__ */ jsx7(View5, { style: styles4.countdownPill, children: /* @__PURE__ */ jsx7(Text5, { style: [styles4.countdownText, isLive && styles4.countdownLive], children: countdown }) }) : null,
2225
+ /* @__PURE__ */ jsx7(View5, { style: styles4.poolPill, children: /* @__PURE__ */ jsxs5(Text5, { style: styles4.poolText, children: [
2226
+ game.totalPool || 0,
2227
+ " SOL"
2228
+ ] }) })
2229
+ ] });
2230
+ }
2231
+ function TeamLogoInternal({ url, size, Img }) {
2232
+ const [failed, setFailed] = useState12(false);
2233
+ if (!url || failed) {
2234
+ return /* @__PURE__ */ jsx7(View5, { style: [styles4.logoPlaceholder, { width: size, height: size, borderRadius: size / 2 }] });
2235
+ }
2236
+ return /* @__PURE__ */ jsx7(
2237
+ Img,
2238
+ {
2239
+ source: { uri: url },
2240
+ style: { width: size, height: size, borderRadius: size / 2 },
2241
+ resizeMode: "contain",
2242
+ onError: () => setFailed(true)
2243
+ }
2244
+ );
2245
+ }
2246
+ var styles4 = StyleSheet5.create({
2247
+ container: {
2248
+ height: 200,
2249
+ borderRadius: 16,
2250
+ overflow: "hidden",
2251
+ position: "relative"
2252
+ },
2253
+ image: {
2254
+ ...StyleSheet5.absoluteFillObject,
2255
+ justifyContent: "center",
2256
+ alignItems: "center"
2257
+ },
2258
+ overlay: {
2259
+ ...StyleSheet5.absoluteFillObject,
2260
+ backgroundColor: "rgba(0,0,0,0.35)"
2261
+ },
2262
+ fallback: {
2263
+ flexDirection: "row",
2264
+ alignItems: "center",
2265
+ gap: 24,
2266
+ zIndex: 2
2267
+ },
2268
+ vs: {
2269
+ color: "#FFF",
2270
+ fontSize: 24,
2271
+ fontWeight: "900",
2272
+ zIndex: 2
2273
+ },
2274
+ logoPlaceholder: {
2275
+ backgroundColor: "rgba(255,255,255,0.15)",
2276
+ zIndex: 2
2277
+ },
2278
+ teamNames: {
2279
+ position: "absolute",
2280
+ top: 12,
2281
+ left: 12,
2282
+ right: 12,
2283
+ flexDirection: "row",
2284
+ alignItems: "center",
2285
+ justifyContent: "center",
2286
+ gap: 8
2287
+ },
2288
+ teamNameText: {
2289
+ color: "#FFF",
2290
+ fontSize: 14,
2291
+ fontWeight: "700",
2292
+ maxWidth: "40%"
2293
+ },
2294
+ teamNameVs: {
2295
+ color: "rgba(255,255,255,0.6)",
2296
+ fontSize: 12,
2297
+ fontWeight: "600"
2298
+ },
2299
+ countdownPill: {
2300
+ position: "absolute",
2301
+ bottom: 12,
2302
+ left: 12,
2303
+ backgroundColor: "rgba(0,0,0,0.65)",
2304
+ borderRadius: 8,
2305
+ paddingHorizontal: 10,
2306
+ paddingVertical: 5
2307
+ },
2308
+ countdownText: {
2309
+ color: "#FFF",
2310
+ fontSize: 13,
2311
+ fontWeight: "700"
2312
+ },
2313
+ countdownLive: {
2314
+ color: "#EF4444"
2315
+ },
2316
+ poolPill: {
2317
+ position: "absolute",
2318
+ bottom: 12,
2319
+ right: 12,
2320
+ backgroundColor: "#7C3AED",
2321
+ borderRadius: 8,
2322
+ paddingHorizontal: 12,
2323
+ paddingVertical: 5
2324
+ },
2325
+ poolText: {
2326
+ color: "#FFF",
2327
+ fontSize: 13,
2328
+ fontWeight: "800"
2329
+ }
2330
+ });
2331
+
2332
+ // src/ui/game/LivePoolsCard.tsx
2333
+ import { useMemo as useMemo3 } from "react";
2334
+ import { StyleSheet as StyleSheet6, View as View6, Text as Text6 } from "react-native";
2335
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2336
+ function LivePoolsCard({
2337
+ game,
2338
+ shortName,
2339
+ homeColor = "#3B82F6",
2340
+ awayColor = "#EF4444"
2341
+ }) {
2342
+ const t = useDubsTheme();
2343
+ const opponents = game.opponents || [];
2344
+ const homeName = shortName ? shortName(opponents[0]?.name) : opponents[0]?.name || "Home";
2345
+ const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
2346
+ const homePool = game.homePool || 0;
2347
+ const awayPool = game.awayPool || 0;
2348
+ const totalPool = game.totalPool || 0;
2349
+ const { homePercent, awayPercent, homeOdds, awayOdds } = useMemo3(() => {
2350
+ return {
2351
+ homePercent: totalPool > 0 ? homePool / totalPool * 100 : 50,
2352
+ awayPercent: totalPool > 0 ? awayPool / totalPool * 100 : 50,
2353
+ homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
2354
+ awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014"
2355
+ };
2356
+ }, [homePool, awayPool, totalPool]);
2357
+ return /* @__PURE__ */ jsxs6(View6, { style: [styles5.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
2358
+ /* @__PURE__ */ jsx8(Text6, { style: [styles5.title, { color: t.text }], children: "Live Pools" }),
2359
+ /* @__PURE__ */ jsxs6(Text6, { style: [styles5.total, { color: t.accent }], children: [
2360
+ totalPool,
2361
+ " SOL total"
2362
+ ] }),
2363
+ /* @__PURE__ */ jsxs6(View6, { style: styles5.bars, children: [
2364
+ /* @__PURE__ */ jsx8(PoolBar, { name: homeName, amount: homePool, percent: homePercent, color: homeColor, t }),
2365
+ /* @__PURE__ */ jsx8(PoolBar, { name: awayName, amount: awayPool, percent: awayPercent, color: awayColor, t })
2366
+ ] }),
2367
+ /* @__PURE__ */ jsxs6(View6, { style: styles5.oddsRow, children: [
2368
+ /* @__PURE__ */ jsxs6(Text6, { style: [styles5.oddsText, { color: t.textMuted }], children: [
2369
+ homeName,
2370
+ ": ",
2371
+ /* @__PURE__ */ jsxs6(Text6, { style: { color: t.text, fontWeight: "700" }, children: [
2372
+ homeOdds,
2373
+ "x"
2374
+ ] })
2375
+ ] }),
2376
+ /* @__PURE__ */ jsxs6(Text6, { style: [styles5.oddsText, { color: t.textMuted }], children: [
2377
+ awayName,
2378
+ ": ",
2379
+ /* @__PURE__ */ jsxs6(Text6, { style: { color: t.text, fontWeight: "700" }, children: [
2380
+ awayOdds,
2381
+ "x"
2382
+ ] })
2383
+ ] })
2384
+ ] })
2385
+ ] });
2386
+ }
2387
+ function PoolBar({ name, amount, percent, color, t }) {
2388
+ return /* @__PURE__ */ jsxs6(View6, { style: styles5.barRow, children: [
2389
+ /* @__PURE__ */ jsx8(Text6, { style: [styles5.barLabel, { color: t.textSecondary }], numberOfLines: 1, children: name }),
2390
+ /* @__PURE__ */ jsx8(View6, { style: [styles5.barTrack, { backgroundColor: t.border }], children: /* @__PURE__ */ jsx8(View6, { style: [styles5.barFill, { width: `${Math.max(percent, 2)}%`, backgroundColor: color }] }) }),
2391
+ /* @__PURE__ */ jsxs6(Text6, { style: [styles5.barAmount, { color: t.text }], children: [
2392
+ amount,
2393
+ " SOL"
2394
+ ] })
2395
+ ] });
2396
+ }
2397
+ var styles5 = StyleSheet6.create({
2398
+ card: { borderRadius: 16, borderWidth: 1, padding: 16 },
2399
+ title: { fontSize: 17, fontWeight: "700", marginBottom: 4 },
2400
+ total: { fontSize: 14, fontWeight: "600", marginBottom: 14 },
2401
+ bars: { gap: 10 },
2402
+ barRow: { flexDirection: "row", alignItems: "center", gap: 10 },
2403
+ barLabel: { width: 80, fontSize: 13, fontWeight: "600" },
2404
+ barTrack: { flex: 1, height: 10, borderRadius: 5, overflow: "hidden" },
2405
+ barFill: { height: "100%", borderRadius: 5 },
2406
+ barAmount: { width: 70, textAlign: "right", fontSize: 13, fontWeight: "700" },
2407
+ oddsRow: { flexDirection: "row", justifyContent: "space-between", marginTop: 12 },
2408
+ oddsText: { fontSize: 12 }
2409
+ });
2410
+
2411
+ // src/ui/game/PickWinnerCard.tsx
2412
+ import { useState as useState13, useMemo as useMemo4 } from "react";
2413
+ import { StyleSheet as StyleSheet7, View as View7, Text as Text7, TouchableOpacity as TouchableOpacity4 } from "react-native";
2414
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2415
+ function PickWinnerCard({
2416
+ game,
2417
+ selectedTeam,
2418
+ onSelect,
2419
+ shortName,
2420
+ homeColor = "#3B82F6",
2421
+ awayColor = "#EF4444",
2422
+ ImageComponent
2423
+ }) {
2424
+ const t = useDubsTheme();
2425
+ const opponents = game.opponents || [];
2426
+ const bettors = game.bettors || [];
2427
+ const totalPool = game.totalPool || 0;
2428
+ const homePool = game.homePool || 0;
2429
+ const awayPool = game.awayPool || 0;
2430
+ const { homeOdds, awayOdds, homeBets, awayBets } = useMemo4(() => ({
2431
+ homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
2432
+ awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014",
2433
+ homeBets: bettors.filter((b) => b.team === "home").length,
2434
+ awayBets: bettors.filter((b) => b.team === "away").length
2435
+ }), [totalPool, homePool, awayPool, bettors]);
2436
+ const homeName = shortName ? shortName(opponents[0]?.name) : opponents[0]?.name || "Home";
2437
+ const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
2438
+ return /* @__PURE__ */ jsxs7(View7, { style: [styles6.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
2439
+ /* @__PURE__ */ jsx9(Text7, { style: [styles6.title, { color: t.text }], children: "Pick Your Winner" }),
2440
+ /* @__PURE__ */ jsxs7(View7, { style: styles6.row, children: [
2441
+ /* @__PURE__ */ jsx9(
2442
+ TeamOption,
2443
+ {
2444
+ name: homeName,
2445
+ imageUrl: opponents[0]?.imageUrl,
2446
+ odds: homeOdds,
2447
+ bets: homeBets,
2448
+ color: homeColor,
2449
+ selected: selectedTeam === "home",
2450
+ onPress: () => onSelect("home"),
2451
+ ImageComponent,
2452
+ t
2453
+ }
2454
+ ),
2455
+ /* @__PURE__ */ jsx9(
2456
+ TeamOption,
2457
+ {
2458
+ name: awayName,
2459
+ imageUrl: opponents[1]?.imageUrl,
2460
+ odds: awayOdds,
2461
+ bets: awayBets,
2462
+ color: awayColor,
2463
+ selected: selectedTeam === "away",
2464
+ onPress: () => onSelect("away"),
2465
+ ImageComponent,
2466
+ t
2467
+ }
2468
+ )
2469
+ ] })
2470
+ ] });
2471
+ }
2472
+ function TeamOption({
2473
+ name,
2474
+ imageUrl,
2475
+ odds,
2476
+ bets,
2477
+ color,
2478
+ selected,
2479
+ onPress,
2480
+ ImageComponent,
2481
+ t
2482
+ }) {
2483
+ const [imgFailed, setImgFailed] = useState13(false);
2484
+ const Img = ImageComponent || __require("react-native").Image;
2485
+ const showImage = imageUrl && !imgFailed;
2486
+ return /* @__PURE__ */ jsxs7(
2487
+ TouchableOpacity4,
2488
+ {
2489
+ style: [styles6.option, { borderColor: selected ? color : t.border, backgroundColor: selected ? color + "15" : t.background }],
2490
+ onPress,
2491
+ activeOpacity: 0.7,
2492
+ children: [
2493
+ showImage ? /* @__PURE__ */ jsx9(Img, { source: { uri: imageUrl }, style: styles6.logo, resizeMode: "contain", onError: () => setImgFailed(true) }) : /* @__PURE__ */ jsx9(View7, { style: [styles6.logo, styles6.logoPlaceholder] }),
2494
+ /* @__PURE__ */ jsx9(Text7, { style: [styles6.name, { color: t.text }], numberOfLines: 1, children: name }),
2495
+ /* @__PURE__ */ jsxs7(Text7, { style: [styles6.odds, { color }], children: [
2496
+ odds,
2497
+ "x"
2498
+ ] }),
2499
+ /* @__PURE__ */ jsxs7(Text7, { style: [styles6.bets, { color: t.textMuted }], children: [
2500
+ bets,
2501
+ " ",
2502
+ bets === 1 ? "bet" : "bets"
2503
+ ] }),
2504
+ selected && /* @__PURE__ */ jsx9(View7, { style: [styles6.badge, { backgroundColor: color }], children: /* @__PURE__ */ jsx9(Text7, { style: styles6.badgeText, children: "Selected" }) })
2505
+ ]
2506
+ }
2507
+ );
2508
+ }
2509
+ var styles6 = StyleSheet7.create({
2510
+ card: { borderRadius: 16, borderWidth: 1, padding: 16 },
2511
+ title: { fontSize: 17, fontWeight: "700", marginBottom: 12 },
2512
+ row: { flexDirection: "row", gap: 12 },
2513
+ option: { flex: 1, borderWidth: 2, borderRadius: 16, padding: 16, alignItems: "center", gap: 8 },
2514
+ logo: { width: 48, height: 48, borderRadius: 24 },
2515
+ logoPlaceholder: { backgroundColor: "rgba(128,128,128,0.2)" },
2516
+ name: { fontSize: 15, fontWeight: "700" },
2517
+ odds: { fontSize: 20, fontWeight: "800" },
2518
+ bets: { fontSize: 12 },
2519
+ badge: { borderRadius: 8, paddingHorizontal: 12, paddingVertical: 4, marginTop: 4 },
2520
+ badgeText: { color: "#FFF", fontSize: 12, fontWeight: "700" }
2521
+ });
2522
+
2523
+ // src/ui/game/PlayersCard.tsx
2524
+ import { useState as useState14 } from "react";
2525
+ import { StyleSheet as StyleSheet8, View as View8, Text as Text8 } from "react-native";
2526
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2527
+ function truncateWallet(addr, chars) {
2528
+ if (addr.length <= chars * 2 + 3) return addr;
2529
+ return `${addr.slice(0, chars)}...${addr.slice(-chars)}`;
2530
+ }
2531
+ function PlayersCard({
2532
+ game,
2533
+ truncateChars = 4,
2534
+ homeColor = "#3B82F6",
2535
+ awayColor = "#EF4444",
2536
+ drawColor = "#A855F7",
2537
+ ImageComponent
2538
+ }) {
2539
+ const t = useDubsTheme();
2540
+ const bettors = game.bettors || [];
2541
+ const dotColor = (team) => {
2542
+ if (team === "home") return homeColor;
2543
+ if (team === "away") return awayColor;
2544
+ return drawColor;
2545
+ };
2546
+ return /* @__PURE__ */ jsxs8(View8, { style: [styles7.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
2547
+ /* @__PURE__ */ jsxs8(Text8, { style: [styles7.title, { color: t.text }], children: [
2548
+ "Players",
2549
+ bettors.length > 0 ? ` (${bettors.length})` : ""
2550
+ ] }),
2551
+ bettors.length === 0 ? /* @__PURE__ */ jsx10(Text8, { style: [styles7.empty, { color: t.textMuted }], children: "No players yet \u2014 be the first!" }) : bettors.map((b, i) => /* @__PURE__ */ jsx10(
2552
+ BettorRow,
2553
+ {
2554
+ bettor: b,
2555
+ dotColor: dotColor(b.team),
2556
+ truncateChars,
2557
+ isFirst: i === 0,
2558
+ ImageComponent,
2559
+ t
2560
+ },
2561
+ `${b.wallet}-${i}`
2562
+ ))
2563
+ ] });
2564
+ }
2565
+ function BettorRow({
2566
+ bettor,
2567
+ dotColor,
2568
+ truncateChars,
2569
+ isFirst,
2570
+ ImageComponent,
2571
+ t
2572
+ }) {
2573
+ const [imgFailed, setImgFailed] = useState14(false);
2574
+ const Img = ImageComponent || __require("react-native").Image;
2575
+ const showAvatar = bettor.avatar && !imgFailed;
2576
+ return /* @__PURE__ */ jsxs8(View8, { style: [styles7.row, !isFirst && { borderTopColor: t.border, borderTopWidth: 1 }], children: [
2577
+ /* @__PURE__ */ jsx10(View8, { style: [styles7.dot, { backgroundColor: dotColor }] }),
2578
+ showAvatar ? /* @__PURE__ */ jsx10(Img, { source: { uri: bettor.avatar }, style: styles7.avatar, resizeMode: "cover", onError: () => setImgFailed(true) }) : /* @__PURE__ */ jsx10(View8, { style: [styles7.avatar, styles7.avatarPlaceholder] }),
2579
+ /* @__PURE__ */ jsx10(View8, { style: styles7.nameCol, children: /* @__PURE__ */ jsx10(Text8, { style: [styles7.username, { color: t.text }], numberOfLines: 1, children: bettor.username || truncateWallet(bettor.wallet, truncateChars) }) }),
2580
+ /* @__PURE__ */ jsxs8(Text8, { style: [styles7.amount, { color: t.textSecondary }], children: [
2581
+ bettor.amount,
2582
+ " SOL"
2583
+ ] })
2584
+ ] });
2585
+ }
2586
+ var styles7 = StyleSheet8.create({
2587
+ card: { borderRadius: 16, borderWidth: 1, padding: 16 },
2588
+ title: { fontSize: 17, fontWeight: "700", marginBottom: 12 },
2589
+ empty: { fontSize: 14, textAlign: "center", paddingVertical: 16 },
2590
+ row: { flexDirection: "row", alignItems: "center", paddingVertical: 10, gap: 10 },
2591
+ dot: { width: 8, height: 8, borderRadius: 4 },
2592
+ avatar: { width: 28, height: 28, borderRadius: 14 },
2593
+ avatarPlaceholder: { backgroundColor: "rgba(128,128,128,0.2)" },
2594
+ nameCol: { flex: 1 },
2595
+ username: { fontSize: 14, fontWeight: "600" },
2596
+ amount: { fontSize: 13, fontWeight: "700" }
2597
+ });
2598
+
2599
+ // src/ui/game/JoinGameButton.tsx
2600
+ import { useMemo as useMemo5 } from "react";
2601
+ import { StyleSheet as StyleSheet9, View as View9, Text as Text9, TouchableOpacity as TouchableOpacity5, ActivityIndicator as ActivityIndicator4 } from "react-native";
2602
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2603
+ var STATUS_LABELS = {
2604
+ building: "Building transaction...",
2605
+ signing: "Approve in wallet...",
2606
+ confirming: "Confirming on-chain...",
2607
+ saving: "Saving..."
2608
+ };
2609
+ function JoinGameButton({ game, walletAddress, selectedTeam, status, onJoin }) {
2610
+ const t = useDubsTheme();
2611
+ const alreadyJoined = useMemo5(() => {
2612
+ if (!walletAddress) return false;
2613
+ return (game.bettors || []).some((b) => b.wallet === walletAddress);
2614
+ }, [game.bettors, walletAddress]);
2615
+ if (alreadyJoined || game.isLocked || game.isResolved) return null;
2616
+ const isJoining = status !== "idle" && status !== "success" && status !== "error";
2617
+ const statusLabel = STATUS_LABELS[status] || "";
2618
+ return /* @__PURE__ */ jsxs9(View9, { style: [styles8.bar, { backgroundColor: t.background, borderTopColor: t.border }], children: [
2619
+ /* @__PURE__ */ jsxs9(View9, { style: styles8.buyInRow, children: [
2620
+ /* @__PURE__ */ jsx11(Text9, { style: [styles8.buyInLabel, { color: t.textMuted }], children: "Buy-in" }),
2621
+ /* @__PURE__ */ jsxs9(Text9, { style: [styles8.buyInValue, { color: t.text }], children: [
2622
+ game.buyIn,
2623
+ " SOL"
2624
+ ] })
2625
+ ] }),
2626
+ /* @__PURE__ */ jsx11(
2627
+ TouchableOpacity5,
2628
+ {
2629
+ style: [styles8.button, { backgroundColor: selectedTeam ? "#22D3EE" : t.border }],
2630
+ disabled: !selectedTeam || isJoining,
2631
+ onPress: onJoin,
2632
+ activeOpacity: 0.8,
2633
+ children: isJoining ? /* @__PURE__ */ jsxs9(View9, { style: styles8.joiningRow, children: [
2634
+ /* @__PURE__ */ jsx11(ActivityIndicator4, { size: "small", color: "#000" }),
2635
+ /* @__PURE__ */ jsx11(Text9, { style: styles8.buttonText, children: statusLabel })
2636
+ ] }) : /* @__PURE__ */ jsx11(Text9, { style: [styles8.buttonText, !selectedTeam && { color: t.textMuted }], children: selectedTeam ? `Join Bet \u2014 ${game.buyIn} SOL` : "Pick a team to bet" })
2637
+ }
2638
+ )
2639
+ ] });
2640
+ }
2641
+ var styles8 = StyleSheet9.create({
2642
+ bar: { position: "absolute", bottom: 0, left: 0, right: 0, paddingHorizontal: 16, paddingTop: 12, paddingBottom: 36, borderTopWidth: 1 },
2643
+ buyInRow: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", marginBottom: 10 },
2644
+ buyInLabel: { fontSize: 13 },
2645
+ buyInValue: { fontSize: 15, fontWeight: "800" },
2646
+ button: { borderRadius: 14, paddingVertical: 16, alignItems: "center" },
2647
+ buttonText: { color: "#000", fontSize: 16, fontWeight: "800" },
2648
+ joiningRow: { flexDirection: "row", alignItems: "center", gap: 10 }
2649
+ });
1803
2650
  export {
1804
2651
  AuthGate,
1805
2652
  ConnectWalletScreen,
@@ -1808,12 +2655,20 @@ export {
1808
2655
  DubsApiError,
1809
2656
  DubsClient,
1810
2657
  DubsProvider,
2658
+ GamePoster,
2659
+ JoinGameButton,
2660
+ LivePoolsCard,
1811
2661
  MwaWalletAdapter,
2662
+ NETWORK_CONFIG,
2663
+ PickWinnerCard,
2664
+ PlayersCard,
1812
2665
  SOLANA_PROGRAM_ERRORS,
2666
+ STORAGE_KEYS,
1813
2667
  SettingsSheet,
1814
2668
  UserProfileCard,
2669
+ createSecureStoreStorage,
2670
+ mergeTheme,
1815
2671
  parseSolanaError,
1816
- pollTransactionConfirmation,
1817
2672
  signAndSendBase64Transaction,
1818
2673
  useAuth,
1819
2674
  useClaim,