@dubsdotapp/expo 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -19
- package/dist/index.d.mts +189 -46
- package/dist/index.d.ts +189 -46
- package/dist/index.js +1206 -402
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1238 -434
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -2
- package/src/auth-context.ts +9 -0
- package/src/client.ts +21 -1
- package/src/constants.ts +15 -0
- package/src/hooks/useAuth.ts +13 -2
- package/src/hooks/useClaim.ts +11 -9
- package/src/hooks/useCreateGame.ts +15 -12
- package/src/hooks/useJoinGame.ts +18 -14
- package/src/index.ts +20 -2
- package/src/managed-wallet.tsx +148 -0
- package/src/provider.tsx +228 -9
- package/src/storage.ts +57 -0
- package/src/types.ts +38 -4
- package/src/ui/AuthGate.tsx +4 -1
- package/src/ui/game/GamePoster.tsx +182 -0
- package/src/ui/game/JoinGameButton.tsx +73 -0
- package/src/ui/game/LivePoolsCard.tsx +88 -0
- package/src/ui/game/PickWinnerCard.tsx +126 -0
- package/src/ui/game/PlayersCard.tsx +108 -0
- package/src/ui/game/index.ts +10 -0
- package/src/ui/index.ts +10 -0
- package/src/utils/transaction.ts +8 -49
- package/src/wallet/mwa-adapter.ts +9 -6
- package/src/wallet/types.ts +6 -0
package/dist/index.js
CHANGED
|
@@ -37,12 +37,19 @@ __export(index_exports, {
|
|
|
37
37
|
DubsApiError: () => DubsApiError,
|
|
38
38
|
DubsClient: () => DubsClient,
|
|
39
39
|
DubsProvider: () => DubsProvider,
|
|
40
|
+
GamePoster: () => GamePoster,
|
|
41
|
+
JoinGameButton: () => JoinGameButton,
|
|
42
|
+
LivePoolsCard: () => LivePoolsCard,
|
|
40
43
|
MwaWalletAdapter: () => MwaWalletAdapter,
|
|
44
|
+
NETWORK_CONFIG: () => NETWORK_CONFIG,
|
|
45
|
+
PickWinnerCard: () => PickWinnerCard,
|
|
46
|
+
PlayersCard: () => PlayersCard,
|
|
41
47
|
SOLANA_PROGRAM_ERRORS: () => SOLANA_PROGRAM_ERRORS,
|
|
48
|
+
STORAGE_KEYS: () => STORAGE_KEYS,
|
|
42
49
|
SettingsSheet: () => SettingsSheet,
|
|
43
50
|
UserProfileCard: () => UserProfileCard,
|
|
51
|
+
createSecureStoreStorage: () => createSecureStoreStorage,
|
|
44
52
|
parseSolanaError: () => parseSolanaError,
|
|
45
|
-
pollTransactionConfirmation: () => pollTransactionConfirmation,
|
|
46
53
|
signAndSendBase64Transaction: () => signAndSendBase64Transaction,
|
|
47
54
|
useAuth: () => useAuth,
|
|
48
55
|
useClaim: () => useClaim,
|
|
@@ -60,6 +67,18 @@ module.exports = __toCommonJS(index_exports);
|
|
|
60
67
|
// src/constants.ts
|
|
61
68
|
var DEFAULT_BASE_URL = "https://dubs-server-prod-9c91d3f01199.herokuapp.com/api/developer/v1";
|
|
62
69
|
var DEFAULT_RPC_URL = "https://api.mainnet-beta.solana.com";
|
|
70
|
+
var NETWORK_CONFIG = {
|
|
71
|
+
"mainnet-beta": {
|
|
72
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
73
|
+
rpcUrl: DEFAULT_RPC_URL,
|
|
74
|
+
cluster: "mainnet-beta"
|
|
75
|
+
},
|
|
76
|
+
devnet: {
|
|
77
|
+
baseUrl: "https://dubs-server-dev-55d1fba09a97.herokuapp.com/api/developer/v1",
|
|
78
|
+
rpcUrl: "https://api.devnet.solana.com",
|
|
79
|
+
cluster: "devnet"
|
|
80
|
+
}
|
|
81
|
+
};
|
|
63
82
|
|
|
64
83
|
// src/errors.ts
|
|
65
84
|
var DubsApiError = class extends Error {
|
|
@@ -193,12 +212,20 @@ var DubsClient = class {
|
|
|
193
212
|
if (this._token) {
|
|
194
213
|
headers["Authorization"] = `Bearer ${this._token}`;
|
|
195
214
|
}
|
|
215
|
+
console.log(`[DubsClient] ${method} ${url}`, body ? JSON.stringify(body).slice(0, 200) : "");
|
|
196
216
|
const res = await fetch(url, {
|
|
197
217
|
method,
|
|
198
218
|
headers,
|
|
199
219
|
body: body ? JSON.stringify(body) : void 0
|
|
200
220
|
});
|
|
201
|
-
const
|
|
221
|
+
const text = await res.text();
|
|
222
|
+
console.log(`[DubsClient] ${method} ${path} \u2192 ${res.status}`, text.slice(0, 300));
|
|
223
|
+
let json;
|
|
224
|
+
try {
|
|
225
|
+
json = JSON.parse(text);
|
|
226
|
+
} catch {
|
|
227
|
+
throw new DubsApiError("parse_error", `Invalid JSON response: ${text.slice(0, 100)}`, res.status);
|
|
228
|
+
}
|
|
202
229
|
if (!json.success) {
|
|
203
230
|
const err = json.error;
|
|
204
231
|
if (typeof err === "object" && err !== null) {
|
|
@@ -318,6 +345,13 @@ var DubsClient = class {
|
|
|
318
345
|
);
|
|
319
346
|
return res.game;
|
|
320
347
|
}
|
|
348
|
+
async getLiveScore(gameId) {
|
|
349
|
+
const res = await this.request(
|
|
350
|
+
"GET",
|
|
351
|
+
`/games/${encodeURIComponent(gameId)}/live-score`
|
|
352
|
+
);
|
|
353
|
+
return res.liveScore;
|
|
354
|
+
}
|
|
321
355
|
async getGames(params) {
|
|
322
356
|
const qs = new URLSearchParams();
|
|
323
357
|
if (params?.wallet) qs.set("wallet", params.wallet);
|
|
@@ -335,6 +369,7 @@ var DubsClient = class {
|
|
|
335
369
|
async getNetworkGames(params) {
|
|
336
370
|
const qs = new URLSearchParams();
|
|
337
371
|
if (params?.league) qs.set("league", params.league);
|
|
372
|
+
if (params?.exclude_wallet) qs.set("exclude_wallet", params.exclude_wallet);
|
|
338
373
|
if (params?.limit != null) qs.set("limit", String(params.limit));
|
|
339
374
|
if (params?.offset != null) qs.set("offset", String(params.offset));
|
|
340
375
|
const query = qs.toString();
|
|
@@ -443,35 +478,56 @@ var DubsClient = class {
|
|
|
443
478
|
}
|
|
444
479
|
};
|
|
445
480
|
|
|
446
|
-
// src/
|
|
447
|
-
var
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
function
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
481
|
+
// src/storage.ts
|
|
482
|
+
var STORAGE_KEYS = {
|
|
483
|
+
MWA_AUTH_TOKEN: "dubs_mwa_auth_token",
|
|
484
|
+
JWT_TOKEN: "dubs_jwt_token"
|
|
485
|
+
};
|
|
486
|
+
function createSecureStoreStorage() {
|
|
487
|
+
let SecureStore = null;
|
|
488
|
+
function getStore() {
|
|
489
|
+
if (!SecureStore) {
|
|
490
|
+
try {
|
|
491
|
+
SecureStore = require("expo-secure-store");
|
|
492
|
+
} catch {
|
|
493
|
+
throw new Error(
|
|
494
|
+
"@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>."
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return SecureStore;
|
|
463
499
|
}
|
|
464
|
-
return
|
|
500
|
+
return {
|
|
501
|
+
async getItem(key) {
|
|
502
|
+
const store = getStore();
|
|
503
|
+
return store.getItemAsync(key);
|
|
504
|
+
},
|
|
505
|
+
async setItem(key, value) {
|
|
506
|
+
const store = getStore();
|
|
507
|
+
await store.setItemAsync(key, value);
|
|
508
|
+
},
|
|
509
|
+
async deleteItem(key) {
|
|
510
|
+
const store = getStore();
|
|
511
|
+
await store.deleteItemAsync(key);
|
|
512
|
+
}
|
|
513
|
+
};
|
|
465
514
|
}
|
|
466
515
|
|
|
516
|
+
// src/provider.tsx
|
|
517
|
+
var import_react12 = require("react");
|
|
518
|
+
var import_web33 = require("@solana/web3.js");
|
|
519
|
+
|
|
520
|
+
// src/managed-wallet.tsx
|
|
521
|
+
var import_react = require("react");
|
|
522
|
+
|
|
467
523
|
// src/wallet/mwa-adapter.ts
|
|
468
|
-
var
|
|
524
|
+
var import_web3 = require("@solana/web3.js");
|
|
469
525
|
function toPublicKey(address) {
|
|
470
526
|
if (address instanceof Uint8Array) {
|
|
471
|
-
return new
|
|
527
|
+
return new import_web3.PublicKey(address);
|
|
472
528
|
}
|
|
473
529
|
const bytes = Uint8Array.from(atob(address), (c) => c.charCodeAt(0));
|
|
474
|
-
return new
|
|
530
|
+
return new import_web3.PublicKey(bytes);
|
|
475
531
|
}
|
|
476
532
|
var MwaWalletAdapter = class {
|
|
477
533
|
constructor(config) {
|
|
@@ -487,6 +543,12 @@ var MwaWalletAdapter = class {
|
|
|
487
543
|
get connected() {
|
|
488
544
|
return this._connected;
|
|
489
545
|
}
|
|
546
|
+
get authToken() {
|
|
547
|
+
return this._authToken;
|
|
548
|
+
}
|
|
549
|
+
setAuthToken(token) {
|
|
550
|
+
this._authToken = token;
|
|
551
|
+
}
|
|
490
552
|
/**
|
|
491
553
|
* Connect to a mobile wallet. Call this before any signing.
|
|
492
554
|
*/
|
|
@@ -550,17 +612,274 @@ var MwaWalletAdapter = class {
|
|
|
550
612
|
return result[0];
|
|
551
613
|
});
|
|
552
614
|
if (signature instanceof Uint8Array) {
|
|
553
|
-
|
|
554
|
-
return new import_web32.PublicKey(signature).toBase58();
|
|
555
|
-
}).catch(() => {
|
|
556
|
-
return Buffer.from(signature).toString("base64");
|
|
557
|
-
});
|
|
558
|
-
return bs582;
|
|
615
|
+
return new import_web3.PublicKey(signature).toBase58();
|
|
559
616
|
}
|
|
560
617
|
return String(signature);
|
|
561
618
|
}
|
|
562
619
|
};
|
|
563
620
|
|
|
621
|
+
// src/ui/ConnectWalletScreen.tsx
|
|
622
|
+
var import_react_native2 = require("react-native");
|
|
623
|
+
|
|
624
|
+
// src/ui/theme.ts
|
|
625
|
+
var import_react_native = require("react-native");
|
|
626
|
+
var dark = {
|
|
627
|
+
background: "#08080D",
|
|
628
|
+
surface: "#111118",
|
|
629
|
+
surfaceActive: "#7C3AED",
|
|
630
|
+
border: "#1A1A24",
|
|
631
|
+
text: "#FFFFFF",
|
|
632
|
+
textSecondary: "#E0E0EE",
|
|
633
|
+
textMuted: "#666666",
|
|
634
|
+
textDim: "#555555",
|
|
635
|
+
accent: "#7C3AED",
|
|
636
|
+
success: "#22C55E",
|
|
637
|
+
live: "#EF4444",
|
|
638
|
+
errorText: "#F87171",
|
|
639
|
+
errorBg: "#1A0A0A",
|
|
640
|
+
errorBorder: "#3A1515"
|
|
641
|
+
};
|
|
642
|
+
var light = {
|
|
643
|
+
background: "#FFFFFF",
|
|
644
|
+
surface: "#F0F0F5",
|
|
645
|
+
surfaceActive: "#7C3AED",
|
|
646
|
+
border: "#E0E0E8",
|
|
647
|
+
text: "#111118",
|
|
648
|
+
textSecondary: "#333333",
|
|
649
|
+
textMuted: "#888888",
|
|
650
|
+
textDim: "#999999",
|
|
651
|
+
accent: "#7C3AED",
|
|
652
|
+
success: "#16A34A",
|
|
653
|
+
live: "#DC2626",
|
|
654
|
+
errorText: "#DC2626",
|
|
655
|
+
errorBg: "#FEF2F2",
|
|
656
|
+
errorBorder: "#FECACA"
|
|
657
|
+
};
|
|
658
|
+
function useDubsTheme() {
|
|
659
|
+
const scheme = (0, import_react_native.useColorScheme)();
|
|
660
|
+
return scheme === "light" ? light : dark;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/ui/ConnectWalletScreen.tsx
|
|
664
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
665
|
+
function ConnectWalletScreen({
|
|
666
|
+
onConnect,
|
|
667
|
+
connecting = false,
|
|
668
|
+
error = null,
|
|
669
|
+
appName = "Dubs"
|
|
670
|
+
}) {
|
|
671
|
+
const t = useDubsTheme();
|
|
672
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.container, { backgroundColor: t.background }], children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.content, children: [
|
|
673
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.brandingSection, children: [
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.logoText, children: "D" }) }),
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.appName, { color: t.text }], children: appName }),
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.subtitle, { color: t.textMuted }], children: "Connect your Solana wallet to get started" })
|
|
677
|
+
] }),
|
|
678
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.actionSection, children: [
|
|
679
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
680
|
+
import_react_native2.View,
|
|
681
|
+
{
|
|
682
|
+
style: [
|
|
683
|
+
styles.errorBox,
|
|
684
|
+
{ backgroundColor: t.errorBg, borderColor: t.errorBorder }
|
|
685
|
+
],
|
|
686
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.errorText, { color: t.errorText }], children: error })
|
|
687
|
+
}
|
|
688
|
+
) : null,
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
690
|
+
import_react_native2.TouchableOpacity,
|
|
691
|
+
{
|
|
692
|
+
style: [styles.connectButton, { backgroundColor: t.accent }],
|
|
693
|
+
onPress: onConnect,
|
|
694
|
+
disabled: connecting,
|
|
695
|
+
activeOpacity: 0.8,
|
|
696
|
+
children: connecting ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.ActivityIndicator, { color: "#FFFFFF", size: "small" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.connectButtonText, children: "Connect Wallet" })
|
|
697
|
+
}
|
|
698
|
+
),
|
|
699
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.hint, { color: t.textDim }], children: "Phantom, Solflare, or any Solana wallet" })
|
|
700
|
+
] })
|
|
701
|
+
] }) });
|
|
702
|
+
}
|
|
703
|
+
var styles = import_react_native2.StyleSheet.create({
|
|
704
|
+
container: {
|
|
705
|
+
flex: 1,
|
|
706
|
+
justifyContent: "center"
|
|
707
|
+
},
|
|
708
|
+
content: {
|
|
709
|
+
flex: 1,
|
|
710
|
+
justifyContent: "space-between",
|
|
711
|
+
paddingHorizontal: 32,
|
|
712
|
+
paddingTop: 120,
|
|
713
|
+
paddingBottom: 80
|
|
714
|
+
},
|
|
715
|
+
brandingSection: {
|
|
716
|
+
alignItems: "center",
|
|
717
|
+
gap: 12
|
|
718
|
+
},
|
|
719
|
+
logoCircle: {
|
|
720
|
+
width: 80,
|
|
721
|
+
height: 80,
|
|
722
|
+
borderRadius: 40,
|
|
723
|
+
justifyContent: "center",
|
|
724
|
+
alignItems: "center",
|
|
725
|
+
marginBottom: 8
|
|
726
|
+
},
|
|
727
|
+
logoText: {
|
|
728
|
+
fontSize: 36,
|
|
729
|
+
fontWeight: "800",
|
|
730
|
+
color: "#FFFFFF"
|
|
731
|
+
},
|
|
732
|
+
appName: {
|
|
733
|
+
fontSize: 32,
|
|
734
|
+
fontWeight: "800"
|
|
735
|
+
},
|
|
736
|
+
subtitle: {
|
|
737
|
+
fontSize: 16,
|
|
738
|
+
textAlign: "center",
|
|
739
|
+
lineHeight: 22
|
|
740
|
+
},
|
|
741
|
+
actionSection: {
|
|
742
|
+
gap: 16
|
|
743
|
+
},
|
|
744
|
+
errorBox: {
|
|
745
|
+
borderWidth: 1,
|
|
746
|
+
borderRadius: 12,
|
|
747
|
+
paddingHorizontal: 16,
|
|
748
|
+
paddingVertical: 12
|
|
749
|
+
},
|
|
750
|
+
errorText: {
|
|
751
|
+
fontSize: 14,
|
|
752
|
+
textAlign: "center"
|
|
753
|
+
},
|
|
754
|
+
connectButton: {
|
|
755
|
+
height: 56,
|
|
756
|
+
borderRadius: 16,
|
|
757
|
+
justifyContent: "center",
|
|
758
|
+
alignItems: "center"
|
|
759
|
+
},
|
|
760
|
+
connectButtonText: {
|
|
761
|
+
color: "#FFFFFF",
|
|
762
|
+
fontSize: 18,
|
|
763
|
+
fontWeight: "700"
|
|
764
|
+
},
|
|
765
|
+
hint: {
|
|
766
|
+
fontSize: 13,
|
|
767
|
+
textAlign: "center"
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// src/managed-wallet.tsx
|
|
772
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
773
|
+
var DisconnectContext = (0, import_react.createContext)(null);
|
|
774
|
+
function useDisconnect() {
|
|
775
|
+
return (0, import_react.useContext)(DisconnectContext);
|
|
776
|
+
}
|
|
777
|
+
function ManagedWalletProvider({
|
|
778
|
+
appName,
|
|
779
|
+
cluster,
|
|
780
|
+
storage,
|
|
781
|
+
renderConnectScreen,
|
|
782
|
+
children
|
|
783
|
+
}) {
|
|
784
|
+
const [connected, setConnected] = (0, import_react.useState)(false);
|
|
785
|
+
const [connecting, setConnecting] = (0, import_react.useState)(false);
|
|
786
|
+
const [isReady, setIsReady] = (0, import_react.useState)(false);
|
|
787
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
788
|
+
const adapterRef = (0, import_react.useRef)(null);
|
|
789
|
+
const transactRef = (0, import_react.useRef)(null);
|
|
790
|
+
if (!adapterRef.current) {
|
|
791
|
+
adapterRef.current = new MwaWalletAdapter({
|
|
792
|
+
transact: (...args) => {
|
|
793
|
+
if (!transactRef.current) {
|
|
794
|
+
throw new Error(
|
|
795
|
+
"@dubsdotapp/expo: @solana-mobile/mobile-wallet-adapter-protocol-web3js is required. Install it with: npm install @solana-mobile/mobile-wallet-adapter-protocol-web3js"
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
return transactRef.current(...args);
|
|
799
|
+
},
|
|
800
|
+
appIdentity: { name: appName },
|
|
801
|
+
cluster,
|
|
802
|
+
onAuthTokenChange: (token) => {
|
|
803
|
+
if (token) {
|
|
804
|
+
storage.setItem(STORAGE_KEYS.MWA_AUTH_TOKEN, token).catch(() => {
|
|
805
|
+
});
|
|
806
|
+
} else {
|
|
807
|
+
storage.deleteItem(STORAGE_KEYS.MWA_AUTH_TOKEN).catch(() => {
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
const adapter = adapterRef.current;
|
|
814
|
+
(0, import_react.useEffect)(() => {
|
|
815
|
+
let cancelled = false;
|
|
816
|
+
(async () => {
|
|
817
|
+
try {
|
|
818
|
+
const mwa = await import("@solana-mobile/mobile-wallet-adapter-protocol-web3js");
|
|
819
|
+
if (cancelled) return;
|
|
820
|
+
transactRef.current = mwa.transact;
|
|
821
|
+
} catch {
|
|
822
|
+
}
|
|
823
|
+
try {
|
|
824
|
+
const savedToken = await storage.getItem(STORAGE_KEYS.MWA_AUTH_TOKEN);
|
|
825
|
+
if (savedToken && !cancelled) {
|
|
826
|
+
adapter.setAuthToken(savedToken);
|
|
827
|
+
await adapter.connect();
|
|
828
|
+
if (!cancelled) setConnected(true);
|
|
829
|
+
}
|
|
830
|
+
} catch {
|
|
831
|
+
} finally {
|
|
832
|
+
if (!cancelled) setIsReady(true);
|
|
833
|
+
}
|
|
834
|
+
})();
|
|
835
|
+
return () => {
|
|
836
|
+
cancelled = true;
|
|
837
|
+
};
|
|
838
|
+
}, [adapter, storage]);
|
|
839
|
+
const handleConnect = (0, import_react.useCallback)(async () => {
|
|
840
|
+
setConnecting(true);
|
|
841
|
+
setError(null);
|
|
842
|
+
try {
|
|
843
|
+
await adapter.connect();
|
|
844
|
+
setConnected(true);
|
|
845
|
+
} catch (err) {
|
|
846
|
+
const message = err instanceof Error ? err.message : "Connection failed";
|
|
847
|
+
setError(message);
|
|
848
|
+
} finally {
|
|
849
|
+
setConnecting(false);
|
|
850
|
+
}
|
|
851
|
+
}, [adapter]);
|
|
852
|
+
const disconnect = (0, import_react.useCallback)(async () => {
|
|
853
|
+
adapter.disconnect();
|
|
854
|
+
await storage.deleteItem(STORAGE_KEYS.MWA_AUTH_TOKEN).catch(() => {
|
|
855
|
+
});
|
|
856
|
+
await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
|
|
857
|
+
});
|
|
858
|
+
setConnected(false);
|
|
859
|
+
}, [adapter, storage]);
|
|
860
|
+
if (!isReady) return null;
|
|
861
|
+
if (!connected) {
|
|
862
|
+
if (renderConnectScreen === false) {
|
|
863
|
+
return null;
|
|
864
|
+
}
|
|
865
|
+
const connectProps = {
|
|
866
|
+
onConnect: handleConnect,
|
|
867
|
+
connecting,
|
|
868
|
+
error,
|
|
869
|
+
appName
|
|
870
|
+
};
|
|
871
|
+
if (renderConnectScreen) {
|
|
872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: renderConnectScreen(connectProps) });
|
|
873
|
+
}
|
|
874
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ConnectWalletScreen, { ...connectProps });
|
|
875
|
+
}
|
|
876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DisconnectContext.Provider, { value: disconnect, children: children(adapter) });
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// src/ui/AuthGate.tsx
|
|
880
|
+
var import_react11 = __toESM(require("react"));
|
|
881
|
+
var import_react_native3 = require("react-native");
|
|
882
|
+
|
|
564
883
|
// src/hooks/useEvents.ts
|
|
565
884
|
var import_react2 = require("react");
|
|
566
885
|
function useEvents(params) {
|
|
@@ -669,44 +988,24 @@ function useNetworkGames(params) {
|
|
|
669
988
|
var import_react6 = require("react");
|
|
670
989
|
|
|
671
990
|
// src/utils/transaction.ts
|
|
672
|
-
var
|
|
673
|
-
async function signAndSendBase64Transaction(base64Tx, wallet
|
|
991
|
+
var import_web32 = require("@solana/web3.js");
|
|
992
|
+
async function signAndSendBase64Transaction(base64Tx, wallet) {
|
|
674
993
|
if (!wallet.publicKey) throw new Error("Wallet not connected");
|
|
675
|
-
const
|
|
676
|
-
const
|
|
994
|
+
const binaryStr = atob(base64Tx);
|
|
995
|
+
const bytes = new Uint8Array(binaryStr.length);
|
|
996
|
+
for (let i = 0; i < binaryStr.length; i++) {
|
|
997
|
+
bytes[i] = binaryStr.charCodeAt(i);
|
|
998
|
+
}
|
|
999
|
+
const transaction = import_web32.Transaction.from(bytes);
|
|
677
1000
|
if (wallet.signAndSendTransaction) {
|
|
678
1001
|
return wallet.signAndSendTransaction(transaction);
|
|
679
1002
|
}
|
|
680
|
-
|
|
681
|
-
const signature = await connection.sendRawTransaction(signed.serialize(), {
|
|
682
|
-
skipPreflight: true
|
|
683
|
-
});
|
|
684
|
-
return signature;
|
|
685
|
-
}
|
|
686
|
-
async function pollTransactionConfirmation(signature, connection, commitment = "confirmed", timeout = 6e4, interval = 1500) {
|
|
687
|
-
const start = Date.now();
|
|
688
|
-
const confirmationOrder = ["processed", "confirmed", "finalized"];
|
|
689
|
-
const targetIndex = confirmationOrder.indexOf(commitment);
|
|
690
|
-
while (Date.now() - start < timeout) {
|
|
691
|
-
const statuses = await connection.getSignatureStatuses([signature]);
|
|
692
|
-
const status = statuses?.value?.[0];
|
|
693
|
-
if (status?.err) {
|
|
694
|
-
throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`);
|
|
695
|
-
}
|
|
696
|
-
if (status?.confirmationStatus) {
|
|
697
|
-
const currentIndex = confirmationOrder.indexOf(status.confirmationStatus);
|
|
698
|
-
if (currentIndex >= targetIndex) {
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
703
|
-
}
|
|
704
|
-
throw new Error(`Transaction confirmation timeout after ${timeout}ms`);
|
|
1003
|
+
throw new Error("Wallet does not support signAndSendTransaction");
|
|
705
1004
|
}
|
|
706
1005
|
|
|
707
1006
|
// src/hooks/useCreateGame.ts
|
|
708
1007
|
function useCreateGame() {
|
|
709
|
-
const { client, wallet
|
|
1008
|
+
const { client, wallet } = useDubs();
|
|
710
1009
|
const [status, setStatus] = (0, import_react6.useState)("idle");
|
|
711
1010
|
const [error, setError] = (0, import_react6.useState)(null);
|
|
712
1011
|
const [data, setData] = (0, import_react6.useState)(null);
|
|
@@ -720,17 +1019,18 @@ function useCreateGame() {
|
|
|
720
1019
|
setError(null);
|
|
721
1020
|
setData(null);
|
|
722
1021
|
try {
|
|
1022
|
+
console.log("[useCreateGame] Step 1: Building transaction...");
|
|
723
1023
|
const createResult = await client.createGame(params);
|
|
1024
|
+
console.log("[useCreateGame] Step 1 done:", { gameId: createResult.gameId, gameAddress: createResult.gameAddress });
|
|
724
1025
|
setStatus("signing");
|
|
1026
|
+
console.log("[useCreateGame] Step 2: Signing and sending...");
|
|
725
1027
|
const signature = await signAndSendBase64Transaction(
|
|
726
1028
|
createResult.transaction,
|
|
727
|
-
wallet
|
|
728
|
-
connection
|
|
1029
|
+
wallet
|
|
729
1030
|
);
|
|
1031
|
+
console.log("[useCreateGame] Step 2 done. Signature:", signature);
|
|
730
1032
|
setStatus("confirming");
|
|
731
|
-
|
|
732
|
-
setStatus("saving");
|
|
733
|
-
const explorerUrl = `https://solscan.io/tx/${signature}`;
|
|
1033
|
+
console.log("[useCreateGame] Step 3: Confirming with backend...");
|
|
734
1034
|
await client.confirmGame({
|
|
735
1035
|
gameId: createResult.gameId,
|
|
736
1036
|
playerWallet: params.playerWallet,
|
|
@@ -740,6 +1040,8 @@ function useCreateGame() {
|
|
|
740
1040
|
role: "creator",
|
|
741
1041
|
gameAddress: createResult.gameAddress
|
|
742
1042
|
});
|
|
1043
|
+
console.log("[useCreateGame] Step 3 done.");
|
|
1044
|
+
const explorerUrl = `https://solscan.io/tx/${signature}`;
|
|
743
1045
|
const result = {
|
|
744
1046
|
gameId: createResult.gameId,
|
|
745
1047
|
gameAddress: createResult.gameAddress,
|
|
@@ -748,21 +1050,23 @@ function useCreateGame() {
|
|
|
748
1050
|
};
|
|
749
1051
|
setData(result);
|
|
750
1052
|
setStatus("success");
|
|
1053
|
+
console.log("[useCreateGame] Complete!");
|
|
751
1054
|
return result;
|
|
752
1055
|
} catch (err) {
|
|
1056
|
+
console.error("[useCreateGame] FAILED:", err);
|
|
753
1057
|
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
754
1058
|
setError(error2);
|
|
755
1059
|
setStatus("error");
|
|
756
1060
|
throw error2;
|
|
757
1061
|
}
|
|
758
|
-
}, [client, wallet
|
|
1062
|
+
}, [client, wallet]);
|
|
759
1063
|
return { execute, status, error, data, reset };
|
|
760
1064
|
}
|
|
761
1065
|
|
|
762
1066
|
// src/hooks/useJoinGame.ts
|
|
763
1067
|
var import_react7 = require("react");
|
|
764
1068
|
function useJoinGame() {
|
|
765
|
-
const { client, wallet
|
|
1069
|
+
const { client, wallet } = useDubs();
|
|
766
1070
|
const [status, setStatus] = (0, import_react7.useState)("idle");
|
|
767
1071
|
const [error, setError] = (0, import_react7.useState)(null);
|
|
768
1072
|
const [data, setData] = (0, import_react7.useState)(null);
|
|
@@ -776,18 +1080,18 @@ function useJoinGame() {
|
|
|
776
1080
|
setError(null);
|
|
777
1081
|
setData(null);
|
|
778
1082
|
try {
|
|
1083
|
+
console.log("[useJoinGame] Step 1: Building transaction...", { gameId: params.gameId, playerWallet: params.playerWallet, teamChoice: params.teamChoice, amount: params.amount });
|
|
779
1084
|
const joinResult = await client.joinGame(params);
|
|
1085
|
+
console.log("[useJoinGame] Step 1 done:", { gameId: joinResult.gameId, gameAddress: joinResult.gameAddress, hasTx: !!joinResult.transaction });
|
|
780
1086
|
setStatus("signing");
|
|
1087
|
+
console.log("[useJoinGame] Step 2: Signing and sending transaction...");
|
|
781
1088
|
const signature = await signAndSendBase64Transaction(
|
|
782
1089
|
joinResult.transaction,
|
|
783
|
-
wallet
|
|
784
|
-
connection
|
|
1090
|
+
wallet
|
|
785
1091
|
);
|
|
1092
|
+
console.log("[useJoinGame] Step 2 done. Signature:", signature);
|
|
786
1093
|
setStatus("confirming");
|
|
787
|
-
|
|
788
|
-
setStatus("saving");
|
|
789
|
-
const explorerUrl = `https://solscan.io/tx/${signature}`;
|
|
790
|
-
await client.confirmGame({
|
|
1094
|
+
const confirmParams = {
|
|
791
1095
|
gameId: params.gameId,
|
|
792
1096
|
playerWallet: params.playerWallet,
|
|
793
1097
|
signature,
|
|
@@ -795,7 +1099,11 @@ function useJoinGame() {
|
|
|
795
1099
|
wagerAmount: params.amount,
|
|
796
1100
|
role: "joiner",
|
|
797
1101
|
gameAddress: joinResult.gameAddress
|
|
798
|
-
}
|
|
1102
|
+
};
|
|
1103
|
+
console.log("[useJoinGame] Step 3: Confirming with backend...", confirmParams);
|
|
1104
|
+
await client.confirmGame(confirmParams);
|
|
1105
|
+
console.log("[useJoinGame] Step 3 done. Backend confirmed.");
|
|
1106
|
+
const explorerUrl = `https://solscan.io/tx/${signature}`;
|
|
799
1107
|
const result = {
|
|
800
1108
|
gameId: params.gameId,
|
|
801
1109
|
gameAddress: joinResult.gameAddress,
|
|
@@ -804,21 +1112,23 @@ function useJoinGame() {
|
|
|
804
1112
|
};
|
|
805
1113
|
setData(result);
|
|
806
1114
|
setStatus("success");
|
|
1115
|
+
console.log("[useJoinGame] Complete!");
|
|
807
1116
|
return result;
|
|
808
1117
|
} catch (err) {
|
|
1118
|
+
console.error("[useJoinGame] FAILED at status:", status, err);
|
|
809
1119
|
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
810
1120
|
setError(error2);
|
|
811
1121
|
setStatus("error");
|
|
812
1122
|
throw error2;
|
|
813
1123
|
}
|
|
814
|
-
}, [client, wallet
|
|
1124
|
+
}, [client, wallet]);
|
|
815
1125
|
return { execute, status, error, data, reset };
|
|
816
1126
|
}
|
|
817
1127
|
|
|
818
1128
|
// src/hooks/useClaim.ts
|
|
819
1129
|
var import_react8 = require("react");
|
|
820
1130
|
function useClaim() {
|
|
821
|
-
const { client, wallet
|
|
1131
|
+
const { client, wallet } = useDubs();
|
|
822
1132
|
const [status, setStatus] = (0, import_react8.useState)("idle");
|
|
823
1133
|
const [error, setError] = (0, import_react8.useState)(null);
|
|
824
1134
|
const [data, setData] = (0, import_react8.useState)(null);
|
|
@@ -832,15 +1142,16 @@ function useClaim() {
|
|
|
832
1142
|
setError(null);
|
|
833
1143
|
setData(null);
|
|
834
1144
|
try {
|
|
1145
|
+
console.log("[useClaim] Step 1: Building claim transaction...");
|
|
835
1146
|
const claimResult = await client.buildClaimTransaction(params);
|
|
1147
|
+
console.log("[useClaim] Step 1 done.");
|
|
836
1148
|
setStatus("signing");
|
|
1149
|
+
console.log("[useClaim] Step 2: Signing and sending...");
|
|
837
1150
|
const signature = await signAndSendBase64Transaction(
|
|
838
1151
|
claimResult.transaction,
|
|
839
|
-
wallet
|
|
840
|
-
connection
|
|
1152
|
+
wallet
|
|
841
1153
|
);
|
|
842
|
-
|
|
843
|
-
await pollTransactionConfirmation(signature, connection);
|
|
1154
|
+
console.log("[useClaim] Step 2 done. Signature:", signature);
|
|
844
1155
|
const explorerUrl = `https://solscan.io/tx/${signature}`;
|
|
845
1156
|
const result = {
|
|
846
1157
|
gameId: params.gameId,
|
|
@@ -849,28 +1160,37 @@ function useClaim() {
|
|
|
849
1160
|
};
|
|
850
1161
|
setData(result);
|
|
851
1162
|
setStatus("success");
|
|
1163
|
+
console.log("[useClaim] Complete!");
|
|
852
1164
|
return result;
|
|
853
1165
|
} catch (err) {
|
|
1166
|
+
console.error("[useClaim] FAILED:", err);
|
|
854
1167
|
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
855
1168
|
setError(error2);
|
|
856
1169
|
setStatus("error");
|
|
857
1170
|
throw error2;
|
|
858
1171
|
}
|
|
859
|
-
}, [client, wallet
|
|
1172
|
+
}, [client, wallet]);
|
|
860
1173
|
return { execute, status, error, data, reset };
|
|
861
1174
|
}
|
|
862
1175
|
|
|
863
1176
|
// src/hooks/useAuth.ts
|
|
864
|
-
var
|
|
1177
|
+
var import_react10 = require("react");
|
|
865
1178
|
var import_bs58 = __toESM(require("bs58"));
|
|
1179
|
+
|
|
1180
|
+
// src/auth-context.ts
|
|
1181
|
+
var import_react9 = require("react");
|
|
1182
|
+
var AuthContext = (0, import_react9.createContext)(null);
|
|
1183
|
+
|
|
1184
|
+
// src/hooks/useAuth.ts
|
|
866
1185
|
function useAuth() {
|
|
1186
|
+
const sharedAuth = (0, import_react10.useContext)(AuthContext);
|
|
867
1187
|
const { client, wallet } = useDubs();
|
|
868
|
-
const [status, setStatus] = (0,
|
|
869
|
-
const [user, setUser] = (0,
|
|
870
|
-
const [token, setToken] = (0,
|
|
871
|
-
const [error, setError] = (0,
|
|
872
|
-
const pendingAuth = (0,
|
|
873
|
-
const reset = (0,
|
|
1188
|
+
const [status, setStatus] = (0, import_react10.useState)("idle");
|
|
1189
|
+
const [user, setUser] = (0, import_react10.useState)(null);
|
|
1190
|
+
const [token, setToken] = (0, import_react10.useState)(null);
|
|
1191
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
1192
|
+
const pendingAuth = (0, import_react10.useRef)(null);
|
|
1193
|
+
const reset = (0, import_react10.useCallback)(() => {
|
|
874
1194
|
setStatus("idle");
|
|
875
1195
|
setUser(null);
|
|
876
1196
|
setToken(null);
|
|
@@ -878,7 +1198,7 @@ function useAuth() {
|
|
|
878
1198
|
pendingAuth.current = null;
|
|
879
1199
|
client.setToken(null);
|
|
880
1200
|
}, [client]);
|
|
881
|
-
const authenticate = (0,
|
|
1201
|
+
const authenticate = (0, import_react10.useCallback)(async () => {
|
|
882
1202
|
try {
|
|
883
1203
|
if (!wallet.publicKey) {
|
|
884
1204
|
throw new Error("Wallet not connected");
|
|
@@ -909,7 +1229,7 @@ function useAuth() {
|
|
|
909
1229
|
setStatus("error");
|
|
910
1230
|
}
|
|
911
1231
|
}, [client, wallet]);
|
|
912
|
-
const register = (0,
|
|
1232
|
+
const register = (0, import_react10.useCallback)(async (username, referralCode, avatarUrl) => {
|
|
913
1233
|
try {
|
|
914
1234
|
const pending = pendingAuth.current;
|
|
915
1235
|
if (!pending) {
|
|
@@ -926,7 +1246,8 @@ function useAuth() {
|
|
|
926
1246
|
avatarUrl
|
|
927
1247
|
});
|
|
928
1248
|
pendingAuth.current = null;
|
|
929
|
-
|
|
1249
|
+
const user2 = avatarUrl && !result.user.avatar ? { ...result.user, avatar: avatarUrl } : result.user;
|
|
1250
|
+
setUser(user2);
|
|
930
1251
|
setToken(result.token);
|
|
931
1252
|
setStatus("authenticated");
|
|
932
1253
|
} catch (err) {
|
|
@@ -934,7 +1255,7 @@ function useAuth() {
|
|
|
934
1255
|
setStatus("error");
|
|
935
1256
|
}
|
|
936
1257
|
}, [client]);
|
|
937
|
-
const logout = (0,
|
|
1258
|
+
const logout = (0, import_react10.useCallback)(async () => {
|
|
938
1259
|
try {
|
|
939
1260
|
await client.logout();
|
|
940
1261
|
} catch {
|
|
@@ -945,7 +1266,7 @@ function useAuth() {
|
|
|
945
1266
|
setError(null);
|
|
946
1267
|
pendingAuth.current = null;
|
|
947
1268
|
}, [client]);
|
|
948
|
-
const restoreSession = (0,
|
|
1269
|
+
const restoreSession = (0, import_react10.useCallback)(async (savedToken) => {
|
|
949
1270
|
try {
|
|
950
1271
|
client.setToken(savedToken);
|
|
951
1272
|
const me = await client.getMe();
|
|
@@ -961,6 +1282,7 @@ function useAuth() {
|
|
|
961
1282
|
return false;
|
|
962
1283
|
}
|
|
963
1284
|
}, [client]);
|
|
1285
|
+
if (sharedAuth) return sharedAuth;
|
|
964
1286
|
return {
|
|
965
1287
|
status,
|
|
966
1288
|
user,
|
|
@@ -976,50 +1298,7 @@ function useAuth() {
|
|
|
976
1298
|
}
|
|
977
1299
|
|
|
978
1300
|
// src/ui/AuthGate.tsx
|
|
979
|
-
var
|
|
980
|
-
var import_react_native2 = require("react-native");
|
|
981
|
-
|
|
982
|
-
// src/ui/theme.ts
|
|
983
|
-
var import_react_native = require("react-native");
|
|
984
|
-
var dark = {
|
|
985
|
-
background: "#08080D",
|
|
986
|
-
surface: "#111118",
|
|
987
|
-
surfaceActive: "#7C3AED",
|
|
988
|
-
border: "#1A1A24",
|
|
989
|
-
text: "#FFFFFF",
|
|
990
|
-
textSecondary: "#E0E0EE",
|
|
991
|
-
textMuted: "#666666",
|
|
992
|
-
textDim: "#555555",
|
|
993
|
-
accent: "#7C3AED",
|
|
994
|
-
success: "#22C55E",
|
|
995
|
-
live: "#EF4444",
|
|
996
|
-
errorText: "#F87171",
|
|
997
|
-
errorBg: "#1A0A0A",
|
|
998
|
-
errorBorder: "#3A1515"
|
|
999
|
-
};
|
|
1000
|
-
var light = {
|
|
1001
|
-
background: "#FFFFFF",
|
|
1002
|
-
surface: "#F0F0F5",
|
|
1003
|
-
surfaceActive: "#7C3AED",
|
|
1004
|
-
border: "#E0E0E8",
|
|
1005
|
-
text: "#111118",
|
|
1006
|
-
textSecondary: "#333333",
|
|
1007
|
-
textMuted: "#888888",
|
|
1008
|
-
textDim: "#999999",
|
|
1009
|
-
accent: "#7C3AED",
|
|
1010
|
-
success: "#16A34A",
|
|
1011
|
-
live: "#DC2626",
|
|
1012
|
-
errorText: "#DC2626",
|
|
1013
|
-
errorBg: "#FEF2F2",
|
|
1014
|
-
errorBorder: "#FECACA"
|
|
1015
|
-
};
|
|
1016
|
-
function useDubsTheme() {
|
|
1017
|
-
const scheme = (0, import_react_native.useColorScheme)();
|
|
1018
|
-
return scheme === "light" ? light : dark;
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
// src/ui/AuthGate.tsx
|
|
1022
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1301
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1023
1302
|
var DICEBEAR_STYLES = [
|
|
1024
1303
|
"adventurer",
|
|
1025
1304
|
"avataaars",
|
|
@@ -1045,9 +1324,9 @@ function AuthGate({
|
|
|
1045
1324
|
}) {
|
|
1046
1325
|
const { client } = useDubs();
|
|
1047
1326
|
const auth = useAuth();
|
|
1048
|
-
const [phase, setPhase] = (0,
|
|
1049
|
-
const [registrationPhase, setRegistrationPhase] = (0,
|
|
1050
|
-
(0,
|
|
1327
|
+
const [phase, setPhase] = (0, import_react11.useState)("init");
|
|
1328
|
+
const [registrationPhase, setRegistrationPhase] = (0, import_react11.useState)(false);
|
|
1329
|
+
(0, import_react11.useEffect)(() => {
|
|
1051
1330
|
let cancelled = false;
|
|
1052
1331
|
(async () => {
|
|
1053
1332
|
try {
|
|
@@ -1073,35 +1352,37 @@ function AuthGate({
|
|
|
1073
1352
|
cancelled = true;
|
|
1074
1353
|
};
|
|
1075
1354
|
}, []);
|
|
1076
|
-
(0,
|
|
1355
|
+
(0, import_react11.useEffect)(() => {
|
|
1077
1356
|
if (auth.status === "needsRegistration") setRegistrationPhase(true);
|
|
1078
1357
|
}, [auth.status]);
|
|
1079
|
-
(0,
|
|
1358
|
+
(0, import_react11.useEffect)(() => {
|
|
1080
1359
|
if (auth.token) onSaveToken(auth.token);
|
|
1081
1360
|
}, [auth.token]);
|
|
1082
|
-
const retry = (0,
|
|
1361
|
+
const retry = (0, import_react11.useCallback)(() => {
|
|
1083
1362
|
setRegistrationPhase(false);
|
|
1084
1363
|
auth.reset();
|
|
1085
1364
|
auth.authenticate();
|
|
1086
1365
|
}, [auth]);
|
|
1087
|
-
const handleRegister = (0,
|
|
1366
|
+
const handleRegister = (0, import_react11.useCallback)(
|
|
1088
1367
|
(username, referralCode, avatarUrl) => {
|
|
1089
1368
|
auth.register(username, referralCode, avatarUrl);
|
|
1090
1369
|
},
|
|
1091
1370
|
[auth]
|
|
1092
1371
|
);
|
|
1093
1372
|
if (phase === "init") {
|
|
1094
|
-
if (renderLoading) return /* @__PURE__ */ (0,
|
|
1095
|
-
return /* @__PURE__ */ (0,
|
|
1373
|
+
if (renderLoading) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: renderLoading("authenticating") });
|
|
1374
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultLoadingScreen, { status: "authenticating", appName });
|
|
1375
|
+
}
|
|
1376
|
+
if (auth.status === "authenticated") {
|
|
1377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AuthContext.Provider, { value: auth, children });
|
|
1096
1378
|
}
|
|
1097
|
-
if (auth.status === "authenticated") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
|
|
1098
1379
|
if (registrationPhase) {
|
|
1099
1380
|
const isRegistering = auth.status === "registering";
|
|
1100
1381
|
const regError = auth.status === "error" ? auth.error : null;
|
|
1101
1382
|
if (renderRegistration) {
|
|
1102
|
-
return /* @__PURE__ */ (0,
|
|
1383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: renderRegistration({ onRegister: handleRegister, registering: isRegistering, error: regError, client }) });
|
|
1103
1384
|
}
|
|
1104
|
-
return /* @__PURE__ */ (0,
|
|
1385
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1105
1386
|
DefaultRegistrationScreen,
|
|
1106
1387
|
{
|
|
1107
1388
|
onRegister: handleRegister,
|
|
@@ -1113,11 +1394,11 @@ function AuthGate({
|
|
|
1113
1394
|
);
|
|
1114
1395
|
}
|
|
1115
1396
|
if (auth.status === "error" && auth.error) {
|
|
1116
|
-
if (renderError) return /* @__PURE__ */ (0,
|
|
1117
|
-
return /* @__PURE__ */ (0,
|
|
1397
|
+
if (renderError) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: renderError(auth.error, retry) });
|
|
1398
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultErrorScreen, { error: auth.error, onRetry: retry, appName });
|
|
1118
1399
|
}
|
|
1119
|
-
if (renderLoading) return /* @__PURE__ */ (0,
|
|
1120
|
-
return /* @__PURE__ */ (0,
|
|
1400
|
+
if (renderLoading) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: renderLoading(auth.status) });
|
|
1401
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultLoadingScreen, { status: auth.status, appName });
|
|
1121
1402
|
}
|
|
1122
1403
|
function DefaultLoadingScreen({ status, appName }) {
|
|
1123
1404
|
const t = useDubsTheme();
|
|
@@ -1131,43 +1412,43 @@ function DefaultLoadingScreen({ status, appName }) {
|
|
|
1131
1412
|
authenticated: "Ready!",
|
|
1132
1413
|
error: "Something went wrong"
|
|
1133
1414
|
};
|
|
1134
|
-
return /* @__PURE__ */ (0,
|
|
1135
|
-
/* @__PURE__ */ (0,
|
|
1136
|
-
/* @__PURE__ */ (0,
|
|
1137
|
-
/* @__PURE__ */ (0,
|
|
1415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [s.container, { backgroundColor: t.background }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.centerContent, children: [
|
|
1416
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.brandingSection, children: [
|
|
1417
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [s.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: s.logoText, children: "D" }) }),
|
|
1418
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.appNameText, { color: t.text }], children: appName })
|
|
1138
1419
|
] }),
|
|
1139
|
-
/* @__PURE__ */ (0,
|
|
1140
|
-
/* @__PURE__ */ (0,
|
|
1141
|
-
/* @__PURE__ */ (0,
|
|
1420
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.loadingSection, children: [
|
|
1421
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.ActivityIndicator, { size: "large", color: t.accent }),
|
|
1422
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.statusText, { color: t.textMuted }], children: statusText[status] || "Loading..." })
|
|
1142
1423
|
] })
|
|
1143
1424
|
] }) });
|
|
1144
1425
|
}
|
|
1145
1426
|
function DefaultErrorScreen({ error, onRetry, appName }) {
|
|
1146
1427
|
const t = useDubsTheme();
|
|
1147
|
-
return /* @__PURE__ */ (0,
|
|
1148
|
-
/* @__PURE__ */ (0,
|
|
1149
|
-
/* @__PURE__ */ (0,
|
|
1150
|
-
/* @__PURE__ */ (0,
|
|
1428
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [s.container, { backgroundColor: t.background }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.spreadContent, children: [
|
|
1429
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.brandingSection, children: [
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [s.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: s.logoText, children: "D" }) }),
|
|
1431
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.appNameText, { color: t.text }], children: appName })
|
|
1151
1432
|
] }),
|
|
1152
|
-
/* @__PURE__ */ (0,
|
|
1153
|
-
/* @__PURE__ */ (0,
|
|
1154
|
-
/* @__PURE__ */ (0,
|
|
1433
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: { gap: 16 }, children: [
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [s.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.errorText, { color: t.errorText }], children: error.message }) }),
|
|
1435
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.TouchableOpacity, { style: [s.primaryBtn, { backgroundColor: t.accent }], onPress: onRetry, activeOpacity: 0.8, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: s.primaryBtnText, children: "Try Again" }) })
|
|
1155
1436
|
] })
|
|
1156
1437
|
] }) });
|
|
1157
1438
|
}
|
|
1158
1439
|
function StepIndicator({ currentStep }) {
|
|
1159
1440
|
const t = useDubsTheme();
|
|
1160
1441
|
const steps = [0, 1, 2, 3];
|
|
1161
|
-
return /* @__PURE__ */ (0,
|
|
1162
|
-
i > 0 && /* @__PURE__ */ (0,
|
|
1163
|
-
/* @__PURE__ */ (0,
|
|
1164
|
-
|
|
1442
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: s.stepRow, children: steps.map((i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react11.default.Fragment, { children: [
|
|
1443
|
+
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [s.stepLine, { backgroundColor: i <= currentStep ? t.success : t.border }] }),
|
|
1444
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1445
|
+
import_react_native3.View,
|
|
1165
1446
|
{
|
|
1166
1447
|
style: [
|
|
1167
1448
|
s.stepCircle,
|
|
1168
1449
|
i < currentStep ? { backgroundColor: t.success } : i === currentStep ? { backgroundColor: t.accent } : { backgroundColor: "transparent", borderWidth: 2, borderColor: t.border }
|
|
1169
1450
|
],
|
|
1170
|
-
children: i < currentStep ? /* @__PURE__ */ (0,
|
|
1451
|
+
children: i < currentStep ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: s.stepCheck, children: "\u2713" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.stepNum, { color: i === currentStep ? "#FFF" : t.textMuted }], children: i + 1 })
|
|
1171
1452
|
}
|
|
1172
1453
|
)
|
|
1173
1454
|
] }, i)) });
|
|
@@ -1180,19 +1461,19 @@ function DefaultRegistrationScreen({
|
|
|
1180
1461
|
appName
|
|
1181
1462
|
}) {
|
|
1182
1463
|
const t = useDubsTheme();
|
|
1183
|
-
const [step, setStep] = (0,
|
|
1184
|
-
const [avatarSeed, setAvatarSeed] = (0,
|
|
1185
|
-
const [avatarStyle, setAvatarStyle] = (0,
|
|
1186
|
-
const [showStyles, setShowStyles] = (0,
|
|
1187
|
-
const [username, setUsername] = (0,
|
|
1188
|
-
const [referralCode, setReferralCode] = (0,
|
|
1189
|
-
const [checking, setChecking] = (0,
|
|
1190
|
-
const [availability, setAvailability] = (0,
|
|
1191
|
-
const debounceRef = (0,
|
|
1192
|
-
const fadeAnim = (0,
|
|
1193
|
-
const slideAnim = (0,
|
|
1464
|
+
const [step, setStep] = (0, import_react11.useState)(0);
|
|
1465
|
+
const [avatarSeed, setAvatarSeed] = (0, import_react11.useState)(generateSeed);
|
|
1466
|
+
const [avatarStyle, setAvatarStyle] = (0, import_react11.useState)("adventurer");
|
|
1467
|
+
const [showStyles, setShowStyles] = (0, import_react11.useState)(false);
|
|
1468
|
+
const [username, setUsername] = (0, import_react11.useState)("");
|
|
1469
|
+
const [referralCode, setReferralCode] = (0, import_react11.useState)("");
|
|
1470
|
+
const [checking, setChecking] = (0, import_react11.useState)(false);
|
|
1471
|
+
const [availability, setAvailability] = (0, import_react11.useState)(null);
|
|
1472
|
+
const debounceRef = (0, import_react11.useRef)(null);
|
|
1473
|
+
const fadeAnim = (0, import_react11.useRef)(new import_react_native3.Animated.Value(1)).current;
|
|
1474
|
+
const slideAnim = (0, import_react11.useRef)(new import_react_native3.Animated.Value(0)).current;
|
|
1194
1475
|
const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed);
|
|
1195
|
-
(0,
|
|
1476
|
+
(0, import_react11.useEffect)(() => {
|
|
1196
1477
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
1197
1478
|
const trimmed = username.trim();
|
|
1198
1479
|
if (trimmed.length < 3) {
|
|
@@ -1215,94 +1496,94 @@ function DefaultRegistrationScreen({
|
|
|
1215
1496
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
1216
1497
|
};
|
|
1217
1498
|
}, [username, client]);
|
|
1218
|
-
const animateToStep = (0,
|
|
1499
|
+
const animateToStep = (0, import_react11.useCallback)((newStep) => {
|
|
1219
1500
|
const dir = newStep > step ? 1 : -1;
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1501
|
+
import_react_native3.Keyboard.dismiss();
|
|
1502
|
+
import_react_native3.Animated.parallel([
|
|
1503
|
+
import_react_native3.Animated.timing(fadeAnim, { toValue: 0, duration: 120, useNativeDriver: true }),
|
|
1504
|
+
import_react_native3.Animated.timing(slideAnim, { toValue: -dir * 40, duration: 120, useNativeDriver: true })
|
|
1224
1505
|
]).start(() => {
|
|
1225
1506
|
setStep(newStep);
|
|
1226
1507
|
slideAnim.setValue(dir * 40);
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1508
|
+
import_react_native3.Animated.parallel([
|
|
1509
|
+
import_react_native3.Animated.timing(fadeAnim, { toValue: 1, duration: 200, useNativeDriver: true }),
|
|
1510
|
+
import_react_native3.Animated.timing(slideAnim, { toValue: 0, duration: 200, useNativeDriver: true })
|
|
1230
1511
|
]).start();
|
|
1231
1512
|
});
|
|
1232
1513
|
}, [step, fadeAnim, slideAnim]);
|
|
1233
1514
|
const canContinueUsername = username.trim().length >= 3 && availability?.available === true && !checking;
|
|
1234
1515
|
const handleSubmit = () => {
|
|
1235
|
-
|
|
1516
|
+
import_react_native3.Keyboard.dismiss();
|
|
1236
1517
|
onRegister(username.trim(), referralCode.trim() || void 0, avatarUrl);
|
|
1237
1518
|
};
|
|
1238
|
-
const renderAvatarStep = () => /* @__PURE__ */ (0,
|
|
1239
|
-
/* @__PURE__ */ (0,
|
|
1240
|
-
/* @__PURE__ */ (0,
|
|
1241
|
-
/* @__PURE__ */ (0,
|
|
1242
|
-
/* @__PURE__ */ (0,
|
|
1243
|
-
/* @__PURE__ */ (0,
|
|
1244
|
-
/* @__PURE__ */ (0,
|
|
1245
|
-
/* @__PURE__ */ (0,
|
|
1519
|
+
const renderAvatarStep = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.stepContainer, children: [
|
|
1520
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.stepTop, children: [
|
|
1521
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.title, { color: t.text }], children: "Choose Your Avatar" }),
|
|
1522
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.subtitle, { color: t.textMuted }], children: "Pick a look that represents you" }),
|
|
1523
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StepIndicator, { currentStep: 0 }),
|
|
1524
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: s.avatarCenter, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: [s.avatarFrame, { borderColor: t.accent }], children: [
|
|
1525
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Image, { source: { uri: avatarUrl }, style: s.avatarLarge }),
|
|
1526
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [s.checkBadge, { backgroundColor: t.success }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: s.checkBadgeText, children: "\u2713" }) })
|
|
1246
1527
|
] }) }),
|
|
1247
|
-
/* @__PURE__ */ (0,
|
|
1248
|
-
/* @__PURE__ */ (0,
|
|
1249
|
-
|
|
1528
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.avatarActions, children: [
|
|
1529
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1530
|
+
import_react_native3.TouchableOpacity,
|
|
1250
1531
|
{
|
|
1251
1532
|
style: [s.outlineBtn, { borderColor: t.border }],
|
|
1252
1533
|
onPress: () => setAvatarSeed(generateSeed()),
|
|
1253
1534
|
activeOpacity: 0.7,
|
|
1254
|
-
children: /* @__PURE__ */ (0,
|
|
1535
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.outlineBtnText, { color: t.text }], children: "\u21BB Shuffle" })
|
|
1255
1536
|
}
|
|
1256
1537
|
),
|
|
1257
|
-
/* @__PURE__ */ (0,
|
|
1258
|
-
|
|
1538
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1539
|
+
import_react_native3.TouchableOpacity,
|
|
1259
1540
|
{
|
|
1260
1541
|
style: [s.outlineBtn, { borderColor: t.accent, backgroundColor: t.accent + "15" }],
|
|
1261
1542
|
onPress: () => setShowStyles(!showStyles),
|
|
1262
1543
|
activeOpacity: 0.7,
|
|
1263
|
-
children: /* @__PURE__ */ (0,
|
|
1544
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.outlineBtnText, { color: t.accent }], children: "\u263A Customize" })
|
|
1264
1545
|
}
|
|
1265
1546
|
)
|
|
1266
1547
|
] }),
|
|
1267
|
-
showStyles && /* @__PURE__ */ (0,
|
|
1268
|
-
|
|
1548
|
+
showStyles && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: s.styleScroll, children: DICEBEAR_STYLES.map((st) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1549
|
+
import_react_native3.TouchableOpacity,
|
|
1269
1550
|
{
|
|
1270
1551
|
onPress: () => setAvatarStyle(st),
|
|
1271
1552
|
style: [s.styleThumbWrap, { borderColor: st === avatarStyle ? t.accent : t.border }],
|
|
1272
|
-
children: /* @__PURE__ */ (0,
|
|
1553
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Image, { source: { uri: getAvatarUrl(st, avatarSeed, 80) }, style: s.styleThumb })
|
|
1273
1554
|
},
|
|
1274
1555
|
st
|
|
1275
1556
|
)) })
|
|
1276
1557
|
] }),
|
|
1277
|
-
/* @__PURE__ */ (0,
|
|
1278
|
-
|
|
1558
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: s.bottomRow, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1559
|
+
import_react_native3.TouchableOpacity,
|
|
1279
1560
|
{
|
|
1280
1561
|
style: [s.primaryBtn, { backgroundColor: t.accent, flex: 1 }],
|
|
1281
1562
|
onPress: () => animateToStep(1),
|
|
1282
1563
|
activeOpacity: 0.8,
|
|
1283
|
-
children: /* @__PURE__ */ (0,
|
|
1564
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: s.primaryBtnText, children: "Continue \u203A" })
|
|
1284
1565
|
}
|
|
1285
1566
|
) })
|
|
1286
1567
|
] });
|
|
1287
|
-
const renderUsernameStep = () => /* @__PURE__ */ (0,
|
|
1288
|
-
/* @__PURE__ */ (0,
|
|
1289
|
-
/* @__PURE__ */ (0,
|
|
1290
|
-
/* @__PURE__ */ (0,
|
|
1291
|
-
/* @__PURE__ */ (0,
|
|
1568
|
+
const renderUsernameStep = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.stepContainer, children: [
|
|
1569
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.stepTop, children: [
|
|
1570
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.headerRow, children: [
|
|
1571
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.TouchableOpacity, { onPress: () => animateToStep(0), hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.backChevron, { color: t.text }], children: "\u2039" }) }),
|
|
1572
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.titleInline, { color: t.text }], children: "Pick a Username" })
|
|
1292
1573
|
] }),
|
|
1293
|
-
/* @__PURE__ */ (0,
|
|
1294
|
-
/* @__PURE__ */ (0,
|
|
1295
|
-
/* @__PURE__ */ (0,
|
|
1296
|
-
/* @__PURE__ */ (0,
|
|
1297
|
-
/* @__PURE__ */ (0,
|
|
1574
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.subtitle, { color: t.textMuted }], children: "This is how others will see you" }),
|
|
1575
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StepIndicator, { currentStep: 1 }),
|
|
1576
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: s.avatarCenter, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: [s.avatarFrameSmall, { borderColor: t.accent }], children: [
|
|
1577
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Image, { source: { uri: avatarUrl }, style: s.avatarSmall }),
|
|
1578
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [s.checkBadgeSm, { backgroundColor: t.success }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: s.checkBadgeTextSm, children: "\u2713" }) })
|
|
1298
1579
|
] }) }),
|
|
1299
|
-
/* @__PURE__ */ (0,
|
|
1300
|
-
/* @__PURE__ */ (0,
|
|
1580
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.inputGroup, children: [
|
|
1581
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Text, { style: [s.inputLabel, { color: t.text }], children: [
|
|
1301
1582
|
"Username ",
|
|
1302
|
-
/* @__PURE__ */ (0,
|
|
1583
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: { color: t.errorText }, children: "*" })
|
|
1303
1584
|
] }),
|
|
1304
|
-
/* @__PURE__ */ (0,
|
|
1305
|
-
|
|
1585
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1586
|
+
import_react_native3.TextInput,
|
|
1306
1587
|
{
|
|
1307
1588
|
style: [s.input, { backgroundColor: t.surface, color: t.text, borderColor: t.accent }],
|
|
1308
1589
|
placeholder: "Enter username",
|
|
@@ -1314,63 +1595,63 @@ function DefaultRegistrationScreen({
|
|
|
1314
1595
|
autoFocus: true
|
|
1315
1596
|
}
|
|
1316
1597
|
),
|
|
1317
|
-
checking ? /* @__PURE__ */ (0,
|
|
1598
|
+
checking ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.hint, { color: t.textDim }], children: "Checking..." }) : availability ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.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__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.hint, { color: t.textDim }], children: "At least 3 characters" }) : null
|
|
1318
1599
|
] })
|
|
1319
1600
|
] }),
|
|
1320
|
-
/* @__PURE__ */ (0,
|
|
1321
|
-
/* @__PURE__ */ (0,
|
|
1322
|
-
|
|
1601
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.bottomRow, children: [
|
|
1602
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1603
|
+
import_react_native3.TouchableOpacity,
|
|
1323
1604
|
{
|
|
1324
1605
|
style: [s.secondaryBtn, { borderColor: t.border }],
|
|
1325
1606
|
onPress: () => animateToStep(0),
|
|
1326
1607
|
activeOpacity: 0.7,
|
|
1327
|
-
children: /* @__PURE__ */ (0,
|
|
1608
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.secondaryBtnText, { color: t.text }], children: "\u2039 Back" })
|
|
1328
1609
|
}
|
|
1329
1610
|
),
|
|
1330
|
-
/* @__PURE__ */ (0,
|
|
1331
|
-
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1612
|
+
import_react_native3.TouchableOpacity,
|
|
1332
1613
|
{
|
|
1333
1614
|
style: [s.primaryBtn, { backgroundColor: t.accent, flex: 1, opacity: canContinueUsername ? 1 : 0.4 }],
|
|
1334
1615
|
onPress: () => animateToStep(2),
|
|
1335
1616
|
disabled: !canContinueUsername,
|
|
1336
1617
|
activeOpacity: 0.8,
|
|
1337
|
-
children: /* @__PURE__ */ (0,
|
|
1618
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: s.primaryBtnText, children: "Continue \u203A" })
|
|
1338
1619
|
}
|
|
1339
1620
|
)
|
|
1340
1621
|
] })
|
|
1341
1622
|
] });
|
|
1342
|
-
const renderReferralStep = () => /* @__PURE__ */ (0,
|
|
1343
|
-
/* @__PURE__ */ (0,
|
|
1344
|
-
/* @__PURE__ */ (0,
|
|
1345
|
-
/* @__PURE__ */ (0,
|
|
1346
|
-
/* @__PURE__ */ (0,
|
|
1623
|
+
const renderReferralStep = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.stepContainer, children: [
|
|
1624
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.stepTop, children: [
|
|
1625
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.headerRow, children: [
|
|
1626
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.TouchableOpacity, { onPress: () => animateToStep(1), hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.backChevron, { color: t.text }], children: "\u2039" }) }),
|
|
1627
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.titleInline, { color: t.text }], children: "Almost There!" })
|
|
1347
1628
|
] }),
|
|
1348
|
-
/* @__PURE__ */ (0,
|
|
1349
|
-
/* @__PURE__ */ (0,
|
|
1350
|
-
/* @__PURE__ */ (0,
|
|
1351
|
-
/* @__PURE__ */ (0,
|
|
1352
|
-
/* @__PURE__ */ (0,
|
|
1353
|
-
/* @__PURE__ */ (0,
|
|
1354
|
-
/* @__PURE__ */ (0,
|
|
1355
|
-
/* @__PURE__ */ (0,
|
|
1629
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.subtitle, { color: t.textMuted }], children: "Got a referral code? (optional)" }),
|
|
1630
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StepIndicator, { currentStep: 2 }),
|
|
1631
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: [s.profileCard, { borderColor: t.border }], children: [
|
|
1632
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.profileLabel, { color: t.textMuted }], children: "Your Profile" }),
|
|
1633
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.profileRow, children: [
|
|
1634
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Image, { source: { uri: avatarUrl }, style: s.profileAvatar }),
|
|
1635
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: { gap: 4 }, children: [
|
|
1636
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Text, { style: [s.profileUsername, { color: t.text }], children: [
|
|
1356
1637
|
"@",
|
|
1357
1638
|
username
|
|
1358
1639
|
] }),
|
|
1359
|
-
/* @__PURE__ */ (0,
|
|
1640
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Text, { style: [s.profileReady, { color: t.success }], children: [
|
|
1360
1641
|
"\u2713",
|
|
1361
1642
|
" Ready to go!"
|
|
1362
1643
|
] })
|
|
1363
1644
|
] })
|
|
1364
1645
|
] })
|
|
1365
1646
|
] }),
|
|
1366
|
-
error ? /* @__PURE__ */ (0,
|
|
1367
|
-
/* @__PURE__ */ (0,
|
|
1368
|
-
/* @__PURE__ */ (0,
|
|
1647
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [s.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.errorText, { color: t.errorText }], children: error.message }) }) : null,
|
|
1648
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.inputGroup, children: [
|
|
1649
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Text, { style: [s.inputLabel, { color: t.text }], children: [
|
|
1369
1650
|
"Referral Code ",
|
|
1370
|
-
/* @__PURE__ */ (0,
|
|
1651
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: { color: t.textMuted }, children: "(optional)" })
|
|
1371
1652
|
] }),
|
|
1372
|
-
/* @__PURE__ */ (0,
|
|
1373
|
-
|
|
1653
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1654
|
+
import_react_native3.TextInput,
|
|
1374
1655
|
{
|
|
1375
1656
|
style: [s.input, { backgroundColor: t.surface, color: t.text, borderColor: t.border }],
|
|
1376
1657
|
placeholder: "Enter referral code",
|
|
@@ -1382,31 +1663,31 @@ function DefaultRegistrationScreen({
|
|
|
1382
1663
|
editable: !registering
|
|
1383
1664
|
}
|
|
1384
1665
|
),
|
|
1385
|
-
/* @__PURE__ */ (0,
|
|
1666
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Text, { style: [s.hint, { color: t.textMuted }], children: [
|
|
1386
1667
|
"\u{1F381}",
|
|
1387
1668
|
" If a friend invited you, enter their code to give them credit!"
|
|
1388
1669
|
] })
|
|
1389
1670
|
] })
|
|
1390
1671
|
] }),
|
|
1391
|
-
/* @__PURE__ */ (0,
|
|
1392
|
-
/* @__PURE__ */ (0,
|
|
1393
|
-
|
|
1672
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: s.bottomRow, children: [
|
|
1673
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1674
|
+
import_react_native3.TouchableOpacity,
|
|
1394
1675
|
{
|
|
1395
1676
|
style: [s.secondaryBtn, { borderColor: t.border }],
|
|
1396
1677
|
onPress: () => animateToStep(1),
|
|
1397
1678
|
disabled: registering,
|
|
1398
1679
|
activeOpacity: 0.7,
|
|
1399
|
-
children: /* @__PURE__ */ (0,
|
|
1680
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [s.secondaryBtnText, { color: t.text }], children: "\u2039 Back" })
|
|
1400
1681
|
}
|
|
1401
1682
|
),
|
|
1402
|
-
/* @__PURE__ */ (0,
|
|
1403
|
-
|
|
1683
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1684
|
+
import_react_native3.TouchableOpacity,
|
|
1404
1685
|
{
|
|
1405
1686
|
style: [s.primaryBtn, { backgroundColor: t.accent, flex: 1, opacity: registering ? 0.7 : 1 }],
|
|
1406
1687
|
onPress: handleSubmit,
|
|
1407
1688
|
disabled: registering,
|
|
1408
1689
|
activeOpacity: 0.8,
|
|
1409
|
-
children: registering ? /* @__PURE__ */ (0,
|
|
1690
|
+
children: registering ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.ActivityIndicator, { color: "#FFFFFF", size: "small" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: s.primaryBtnText, children: "Create Account" })
|
|
1410
1691
|
}
|
|
1411
1692
|
)
|
|
1412
1693
|
] })
|
|
@@ -1423,19 +1704,19 @@ function DefaultRegistrationScreen({
|
|
|
1423
1704
|
return null;
|
|
1424
1705
|
}
|
|
1425
1706
|
};
|
|
1426
|
-
return /* @__PURE__ */ (0,
|
|
1427
|
-
|
|
1707
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1708
|
+
import_react_native3.KeyboardAvoidingView,
|
|
1428
1709
|
{
|
|
1429
1710
|
style: [s.container, { backgroundColor: t.background }],
|
|
1430
|
-
behavior:
|
|
1431
|
-
children: /* @__PURE__ */ (0,
|
|
1432
|
-
|
|
1711
|
+
behavior: import_react_native3.Platform.OS === "ios" ? "padding" : void 0,
|
|
1712
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1713
|
+
import_react_native3.ScrollView,
|
|
1433
1714
|
{
|
|
1434
1715
|
contentContainerStyle: { flexGrow: 1 },
|
|
1435
1716
|
keyboardShouldPersistTaps: "handled",
|
|
1436
1717
|
bounces: false,
|
|
1437
|
-
children: /* @__PURE__ */ (0,
|
|
1438
|
-
|
|
1718
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1719
|
+
import_react_native3.Animated.View,
|
|
1439
1720
|
{
|
|
1440
1721
|
style: [
|
|
1441
1722
|
{ flex: 1 },
|
|
@@ -1449,7 +1730,7 @@ function DefaultRegistrationScreen({
|
|
|
1449
1730
|
}
|
|
1450
1731
|
);
|
|
1451
1732
|
}
|
|
1452
|
-
var s =
|
|
1733
|
+
var s = import_react_native3.StyleSheet.create({
|
|
1453
1734
|
container: { flex: 1 },
|
|
1454
1735
|
// Loading / Error
|
|
1455
1736
|
centerContent: { flex: 1, justifyContent: "center", alignItems: "center", paddingHorizontal: 32, gap: 48 },
|
|
@@ -1512,119 +1793,165 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1512
1793
|
secondaryBtnText: { fontSize: 16, fontWeight: "600" }
|
|
1513
1794
|
});
|
|
1514
1795
|
|
|
1515
|
-
// src/
|
|
1516
|
-
var
|
|
1517
|
-
var
|
|
1518
|
-
function
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1796
|
+
// src/provider.tsx
|
|
1797
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1798
|
+
var DubsContext = (0, import_react12.createContext)(null);
|
|
1799
|
+
function DubsProvider({
|
|
1800
|
+
apiKey,
|
|
1801
|
+
children,
|
|
1802
|
+
appName = "Dubs",
|
|
1803
|
+
network = "mainnet-beta",
|
|
1804
|
+
wallet: externalWallet,
|
|
1805
|
+
tokenStorage,
|
|
1806
|
+
baseUrl: baseUrlOverride,
|
|
1807
|
+
rpcUrl: rpcUrlOverride,
|
|
1808
|
+
renderConnectScreen,
|
|
1809
|
+
renderLoading,
|
|
1810
|
+
renderError,
|
|
1811
|
+
renderRegistration,
|
|
1812
|
+
managed = true
|
|
1523
1813
|
}) {
|
|
1524
|
-
const
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1814
|
+
const config = NETWORK_CONFIG[network];
|
|
1815
|
+
const baseUrl = baseUrlOverride || config.baseUrl;
|
|
1816
|
+
const rpcUrl = rpcUrlOverride || config.rpcUrl;
|
|
1817
|
+
const cluster = config.cluster;
|
|
1818
|
+
const client = (0, import_react12.useMemo)(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
|
|
1819
|
+
const connection = (0, import_react12.useMemo)(() => new import_web33.Connection(rpcUrl, { commitment: "confirmed" }), [rpcUrl]);
|
|
1820
|
+
const storage = (0, import_react12.useMemo)(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
|
|
1821
|
+
if (externalWallet) {
|
|
1822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1823
|
+
ExternalWalletProvider,
|
|
1824
|
+
{
|
|
1825
|
+
client,
|
|
1826
|
+
connection,
|
|
1827
|
+
wallet: externalWallet,
|
|
1828
|
+
appName,
|
|
1829
|
+
network,
|
|
1830
|
+
storage,
|
|
1831
|
+
managed,
|
|
1832
|
+
renderLoading,
|
|
1833
|
+
renderError,
|
|
1834
|
+
renderRegistration,
|
|
1835
|
+
children
|
|
1836
|
+
}
|
|
1837
|
+
);
|
|
1838
|
+
}
|
|
1839
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1840
|
+
ManagedWalletProvider,
|
|
1841
|
+
{
|
|
1842
|
+
appName,
|
|
1843
|
+
cluster,
|
|
1844
|
+
storage,
|
|
1845
|
+
renderConnectScreen,
|
|
1846
|
+
children: (adapter) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1847
|
+
ManagedInner,
|
|
1544
1848
|
{
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1849
|
+
client,
|
|
1850
|
+
connection,
|
|
1851
|
+
wallet: adapter,
|
|
1852
|
+
appName,
|
|
1853
|
+
network,
|
|
1854
|
+
storage,
|
|
1855
|
+
renderLoading,
|
|
1856
|
+
renderError,
|
|
1857
|
+
renderRegistration,
|
|
1858
|
+
children
|
|
1550
1859
|
}
|
|
1551
|
-
)
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
] }) });
|
|
1860
|
+
)
|
|
1861
|
+
}
|
|
1862
|
+
);
|
|
1555
1863
|
}
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
hint: {
|
|
1619
|
-
fontSize: 13,
|
|
1620
|
-
textAlign: "center"
|
|
1864
|
+
function ManagedInner({
|
|
1865
|
+
client,
|
|
1866
|
+
connection,
|
|
1867
|
+
wallet,
|
|
1868
|
+
appName,
|
|
1869
|
+
network,
|
|
1870
|
+
storage,
|
|
1871
|
+
renderLoading,
|
|
1872
|
+
renderError,
|
|
1873
|
+
renderRegistration,
|
|
1874
|
+
children
|
|
1875
|
+
}) {
|
|
1876
|
+
const managedDisconnect = useDisconnect();
|
|
1877
|
+
const disconnect = (0, import_react12.useCallback)(async () => {
|
|
1878
|
+
client.setToken(null);
|
|
1879
|
+
await managedDisconnect?.();
|
|
1880
|
+
}, [client, managedDisconnect]);
|
|
1881
|
+
const value = (0, import_react12.useMemo)(
|
|
1882
|
+
() => ({ client, wallet, connection, appName, network, disconnect }),
|
|
1883
|
+
[client, wallet, connection, appName, network, disconnect]
|
|
1884
|
+
);
|
|
1885
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DubsContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1886
|
+
AuthGate,
|
|
1887
|
+
{
|
|
1888
|
+
onSaveToken: (token) => {
|
|
1889
|
+
if (token) return storage.setItem(STORAGE_KEYS.JWT_TOKEN, token);
|
|
1890
|
+
return storage.deleteItem(STORAGE_KEYS.JWT_TOKEN);
|
|
1891
|
+
},
|
|
1892
|
+
onLoadToken: () => storage.getItem(STORAGE_KEYS.JWT_TOKEN),
|
|
1893
|
+
renderLoading,
|
|
1894
|
+
renderError,
|
|
1895
|
+
renderRegistration,
|
|
1896
|
+
appName,
|
|
1897
|
+
children
|
|
1898
|
+
}
|
|
1899
|
+
) });
|
|
1900
|
+
}
|
|
1901
|
+
function ExternalWalletProvider({
|
|
1902
|
+
client,
|
|
1903
|
+
connection,
|
|
1904
|
+
wallet,
|
|
1905
|
+
appName,
|
|
1906
|
+
network,
|
|
1907
|
+
storage,
|
|
1908
|
+
managed,
|
|
1909
|
+
renderLoading,
|
|
1910
|
+
renderError,
|
|
1911
|
+
renderRegistration,
|
|
1912
|
+
children
|
|
1913
|
+
}) {
|
|
1914
|
+
const disconnect = (0, import_react12.useCallback)(async () => {
|
|
1915
|
+
client.setToken(null);
|
|
1916
|
+
await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
|
|
1917
|
+
});
|
|
1918
|
+
await wallet.disconnect?.();
|
|
1919
|
+
}, [client, storage, wallet]);
|
|
1920
|
+
const value = (0, import_react12.useMemo)(
|
|
1921
|
+
() => ({ client, wallet, connection, appName, network, disconnect }),
|
|
1922
|
+
[client, wallet, connection, appName, network, disconnect]
|
|
1923
|
+
);
|
|
1924
|
+
if (!managed) {
|
|
1925
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DubsContext.Provider, { value, children });
|
|
1621
1926
|
}
|
|
1622
|
-
|
|
1927
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DubsContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1928
|
+
AuthGate,
|
|
1929
|
+
{
|
|
1930
|
+
onSaveToken: (token) => {
|
|
1931
|
+
if (token) return storage.setItem(STORAGE_KEYS.JWT_TOKEN, token);
|
|
1932
|
+
return storage.deleteItem(STORAGE_KEYS.JWT_TOKEN);
|
|
1933
|
+
},
|
|
1934
|
+
onLoadToken: () => storage.getItem(STORAGE_KEYS.JWT_TOKEN),
|
|
1935
|
+
renderLoading,
|
|
1936
|
+
renderError,
|
|
1937
|
+
renderRegistration,
|
|
1938
|
+
appName,
|
|
1939
|
+
children
|
|
1940
|
+
}
|
|
1941
|
+
) });
|
|
1942
|
+
}
|
|
1943
|
+
function useDubs() {
|
|
1944
|
+
const ctx = (0, import_react12.useContext)(DubsContext);
|
|
1945
|
+
if (!ctx) {
|
|
1946
|
+
throw new Error("useDubs must be used within a <DubsProvider>");
|
|
1947
|
+
}
|
|
1948
|
+
return ctx;
|
|
1949
|
+
}
|
|
1623
1950
|
|
|
1624
1951
|
// src/ui/UserProfileCard.tsx
|
|
1625
|
-
var
|
|
1952
|
+
var import_react13 = require("react");
|
|
1626
1953
|
var import_react_native4 = require("react-native");
|
|
1627
|
-
var
|
|
1954
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1628
1955
|
function truncateAddress(address, chars = 4) {
|
|
1629
1956
|
if (address.length <= chars * 2 + 3) return address;
|
|
1630
1957
|
return `${address.slice(0, chars)}...${address.slice(-chars)}`;
|
|
@@ -1642,16 +1969,16 @@ function UserProfileCard({
|
|
|
1642
1969
|
memberSince
|
|
1643
1970
|
}) {
|
|
1644
1971
|
const t = useDubsTheme();
|
|
1645
|
-
const imageUri = (0,
|
|
1972
|
+
const imageUri = (0, import_react13.useMemo)(
|
|
1646
1973
|
() => avatarUrl || `https://api.dicebear.com/9.x/avataaars/png?seed=${walletAddress}&size=128`,
|
|
1647
1974
|
[avatarUrl, walletAddress]
|
|
1648
1975
|
);
|
|
1649
|
-
return /* @__PURE__ */ (0,
|
|
1650
|
-
/* @__PURE__ */ (0,
|
|
1651
|
-
/* @__PURE__ */ (0,
|
|
1652
|
-
username ? /* @__PURE__ */ (0,
|
|
1653
|
-
/* @__PURE__ */ (0,
|
|
1654
|
-
memberSince ? /* @__PURE__ */ (0,
|
|
1976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { style: [styles2.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
|
|
1977
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Image, { source: { uri: imageUri }, style: styles2.avatar }),
|
|
1978
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { style: styles2.info, children: [
|
|
1979
|
+
username ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: [styles2.username, { color: t.text }], children: username }) : null,
|
|
1980
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: [styles2.address, { color: t.textMuted }], children: truncateAddress(walletAddress) }),
|
|
1981
|
+
memberSince ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: [styles2.memberSince, { color: t.textDim }], children: formatMemberSince(memberSince) }) : null
|
|
1655
1982
|
] })
|
|
1656
1983
|
] });
|
|
1657
1984
|
}
|
|
@@ -1690,7 +2017,7 @@ var styles2 = import_react_native4.StyleSheet.create({
|
|
|
1690
2017
|
|
|
1691
2018
|
// src/ui/SettingsSheet.tsx
|
|
1692
2019
|
var import_react_native5 = require("react-native");
|
|
1693
|
-
var
|
|
2020
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1694
2021
|
function truncateAddress2(address, chars = 4) {
|
|
1695
2022
|
if (address.length <= chars * 2 + 3) return address;
|
|
1696
2023
|
return `${address.slice(0, chars)}...${address.slice(-chars)}`;
|
|
@@ -1707,13 +2034,13 @@ function SettingsSheet({
|
|
|
1707
2034
|
loggingOut = false
|
|
1708
2035
|
}) {
|
|
1709
2036
|
const t = useDubsTheme();
|
|
1710
|
-
return /* @__PURE__ */ (0,
|
|
2037
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1711
2038
|
import_react_native5.ScrollView,
|
|
1712
2039
|
{
|
|
1713
2040
|
style: [styles3.container, { backgroundColor: t.background }],
|
|
1714
2041
|
contentContainerStyle: styles3.content,
|
|
1715
2042
|
children: [
|
|
1716
|
-
/* @__PURE__ */ (0,
|
|
2043
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1717
2044
|
UserProfileCard,
|
|
1718
2045
|
{
|
|
1719
2046
|
walletAddress,
|
|
@@ -1722,49 +2049,49 @@ function SettingsSheet({
|
|
|
1722
2049
|
memberSince
|
|
1723
2050
|
}
|
|
1724
2051
|
),
|
|
1725
|
-
/* @__PURE__ */ (0,
|
|
1726
|
-
onCopyAddress ? /* @__PURE__ */ (0,
|
|
2052
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native5.View, { style: [styles3.actionsCard, { backgroundColor: t.surface, borderColor: t.border }], children: [
|
|
2053
|
+
onCopyAddress ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1727
2054
|
import_react_native5.TouchableOpacity,
|
|
1728
2055
|
{
|
|
1729
2056
|
style: styles3.actionRow,
|
|
1730
2057
|
onPress: onCopyAddress,
|
|
1731
2058
|
activeOpacity: 0.7,
|
|
1732
2059
|
children: [
|
|
1733
|
-
/* @__PURE__ */ (0,
|
|
1734
|
-
/* @__PURE__ */ (0,
|
|
1735
|
-
/* @__PURE__ */ (0,
|
|
2060
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native5.View, { style: styles3.actionRowLeft, children: [
|
|
2061
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: [styles3.actionLabel, { color: t.text }], children: "Wallet Address" }),
|
|
2062
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: [styles3.actionValue, { color: t.textMuted }], children: truncateAddress2(walletAddress) })
|
|
1736
2063
|
] }),
|
|
1737
|
-
/* @__PURE__ */ (0,
|
|
2064
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: [styles3.copyLabel, { color: t.accent }], children: "Copy" })
|
|
1738
2065
|
]
|
|
1739
2066
|
}
|
|
1740
2067
|
) : null,
|
|
1741
|
-
onSupport ? /* @__PURE__ */ (0,
|
|
1742
|
-
onCopyAddress ? /* @__PURE__ */ (0,
|
|
1743
|
-
/* @__PURE__ */ (0,
|
|
2068
|
+
onSupport ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2069
|
+
onCopyAddress ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.View, { style: [styles3.separator, { backgroundColor: t.border }] }) : null,
|
|
2070
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1744
2071
|
import_react_native5.TouchableOpacity,
|
|
1745
2072
|
{
|
|
1746
2073
|
style: styles3.actionRow,
|
|
1747
2074
|
onPress: onSupport,
|
|
1748
2075
|
activeOpacity: 0.7,
|
|
1749
2076
|
children: [
|
|
1750
|
-
/* @__PURE__ */ (0,
|
|
1751
|
-
/* @__PURE__ */ (0,
|
|
2077
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: [styles3.actionLabel, { color: t.text }], children: "Help & Support" }),
|
|
2078
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: [styles3.chevron, { color: t.textMuted }], children: "\u203A" })
|
|
1752
2079
|
]
|
|
1753
2080
|
}
|
|
1754
2081
|
)
|
|
1755
2082
|
] }) : null
|
|
1756
2083
|
] }),
|
|
1757
|
-
/* @__PURE__ */ (0,
|
|
2084
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1758
2085
|
import_react_native5.TouchableOpacity,
|
|
1759
2086
|
{
|
|
1760
2087
|
style: [styles3.logoutButton, { borderColor: t.live }],
|
|
1761
2088
|
onPress: onLogout,
|
|
1762
2089
|
disabled: loggingOut,
|
|
1763
2090
|
activeOpacity: 0.7,
|
|
1764
|
-
children: loggingOut ? /* @__PURE__ */ (0,
|
|
2091
|
+
children: loggingOut ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.ActivityIndicator, { color: t.live, size: "small" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: [styles3.logoutText, { color: t.live }], children: "Log Out" })
|
|
1765
2092
|
}
|
|
1766
2093
|
),
|
|
1767
|
-
appVersion ? /* @__PURE__ */ (0,
|
|
2094
|
+
appVersion ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native5.Text, { style: [styles3.version, { color: t.textDim }], children: [
|
|
1768
2095
|
"v",
|
|
1769
2096
|
appVersion
|
|
1770
2097
|
] }) : null
|
|
@@ -1833,6 +2160,476 @@ var styles3 = import_react_native5.StyleSheet.create({
|
|
|
1833
2160
|
textAlign: "center"
|
|
1834
2161
|
}
|
|
1835
2162
|
});
|
|
2163
|
+
|
|
2164
|
+
// src/ui/game/GamePoster.tsx
|
|
2165
|
+
var import_react14 = require("react");
|
|
2166
|
+
var import_react_native6 = require("react-native");
|
|
2167
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2168
|
+
function computeCountdown(lockTimestamp) {
|
|
2169
|
+
if (!lockTimestamp) return "";
|
|
2170
|
+
const ts = typeof lockTimestamp === "string" ? parseInt(lockTimestamp) : lockTimestamp;
|
|
2171
|
+
const diff = ts * 1e3 - Date.now();
|
|
2172
|
+
if (diff <= 0) return "LIVE";
|
|
2173
|
+
const days = Math.floor(diff / 864e5);
|
|
2174
|
+
const hours = Math.floor(diff % 864e5 / 36e5);
|
|
2175
|
+
const mins = Math.floor(diff % 36e5 / 6e4);
|
|
2176
|
+
if (days > 0) return `${days}d ${hours}h`;
|
|
2177
|
+
if (hours > 0) return `${hours}h ${mins}m`;
|
|
2178
|
+
return `${mins}m`;
|
|
2179
|
+
}
|
|
2180
|
+
function GamePoster({ game, ImageComponent }) {
|
|
2181
|
+
const t = useDubsTheme();
|
|
2182
|
+
const Img = ImageComponent || require("react-native").Image;
|
|
2183
|
+
const opponents = game.opponents || [];
|
|
2184
|
+
const home = opponents[0];
|
|
2185
|
+
const away = opponents[1];
|
|
2186
|
+
const countdown = computeCountdown(game.lockTimestamp);
|
|
2187
|
+
const isLive = countdown === "LIVE";
|
|
2188
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native6.View, { style: styles4.container, children: [
|
|
2189
|
+
game.media?.poster ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2190
|
+
Img,
|
|
2191
|
+
{
|
|
2192
|
+
source: { uri: game.media.poster },
|
|
2193
|
+
style: styles4.image,
|
|
2194
|
+
resizeMode: "cover"
|
|
2195
|
+
}
|
|
2196
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { style: [styles4.image, { backgroundColor: t.surface }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native6.View, { style: styles4.fallback, children: [
|
|
2197
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TeamLogoInternal, { url: home?.imageUrl, size: 56, Img }),
|
|
2198
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: styles4.vs, children: "VS" }),
|
|
2199
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TeamLogoInternal, { url: away?.imageUrl, size: 56, Img })
|
|
2200
|
+
] }) }),
|
|
2201
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { style: styles4.overlay }),
|
|
2202
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native6.View, { style: styles4.teamNames, children: [
|
|
2203
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: styles4.teamNameText, numberOfLines: 1, children: home?.name || "Home" }),
|
|
2204
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: styles4.teamNameVs, children: "vs" }),
|
|
2205
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: styles4.teamNameText, numberOfLines: 1, children: away?.name || "Away" })
|
|
2206
|
+
] }),
|
|
2207
|
+
countdown ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { style: styles4.countdownPill, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: [styles4.countdownText, isLive && styles4.countdownLive], children: countdown }) }) : null,
|
|
2208
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { style: styles4.poolPill, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native6.Text, { style: styles4.poolText, children: [
|
|
2209
|
+
game.totalPool || 0,
|
|
2210
|
+
" SOL"
|
|
2211
|
+
] }) })
|
|
2212
|
+
] });
|
|
2213
|
+
}
|
|
2214
|
+
function TeamLogoInternal({ url, size, Img }) {
|
|
2215
|
+
const [failed, setFailed] = (0, import_react14.useState)(false);
|
|
2216
|
+
if (!url || failed) {
|
|
2217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { style: [styles4.logoPlaceholder, { width: size, height: size, borderRadius: size / 2 }] });
|
|
2218
|
+
}
|
|
2219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2220
|
+
Img,
|
|
2221
|
+
{
|
|
2222
|
+
source: { uri: url },
|
|
2223
|
+
style: { width: size, height: size, borderRadius: size / 2 },
|
|
2224
|
+
resizeMode: "contain",
|
|
2225
|
+
onError: () => setFailed(true)
|
|
2226
|
+
}
|
|
2227
|
+
);
|
|
2228
|
+
}
|
|
2229
|
+
var styles4 = import_react_native6.StyleSheet.create({
|
|
2230
|
+
container: {
|
|
2231
|
+
height: 200,
|
|
2232
|
+
borderRadius: 16,
|
|
2233
|
+
overflow: "hidden",
|
|
2234
|
+
position: "relative"
|
|
2235
|
+
},
|
|
2236
|
+
image: {
|
|
2237
|
+
...import_react_native6.StyleSheet.absoluteFillObject,
|
|
2238
|
+
justifyContent: "center",
|
|
2239
|
+
alignItems: "center"
|
|
2240
|
+
},
|
|
2241
|
+
overlay: {
|
|
2242
|
+
...import_react_native6.StyleSheet.absoluteFillObject,
|
|
2243
|
+
backgroundColor: "rgba(0,0,0,0.35)"
|
|
2244
|
+
},
|
|
2245
|
+
fallback: {
|
|
2246
|
+
flexDirection: "row",
|
|
2247
|
+
alignItems: "center",
|
|
2248
|
+
gap: 24,
|
|
2249
|
+
zIndex: 2
|
|
2250
|
+
},
|
|
2251
|
+
vs: {
|
|
2252
|
+
color: "#FFF",
|
|
2253
|
+
fontSize: 24,
|
|
2254
|
+
fontWeight: "900",
|
|
2255
|
+
zIndex: 2
|
|
2256
|
+
},
|
|
2257
|
+
logoPlaceholder: {
|
|
2258
|
+
backgroundColor: "rgba(255,255,255,0.15)",
|
|
2259
|
+
zIndex: 2
|
|
2260
|
+
},
|
|
2261
|
+
teamNames: {
|
|
2262
|
+
position: "absolute",
|
|
2263
|
+
top: 12,
|
|
2264
|
+
left: 12,
|
|
2265
|
+
right: 12,
|
|
2266
|
+
flexDirection: "row",
|
|
2267
|
+
alignItems: "center",
|
|
2268
|
+
justifyContent: "center",
|
|
2269
|
+
gap: 8
|
|
2270
|
+
},
|
|
2271
|
+
teamNameText: {
|
|
2272
|
+
color: "#FFF",
|
|
2273
|
+
fontSize: 14,
|
|
2274
|
+
fontWeight: "700",
|
|
2275
|
+
maxWidth: "40%"
|
|
2276
|
+
},
|
|
2277
|
+
teamNameVs: {
|
|
2278
|
+
color: "rgba(255,255,255,0.6)",
|
|
2279
|
+
fontSize: 12,
|
|
2280
|
+
fontWeight: "600"
|
|
2281
|
+
},
|
|
2282
|
+
countdownPill: {
|
|
2283
|
+
position: "absolute",
|
|
2284
|
+
bottom: 12,
|
|
2285
|
+
left: 12,
|
|
2286
|
+
backgroundColor: "rgba(0,0,0,0.65)",
|
|
2287
|
+
borderRadius: 8,
|
|
2288
|
+
paddingHorizontal: 10,
|
|
2289
|
+
paddingVertical: 5
|
|
2290
|
+
},
|
|
2291
|
+
countdownText: {
|
|
2292
|
+
color: "#FFF",
|
|
2293
|
+
fontSize: 13,
|
|
2294
|
+
fontWeight: "700"
|
|
2295
|
+
},
|
|
2296
|
+
countdownLive: {
|
|
2297
|
+
color: "#EF4444"
|
|
2298
|
+
},
|
|
2299
|
+
poolPill: {
|
|
2300
|
+
position: "absolute",
|
|
2301
|
+
bottom: 12,
|
|
2302
|
+
right: 12,
|
|
2303
|
+
backgroundColor: "#7C3AED",
|
|
2304
|
+
borderRadius: 8,
|
|
2305
|
+
paddingHorizontal: 12,
|
|
2306
|
+
paddingVertical: 5
|
|
2307
|
+
},
|
|
2308
|
+
poolText: {
|
|
2309
|
+
color: "#FFF",
|
|
2310
|
+
fontSize: 13,
|
|
2311
|
+
fontWeight: "800"
|
|
2312
|
+
}
|
|
2313
|
+
});
|
|
2314
|
+
|
|
2315
|
+
// src/ui/game/LivePoolsCard.tsx
|
|
2316
|
+
var import_react15 = require("react");
|
|
2317
|
+
var import_react_native7 = require("react-native");
|
|
2318
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2319
|
+
function LivePoolsCard({
|
|
2320
|
+
game,
|
|
2321
|
+
shortName,
|
|
2322
|
+
homeColor = "#3B82F6",
|
|
2323
|
+
awayColor = "#EF4444"
|
|
2324
|
+
}) {
|
|
2325
|
+
const t = useDubsTheme();
|
|
2326
|
+
const opponents = game.opponents || [];
|
|
2327
|
+
const homeName = shortName ? shortName(opponents[0]?.name) : opponents[0]?.name || "Home";
|
|
2328
|
+
const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
|
|
2329
|
+
const homePool = game.homePool || 0;
|
|
2330
|
+
const awayPool = game.awayPool || 0;
|
|
2331
|
+
const totalPool = game.totalPool || 0;
|
|
2332
|
+
const { homePercent, awayPercent, homeOdds, awayOdds } = (0, import_react15.useMemo)(() => {
|
|
2333
|
+
return {
|
|
2334
|
+
homePercent: totalPool > 0 ? homePool / totalPool * 100 : 50,
|
|
2335
|
+
awayPercent: totalPool > 0 ? awayPool / totalPool * 100 : 50,
|
|
2336
|
+
homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
|
|
2337
|
+
awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014"
|
|
2338
|
+
};
|
|
2339
|
+
}, [homePool, awayPool, totalPool]);
|
|
2340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: [styles5.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
|
|
2341
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: [styles5.title, { color: t.text }], children: "Live Pools" }),
|
|
2342
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.Text, { style: [styles5.total, { color: t.accent }], children: [
|
|
2343
|
+
totalPool,
|
|
2344
|
+
" SOL total"
|
|
2345
|
+
] }),
|
|
2346
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles5.bars, children: [
|
|
2347
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PoolBar, { name: homeName, amount: homePool, percent: homePercent, color: homeColor, t }),
|
|
2348
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PoolBar, { name: awayName, amount: awayPool, percent: awayPercent, color: awayColor, t })
|
|
2349
|
+
] }),
|
|
2350
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles5.oddsRow, children: [
|
|
2351
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.Text, { style: [styles5.oddsText, { color: t.textMuted }], children: [
|
|
2352
|
+
homeName,
|
|
2353
|
+
": ",
|
|
2354
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.Text, { style: { color: t.text, fontWeight: "700" }, children: [
|
|
2355
|
+
homeOdds,
|
|
2356
|
+
"x"
|
|
2357
|
+
] })
|
|
2358
|
+
] }),
|
|
2359
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.Text, { style: [styles5.oddsText, { color: t.textMuted }], children: [
|
|
2360
|
+
awayName,
|
|
2361
|
+
": ",
|
|
2362
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.Text, { style: { color: t.text, fontWeight: "700" }, children: [
|
|
2363
|
+
awayOdds,
|
|
2364
|
+
"x"
|
|
2365
|
+
] })
|
|
2366
|
+
] })
|
|
2367
|
+
] })
|
|
2368
|
+
] });
|
|
2369
|
+
}
|
|
2370
|
+
function PoolBar({ name, amount, percent, color, t }) {
|
|
2371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles5.barRow, children: [
|
|
2372
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: [styles5.barLabel, { color: t.textSecondary }], numberOfLines: 1, children: name }),
|
|
2373
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: [styles5.barTrack, { backgroundColor: t.border }], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: [styles5.barFill, { width: `${Math.max(percent, 2)}%`, backgroundColor: color }] }) }),
|
|
2374
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.Text, { style: [styles5.barAmount, { color: t.text }], children: [
|
|
2375
|
+
amount,
|
|
2376
|
+
" SOL"
|
|
2377
|
+
] })
|
|
2378
|
+
] });
|
|
2379
|
+
}
|
|
2380
|
+
var styles5 = import_react_native7.StyleSheet.create({
|
|
2381
|
+
card: { borderRadius: 16, borderWidth: 1, padding: 16 },
|
|
2382
|
+
title: { fontSize: 17, fontWeight: "700", marginBottom: 4 },
|
|
2383
|
+
total: { fontSize: 14, fontWeight: "600", marginBottom: 14 },
|
|
2384
|
+
bars: { gap: 10 },
|
|
2385
|
+
barRow: { flexDirection: "row", alignItems: "center", gap: 10 },
|
|
2386
|
+
barLabel: { width: 80, fontSize: 13, fontWeight: "600" },
|
|
2387
|
+
barTrack: { flex: 1, height: 10, borderRadius: 5, overflow: "hidden" },
|
|
2388
|
+
barFill: { height: "100%", borderRadius: 5 },
|
|
2389
|
+
barAmount: { width: 70, textAlign: "right", fontSize: 13, fontWeight: "700" },
|
|
2390
|
+
oddsRow: { flexDirection: "row", justifyContent: "space-between", marginTop: 12 },
|
|
2391
|
+
oddsText: { fontSize: 12 }
|
|
2392
|
+
});
|
|
2393
|
+
|
|
2394
|
+
// src/ui/game/PickWinnerCard.tsx
|
|
2395
|
+
var import_react16 = require("react");
|
|
2396
|
+
var import_react_native8 = require("react-native");
|
|
2397
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2398
|
+
function PickWinnerCard({
|
|
2399
|
+
game,
|
|
2400
|
+
selectedTeam,
|
|
2401
|
+
onSelect,
|
|
2402
|
+
shortName,
|
|
2403
|
+
homeColor = "#3B82F6",
|
|
2404
|
+
awayColor = "#EF4444",
|
|
2405
|
+
ImageComponent
|
|
2406
|
+
}) {
|
|
2407
|
+
const t = useDubsTheme();
|
|
2408
|
+
const opponents = game.opponents || [];
|
|
2409
|
+
const bettors = game.bettors || [];
|
|
2410
|
+
const totalPool = game.totalPool || 0;
|
|
2411
|
+
const homePool = game.homePool || 0;
|
|
2412
|
+
const awayPool = game.awayPool || 0;
|
|
2413
|
+
const { homeOdds, awayOdds, homeBets, awayBets } = (0, import_react16.useMemo)(() => ({
|
|
2414
|
+
homeOdds: homePool > 0 ? (totalPool / homePool).toFixed(2) : "\u2014",
|
|
2415
|
+
awayOdds: awayPool > 0 ? (totalPool / awayPool).toFixed(2) : "\u2014",
|
|
2416
|
+
homeBets: bettors.filter((b) => b.team === "home").length,
|
|
2417
|
+
awayBets: bettors.filter((b) => b.team === "away").length
|
|
2418
|
+
}), [totalPool, homePool, awayPool, bettors]);
|
|
2419
|
+
const homeName = shortName ? shortName(opponents[0]?.name) : opponents[0]?.name || "Home";
|
|
2420
|
+
const awayName = shortName ? shortName(opponents[1]?.name) : opponents[1]?.name || "Away";
|
|
2421
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: [styles6.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
|
|
2422
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: [styles6.title, { color: t.text }], children: "Pick Your Winner" }),
|
|
2423
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: styles6.row, children: [
|
|
2424
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2425
|
+
TeamOption,
|
|
2426
|
+
{
|
|
2427
|
+
name: homeName,
|
|
2428
|
+
imageUrl: opponents[0]?.imageUrl,
|
|
2429
|
+
odds: homeOdds,
|
|
2430
|
+
bets: homeBets,
|
|
2431
|
+
color: homeColor,
|
|
2432
|
+
selected: selectedTeam === "home",
|
|
2433
|
+
onPress: () => onSelect("home"),
|
|
2434
|
+
ImageComponent,
|
|
2435
|
+
t
|
|
2436
|
+
}
|
|
2437
|
+
),
|
|
2438
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2439
|
+
TeamOption,
|
|
2440
|
+
{
|
|
2441
|
+
name: awayName,
|
|
2442
|
+
imageUrl: opponents[1]?.imageUrl,
|
|
2443
|
+
odds: awayOdds,
|
|
2444
|
+
bets: awayBets,
|
|
2445
|
+
color: awayColor,
|
|
2446
|
+
selected: selectedTeam === "away",
|
|
2447
|
+
onPress: () => onSelect("away"),
|
|
2448
|
+
ImageComponent,
|
|
2449
|
+
t
|
|
2450
|
+
}
|
|
2451
|
+
)
|
|
2452
|
+
] })
|
|
2453
|
+
] });
|
|
2454
|
+
}
|
|
2455
|
+
function TeamOption({
|
|
2456
|
+
name,
|
|
2457
|
+
imageUrl,
|
|
2458
|
+
odds,
|
|
2459
|
+
bets,
|
|
2460
|
+
color,
|
|
2461
|
+
selected,
|
|
2462
|
+
onPress,
|
|
2463
|
+
ImageComponent,
|
|
2464
|
+
t
|
|
2465
|
+
}) {
|
|
2466
|
+
const [imgFailed, setImgFailed] = (0, import_react16.useState)(false);
|
|
2467
|
+
const Img = ImageComponent || require("react-native").Image;
|
|
2468
|
+
const showImage = imageUrl && !imgFailed;
|
|
2469
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2470
|
+
import_react_native8.TouchableOpacity,
|
|
2471
|
+
{
|
|
2472
|
+
style: [styles6.option, { borderColor: selected ? color : t.border, backgroundColor: selected ? color + "15" : t.background }],
|
|
2473
|
+
onPress,
|
|
2474
|
+
activeOpacity: 0.7,
|
|
2475
|
+
children: [
|
|
2476
|
+
showImage ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Img, { source: { uri: imageUrl }, style: styles6.logo, resizeMode: "contain", onError: () => setImgFailed(true) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: [styles6.logo, styles6.logoPlaceholder] }),
|
|
2477
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: [styles6.name, { color: t.text }], numberOfLines: 1, children: name }),
|
|
2478
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.Text, { style: [styles6.odds, { color }], children: [
|
|
2479
|
+
odds,
|
|
2480
|
+
"x"
|
|
2481
|
+
] }),
|
|
2482
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.Text, { style: [styles6.bets, { color: t.textMuted }], children: [
|
|
2483
|
+
bets,
|
|
2484
|
+
" ",
|
|
2485
|
+
bets === 1 ? "bet" : "bets"
|
|
2486
|
+
] }),
|
|
2487
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: [styles6.badge, { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles6.badgeText, children: "Selected" }) })
|
|
2488
|
+
]
|
|
2489
|
+
}
|
|
2490
|
+
);
|
|
2491
|
+
}
|
|
2492
|
+
var styles6 = import_react_native8.StyleSheet.create({
|
|
2493
|
+
card: { borderRadius: 16, borderWidth: 1, padding: 16 },
|
|
2494
|
+
title: { fontSize: 17, fontWeight: "700", marginBottom: 12 },
|
|
2495
|
+
row: { flexDirection: "row", gap: 12 },
|
|
2496
|
+
option: { flex: 1, borderWidth: 2, borderRadius: 16, padding: 16, alignItems: "center", gap: 8 },
|
|
2497
|
+
logo: { width: 48, height: 48, borderRadius: 24 },
|
|
2498
|
+
logoPlaceholder: { backgroundColor: "rgba(128,128,128,0.2)" },
|
|
2499
|
+
name: { fontSize: 15, fontWeight: "700" },
|
|
2500
|
+
odds: { fontSize: 20, fontWeight: "800" },
|
|
2501
|
+
bets: { fontSize: 12 },
|
|
2502
|
+
badge: { borderRadius: 8, paddingHorizontal: 12, paddingVertical: 4, marginTop: 4 },
|
|
2503
|
+
badgeText: { color: "#FFF", fontSize: 12, fontWeight: "700" }
|
|
2504
|
+
});
|
|
2505
|
+
|
|
2506
|
+
// src/ui/game/PlayersCard.tsx
|
|
2507
|
+
var import_react17 = require("react");
|
|
2508
|
+
var import_react_native9 = require("react-native");
|
|
2509
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2510
|
+
function truncateWallet(addr, chars) {
|
|
2511
|
+
if (addr.length <= chars * 2 + 3) return addr;
|
|
2512
|
+
return `${addr.slice(0, chars)}...${addr.slice(-chars)}`;
|
|
2513
|
+
}
|
|
2514
|
+
function PlayersCard({
|
|
2515
|
+
game,
|
|
2516
|
+
truncateChars = 4,
|
|
2517
|
+
homeColor = "#3B82F6",
|
|
2518
|
+
awayColor = "#EF4444",
|
|
2519
|
+
drawColor = "#A855F7",
|
|
2520
|
+
ImageComponent
|
|
2521
|
+
}) {
|
|
2522
|
+
const t = useDubsTheme();
|
|
2523
|
+
const bettors = game.bettors || [];
|
|
2524
|
+
const dotColor = (team) => {
|
|
2525
|
+
if (team === "home") return homeColor;
|
|
2526
|
+
if (team === "away") return awayColor;
|
|
2527
|
+
return drawColor;
|
|
2528
|
+
};
|
|
2529
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native9.View, { style: [styles7.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
|
|
2530
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native9.Text, { style: [styles7.title, { color: t.text }], children: [
|
|
2531
|
+
"Players",
|
|
2532
|
+
bettors.length > 0 ? ` (${bettors.length})` : ""
|
|
2533
|
+
] }),
|
|
2534
|
+
bettors.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.Text, { style: [styles7.empty, { color: t.textMuted }], children: "No players yet \u2014 be the first!" }) : bettors.map((b, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2535
|
+
BettorRow,
|
|
2536
|
+
{
|
|
2537
|
+
bettor: b,
|
|
2538
|
+
dotColor: dotColor(b.team),
|
|
2539
|
+
truncateChars,
|
|
2540
|
+
isFirst: i === 0,
|
|
2541
|
+
ImageComponent,
|
|
2542
|
+
t
|
|
2543
|
+
},
|
|
2544
|
+
`${b.wallet}-${i}`
|
|
2545
|
+
))
|
|
2546
|
+
] });
|
|
2547
|
+
}
|
|
2548
|
+
function BettorRow({
|
|
2549
|
+
bettor,
|
|
2550
|
+
dotColor,
|
|
2551
|
+
truncateChars,
|
|
2552
|
+
isFirst,
|
|
2553
|
+
ImageComponent,
|
|
2554
|
+
t
|
|
2555
|
+
}) {
|
|
2556
|
+
const [imgFailed, setImgFailed] = (0, import_react17.useState)(false);
|
|
2557
|
+
const Img = ImageComponent || require("react-native").Image;
|
|
2558
|
+
const showAvatar = bettor.avatar && !imgFailed;
|
|
2559
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native9.View, { style: [styles7.row, !isFirst && { borderTopColor: t.border, borderTopWidth: 1 }], children: [
|
|
2560
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.View, { style: [styles7.dot, { backgroundColor: dotColor }] }),
|
|
2561
|
+
showAvatar ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Img, { source: { uri: bettor.avatar }, style: styles7.avatar, resizeMode: "cover", onError: () => setImgFailed(true) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.View, { style: [styles7.avatar, styles7.avatarPlaceholder] }),
|
|
2562
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.View, { style: styles7.nameCol, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.Text, { style: [styles7.username, { color: t.text }], numberOfLines: 1, children: bettor.username || truncateWallet(bettor.wallet, truncateChars) }) }),
|
|
2563
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native9.Text, { style: [styles7.amount, { color: t.textSecondary }], children: [
|
|
2564
|
+
bettor.amount,
|
|
2565
|
+
" SOL"
|
|
2566
|
+
] })
|
|
2567
|
+
] });
|
|
2568
|
+
}
|
|
2569
|
+
var styles7 = import_react_native9.StyleSheet.create({
|
|
2570
|
+
card: { borderRadius: 16, borderWidth: 1, padding: 16 },
|
|
2571
|
+
title: { fontSize: 17, fontWeight: "700", marginBottom: 12 },
|
|
2572
|
+
empty: { fontSize: 14, textAlign: "center", paddingVertical: 16 },
|
|
2573
|
+
row: { flexDirection: "row", alignItems: "center", paddingVertical: 10, gap: 10 },
|
|
2574
|
+
dot: { width: 8, height: 8, borderRadius: 4 },
|
|
2575
|
+
avatar: { width: 28, height: 28, borderRadius: 14 },
|
|
2576
|
+
avatarPlaceholder: { backgroundColor: "rgba(128,128,128,0.2)" },
|
|
2577
|
+
nameCol: { flex: 1 },
|
|
2578
|
+
username: { fontSize: 14, fontWeight: "600" },
|
|
2579
|
+
amount: { fontSize: 13, fontWeight: "700" }
|
|
2580
|
+
});
|
|
2581
|
+
|
|
2582
|
+
// src/ui/game/JoinGameButton.tsx
|
|
2583
|
+
var import_react18 = require("react");
|
|
2584
|
+
var import_react_native10 = require("react-native");
|
|
2585
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2586
|
+
var STATUS_LABELS = {
|
|
2587
|
+
building: "Building transaction...",
|
|
2588
|
+
signing: "Approve in wallet...",
|
|
2589
|
+
confirming: "Confirming on-chain...",
|
|
2590
|
+
saving: "Saving..."
|
|
2591
|
+
};
|
|
2592
|
+
function JoinGameButton({ game, walletAddress, selectedTeam, status, onJoin }) {
|
|
2593
|
+
const t = useDubsTheme();
|
|
2594
|
+
const alreadyJoined = (0, import_react18.useMemo)(() => {
|
|
2595
|
+
if (!walletAddress) return false;
|
|
2596
|
+
return (game.bettors || []).some((b) => b.wallet === walletAddress);
|
|
2597
|
+
}, [game.bettors, walletAddress]);
|
|
2598
|
+
if (alreadyJoined || game.isLocked || game.isResolved) return null;
|
|
2599
|
+
const isJoining = status !== "idle" && status !== "success" && status !== "error";
|
|
2600
|
+
const statusLabel = STATUS_LABELS[status] || "";
|
|
2601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native10.View, { style: [styles8.bar, { backgroundColor: t.background, borderTopColor: t.border }], children: [
|
|
2602
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native10.View, { style: styles8.buyInRow, children: [
|
|
2603
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.Text, { style: [styles8.buyInLabel, { color: t.textMuted }], children: "Buy-in" }),
|
|
2604
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native10.Text, { style: [styles8.buyInValue, { color: t.text }], children: [
|
|
2605
|
+
game.buyIn,
|
|
2606
|
+
" SOL"
|
|
2607
|
+
] })
|
|
2608
|
+
] }),
|
|
2609
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2610
|
+
import_react_native10.TouchableOpacity,
|
|
2611
|
+
{
|
|
2612
|
+
style: [styles8.button, { backgroundColor: selectedTeam ? "#22D3EE" : t.border }],
|
|
2613
|
+
disabled: !selectedTeam || isJoining,
|
|
2614
|
+
onPress: onJoin,
|
|
2615
|
+
activeOpacity: 0.8,
|
|
2616
|
+
children: isJoining ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native10.View, { style: styles8.joiningRow, children: [
|
|
2617
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.ActivityIndicator, { size: "small", color: "#000" }),
|
|
2618
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.Text, { style: styles8.buttonText, children: statusLabel })
|
|
2619
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.Text, { style: [styles8.buttonText, !selectedTeam && { color: t.textMuted }], children: selectedTeam ? `Join Bet \u2014 ${game.buyIn} SOL` : "Pick a team to bet" })
|
|
2620
|
+
}
|
|
2621
|
+
)
|
|
2622
|
+
] });
|
|
2623
|
+
}
|
|
2624
|
+
var styles8 = import_react_native10.StyleSheet.create({
|
|
2625
|
+
bar: { position: "absolute", bottom: 0, left: 0, right: 0, paddingHorizontal: 16, paddingTop: 12, paddingBottom: 36, borderTopWidth: 1 },
|
|
2626
|
+
buyInRow: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", marginBottom: 10 },
|
|
2627
|
+
buyInLabel: { fontSize: 13 },
|
|
2628
|
+
buyInValue: { fontSize: 15, fontWeight: "800" },
|
|
2629
|
+
button: { borderRadius: 14, paddingVertical: 16, alignItems: "center" },
|
|
2630
|
+
buttonText: { color: "#000", fontSize: 16, fontWeight: "800" },
|
|
2631
|
+
joiningRow: { flexDirection: "row", alignItems: "center", gap: 10 }
|
|
2632
|
+
});
|
|
1836
2633
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1837
2634
|
0 && (module.exports = {
|
|
1838
2635
|
AuthGate,
|
|
@@ -1842,12 +2639,19 @@ var styles3 = import_react_native5.StyleSheet.create({
|
|
|
1842
2639
|
DubsApiError,
|
|
1843
2640
|
DubsClient,
|
|
1844
2641
|
DubsProvider,
|
|
2642
|
+
GamePoster,
|
|
2643
|
+
JoinGameButton,
|
|
2644
|
+
LivePoolsCard,
|
|
1845
2645
|
MwaWalletAdapter,
|
|
2646
|
+
NETWORK_CONFIG,
|
|
2647
|
+
PickWinnerCard,
|
|
2648
|
+
PlayersCard,
|
|
1846
2649
|
SOLANA_PROGRAM_ERRORS,
|
|
2650
|
+
STORAGE_KEYS,
|
|
1847
2651
|
SettingsSheet,
|
|
1848
2652
|
UserProfileCard,
|
|
2653
|
+
createSecureStoreStorage,
|
|
1849
2654
|
parseSolanaError,
|
|
1850
|
-
pollTransactionConfirmation,
|
|
1851
2655
|
signAndSendBase64Transaction,
|
|
1852
2656
|
useAuth,
|
|
1853
2657
|
useClaim,
|