@dubsdotapp/expo 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +45 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.js +501 -62
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +482 -34
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +32 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useCreateCustomGame.ts +81 -0
- package/src/index.ts +6 -1
- package/src/types.ts +18 -0
- package/src/ui/game/CreateCustomGameSheet.tsx +425 -0
- package/src/ui/game/index.ts +2 -0
- package/src/ui/index.ts +2 -1
package/dist/index.mjs
CHANGED
|
@@ -266,6 +266,33 @@ var DubsClient = class {
|
|
|
266
266
|
message: res.message
|
|
267
267
|
};
|
|
268
268
|
}
|
|
269
|
+
// ── Custom Game Lifecycle (game_mode=6) ──
|
|
270
|
+
async createCustomGame(params) {
|
|
271
|
+
const res = await this.request(
|
|
272
|
+
"POST",
|
|
273
|
+
"/games/custom/create",
|
|
274
|
+
params
|
|
275
|
+
);
|
|
276
|
+
return {
|
|
277
|
+
gameId: res.gameId,
|
|
278
|
+
gameAddress: res.gameAddress,
|
|
279
|
+
transaction: res.transaction,
|
|
280
|
+
lockTimestamp: res.lockTimestamp
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
async confirmCustomGame(params) {
|
|
284
|
+
const res = await this.request(
|
|
285
|
+
"POST",
|
|
286
|
+
"/games/custom/confirm",
|
|
287
|
+
params
|
|
288
|
+
);
|
|
289
|
+
return {
|
|
290
|
+
gameId: res.gameId,
|
|
291
|
+
signature: res.signature,
|
|
292
|
+
explorerUrl: res.explorerUrl,
|
|
293
|
+
message: res.message
|
|
294
|
+
};
|
|
295
|
+
}
|
|
269
296
|
async buildClaimTransaction(params) {
|
|
270
297
|
const res = await this.request(
|
|
271
298
|
"POST",
|
|
@@ -461,7 +488,7 @@ function createSecureStoreStorage() {
|
|
|
461
488
|
}
|
|
462
489
|
|
|
463
490
|
// src/provider.tsx
|
|
464
|
-
import { createContext as createContext3, useContext as useContext3, useMemo, useCallback as
|
|
491
|
+
import { createContext as createContext3, useContext as useContext3, useMemo, useCallback as useCallback12, useState as useState12, useEffect as useEffect7 } from "react";
|
|
465
492
|
import { Connection } from "@solana/web3.js";
|
|
466
493
|
|
|
467
494
|
// src/managed-wallet.tsx
|
|
@@ -856,7 +883,7 @@ function ManagedWalletProvider({
|
|
|
856
883
|
}
|
|
857
884
|
|
|
858
885
|
// src/ui/AuthGate.tsx
|
|
859
|
-
import React2, { useState as
|
|
886
|
+
import React2, { useState as useState11, useEffect as useEffect6, useRef as useRef3, useCallback as useCallback11 } from "react";
|
|
860
887
|
import {
|
|
861
888
|
View as View2,
|
|
862
889
|
Text as Text2,
|
|
@@ -1165,8 +1192,69 @@ function useClaim() {
|
|
|
1165
1192
|
return { execute, status, error, data, reset };
|
|
1166
1193
|
}
|
|
1167
1194
|
|
|
1195
|
+
// src/hooks/useCreateCustomGame.ts
|
|
1196
|
+
import { useState as useState9, useCallback as useCallback9 } from "react";
|
|
1197
|
+
function useCreateCustomGame() {
|
|
1198
|
+
const { client, wallet } = useDubs();
|
|
1199
|
+
const [status, setStatus] = useState9("idle");
|
|
1200
|
+
const [error, setError] = useState9(null);
|
|
1201
|
+
const [data, setData] = useState9(null);
|
|
1202
|
+
const reset = useCallback9(() => {
|
|
1203
|
+
setStatus("idle");
|
|
1204
|
+
setError(null);
|
|
1205
|
+
setData(null);
|
|
1206
|
+
}, []);
|
|
1207
|
+
const execute = useCallback9(async (params) => {
|
|
1208
|
+
setStatus("building");
|
|
1209
|
+
setError(null);
|
|
1210
|
+
setData(null);
|
|
1211
|
+
try {
|
|
1212
|
+
console.log("[useCreateCustomGame] Step 1: Building transaction...");
|
|
1213
|
+
const createResult = await client.createCustomGame(params);
|
|
1214
|
+
console.log("[useCreateCustomGame] Step 1 done:", { gameId: createResult.gameId, gameAddress: createResult.gameAddress });
|
|
1215
|
+
setStatus("signing");
|
|
1216
|
+
console.log("[useCreateCustomGame] Step 2: Signing and sending...");
|
|
1217
|
+
const signature = await signAndSendBase64Transaction(
|
|
1218
|
+
createResult.transaction,
|
|
1219
|
+
wallet
|
|
1220
|
+
);
|
|
1221
|
+
console.log("[useCreateCustomGame] Step 2 done. Signature:", signature);
|
|
1222
|
+
setStatus("confirming");
|
|
1223
|
+
console.log("[useCreateCustomGame] Step 3: Confirming with backend...");
|
|
1224
|
+
await client.confirmCustomGame({
|
|
1225
|
+
gameId: createResult.gameId,
|
|
1226
|
+
playerWallet: params.playerWallet,
|
|
1227
|
+
signature,
|
|
1228
|
+
teamChoice: params.teamChoice,
|
|
1229
|
+
wagerAmount: params.wagerAmount,
|
|
1230
|
+
role: "creator",
|
|
1231
|
+
gameAddress: createResult.gameAddress
|
|
1232
|
+
});
|
|
1233
|
+
console.log("[useCreateCustomGame] Step 3 done.");
|
|
1234
|
+
const explorerUrl = `https://solscan.io/tx/${signature}`;
|
|
1235
|
+
const result = {
|
|
1236
|
+
gameId: createResult.gameId,
|
|
1237
|
+
gameAddress: createResult.gameAddress,
|
|
1238
|
+
signature,
|
|
1239
|
+
explorerUrl
|
|
1240
|
+
};
|
|
1241
|
+
setData(result);
|
|
1242
|
+
setStatus("success");
|
|
1243
|
+
console.log("[useCreateCustomGame] Complete!");
|
|
1244
|
+
return result;
|
|
1245
|
+
} catch (err) {
|
|
1246
|
+
console.error("[useCreateCustomGame] FAILED:", err);
|
|
1247
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
1248
|
+
setError(error2);
|
|
1249
|
+
setStatus("error");
|
|
1250
|
+
throw error2;
|
|
1251
|
+
}
|
|
1252
|
+
}, [client, wallet]);
|
|
1253
|
+
return { execute, status, error, data, reset };
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1168
1256
|
// src/hooks/useAuth.ts
|
|
1169
|
-
import { useState as
|
|
1257
|
+
import { useState as useState10, useCallback as useCallback10, useRef as useRef2, useContext as useContext2 } from "react";
|
|
1170
1258
|
import bs58 from "bs58";
|
|
1171
1259
|
|
|
1172
1260
|
// src/auth-context.ts
|
|
@@ -1177,12 +1265,12 @@ var AuthContext = createContext2(null);
|
|
|
1177
1265
|
function useAuth() {
|
|
1178
1266
|
const sharedAuth = useContext2(AuthContext);
|
|
1179
1267
|
const { client, wallet } = useDubs();
|
|
1180
|
-
const [status, setStatus] =
|
|
1181
|
-
const [user, setUser] =
|
|
1182
|
-
const [token, setToken] =
|
|
1183
|
-
const [error, setError] =
|
|
1268
|
+
const [status, setStatus] = useState10("idle");
|
|
1269
|
+
const [user, setUser] = useState10(null);
|
|
1270
|
+
const [token, setToken] = useState10(null);
|
|
1271
|
+
const [error, setError] = useState10(null);
|
|
1184
1272
|
const pendingAuth = useRef2(null);
|
|
1185
|
-
const reset =
|
|
1273
|
+
const reset = useCallback10(() => {
|
|
1186
1274
|
setStatus("idle");
|
|
1187
1275
|
setUser(null);
|
|
1188
1276
|
setToken(null);
|
|
@@ -1190,7 +1278,7 @@ function useAuth() {
|
|
|
1190
1278
|
pendingAuth.current = null;
|
|
1191
1279
|
client.setToken(null);
|
|
1192
1280
|
}, [client]);
|
|
1193
|
-
const authenticate =
|
|
1281
|
+
const authenticate = useCallback10(async () => {
|
|
1194
1282
|
try {
|
|
1195
1283
|
if (!wallet.publicKey) {
|
|
1196
1284
|
throw new Error("Wallet not connected");
|
|
@@ -1221,7 +1309,7 @@ function useAuth() {
|
|
|
1221
1309
|
setStatus("error");
|
|
1222
1310
|
}
|
|
1223
1311
|
}, [client, wallet]);
|
|
1224
|
-
const register =
|
|
1312
|
+
const register = useCallback10(async (username, referralCode, avatarUrl) => {
|
|
1225
1313
|
try {
|
|
1226
1314
|
const pending = pendingAuth.current;
|
|
1227
1315
|
if (!pending) {
|
|
@@ -1247,7 +1335,7 @@ function useAuth() {
|
|
|
1247
1335
|
setStatus("error");
|
|
1248
1336
|
}
|
|
1249
1337
|
}, [client]);
|
|
1250
|
-
const logout =
|
|
1338
|
+
const logout = useCallback10(async () => {
|
|
1251
1339
|
try {
|
|
1252
1340
|
await client.logout();
|
|
1253
1341
|
} catch {
|
|
@@ -1258,7 +1346,7 @@ function useAuth() {
|
|
|
1258
1346
|
setError(null);
|
|
1259
1347
|
pendingAuth.current = null;
|
|
1260
1348
|
}, [client]);
|
|
1261
|
-
const restoreSession =
|
|
1349
|
+
const restoreSession = useCallback10(async (savedToken) => {
|
|
1262
1350
|
try {
|
|
1263
1351
|
client.setToken(savedToken);
|
|
1264
1352
|
const me = await client.getMe();
|
|
@@ -1317,8 +1405,8 @@ function AuthGate({
|
|
|
1317
1405
|
}) {
|
|
1318
1406
|
const { client } = useDubs();
|
|
1319
1407
|
const auth = useAuth();
|
|
1320
|
-
const [phase, setPhase] =
|
|
1321
|
-
const [registrationPhase, setRegistrationPhase] =
|
|
1408
|
+
const [phase, setPhase] = useState11("init");
|
|
1409
|
+
const [registrationPhase, setRegistrationPhase] = useState11(false);
|
|
1322
1410
|
useEffect6(() => {
|
|
1323
1411
|
let cancelled = false;
|
|
1324
1412
|
(async () => {
|
|
@@ -1351,12 +1439,12 @@ function AuthGate({
|
|
|
1351
1439
|
useEffect6(() => {
|
|
1352
1440
|
if (auth.token) onSaveToken(auth.token);
|
|
1353
1441
|
}, [auth.token]);
|
|
1354
|
-
const retry =
|
|
1442
|
+
const retry = useCallback11(() => {
|
|
1355
1443
|
setRegistrationPhase(false);
|
|
1356
1444
|
auth.reset();
|
|
1357
1445
|
auth.authenticate();
|
|
1358
1446
|
}, [auth]);
|
|
1359
|
-
const handleRegister =
|
|
1447
|
+
const handleRegister = useCallback11(
|
|
1360
1448
|
(username, referralCode, avatarUrl) => {
|
|
1361
1449
|
auth.register(username, referralCode, avatarUrl);
|
|
1362
1450
|
},
|
|
@@ -1459,14 +1547,14 @@ function DefaultRegistrationScreen({
|
|
|
1459
1547
|
}) {
|
|
1460
1548
|
const t = useDubsTheme();
|
|
1461
1549
|
const accent = accentColor || t.accent;
|
|
1462
|
-
const [step, setStep] =
|
|
1463
|
-
const [avatarSeed, setAvatarSeed] =
|
|
1464
|
-
const [avatarStyle, setAvatarStyle] =
|
|
1465
|
-
const [showStyles, setShowStyles] =
|
|
1466
|
-
const [username, setUsername] =
|
|
1467
|
-
const [referralCode, setReferralCode] =
|
|
1468
|
-
const [checking, setChecking] =
|
|
1469
|
-
const [availability, setAvailability] =
|
|
1550
|
+
const [step, setStep] = useState11(0);
|
|
1551
|
+
const [avatarSeed, setAvatarSeed] = useState11(generateSeed);
|
|
1552
|
+
const [avatarStyle, setAvatarStyle] = useState11("adventurer");
|
|
1553
|
+
const [showStyles, setShowStyles] = useState11(false);
|
|
1554
|
+
const [username, setUsername] = useState11("");
|
|
1555
|
+
const [referralCode, setReferralCode] = useState11("");
|
|
1556
|
+
const [checking, setChecking] = useState11(false);
|
|
1557
|
+
const [availability, setAvailability] = useState11(null);
|
|
1470
1558
|
const debounceRef = useRef3(null);
|
|
1471
1559
|
const fadeAnim = useRef3(new Animated.Value(1)).current;
|
|
1472
1560
|
const slideAnim = useRef3(new Animated.Value(0)).current;
|
|
@@ -1494,7 +1582,7 @@ function DefaultRegistrationScreen({
|
|
|
1494
1582
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
1495
1583
|
};
|
|
1496
1584
|
}, [username, client]);
|
|
1497
|
-
const animateToStep =
|
|
1585
|
+
const animateToStep = useCallback11((newStep) => {
|
|
1498
1586
|
const dir = newStep > step ? 1 : -1;
|
|
1499
1587
|
Keyboard.dismiss();
|
|
1500
1588
|
Animated.parallel([
|
|
@@ -1816,7 +1904,7 @@ function DubsProvider({
|
|
|
1816
1904
|
const client = useMemo(() => new DubsClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
|
|
1817
1905
|
const connection = useMemo(() => new Connection(rpcUrl, { commitment: "confirmed" }), [rpcUrl]);
|
|
1818
1906
|
const storage = useMemo(() => tokenStorage || createSecureStoreStorage(), [tokenStorage]);
|
|
1819
|
-
const [uiConfig, setUiConfig] =
|
|
1907
|
+
const [uiConfig, setUiConfig] = useState12(null);
|
|
1820
1908
|
useEffect7(() => {
|
|
1821
1909
|
client.getAppConfig().then((config2) => {
|
|
1822
1910
|
console.log("[DubsProvider] UI config loaded:", JSON.stringify(config2));
|
|
@@ -1892,7 +1980,7 @@ function ManagedInner({
|
|
|
1892
1980
|
children
|
|
1893
1981
|
}) {
|
|
1894
1982
|
const managedDisconnect = useDisconnect();
|
|
1895
|
-
const disconnect =
|
|
1983
|
+
const disconnect = useCallback12(async () => {
|
|
1896
1984
|
client.setToken(null);
|
|
1897
1985
|
await managedDisconnect?.();
|
|
1898
1986
|
}, [client, managedDisconnect]);
|
|
@@ -1932,7 +2020,7 @@ function ExternalWalletProvider({
|
|
|
1932
2020
|
uiConfig,
|
|
1933
2021
|
children
|
|
1934
2022
|
}) {
|
|
1935
|
-
const disconnect =
|
|
2023
|
+
const disconnect = useCallback12(async () => {
|
|
1936
2024
|
client.setToken(null);
|
|
1937
2025
|
await storage.deleteItem(STORAGE_KEYS.JWT_TOKEN).catch(() => {
|
|
1938
2026
|
});
|
|
@@ -2195,7 +2283,7 @@ var styles3 = StyleSheet4.create({
|
|
|
2195
2283
|
});
|
|
2196
2284
|
|
|
2197
2285
|
// src/ui/game/GamePoster.tsx
|
|
2198
|
-
import { useState as
|
|
2286
|
+
import { useState as useState13 } from "react";
|
|
2199
2287
|
import { StyleSheet as StyleSheet5, View as View5, Text as Text5 } from "react-native";
|
|
2200
2288
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2201
2289
|
function computeCountdown(lockTimestamp) {
|
|
@@ -2245,7 +2333,7 @@ function GamePoster({ game, ImageComponent }) {
|
|
|
2245
2333
|
] });
|
|
2246
2334
|
}
|
|
2247
2335
|
function TeamLogoInternal({ url, size, Img }) {
|
|
2248
|
-
const [failed, setFailed] =
|
|
2336
|
+
const [failed, setFailed] = useState13(false);
|
|
2249
2337
|
if (!url || failed) {
|
|
2250
2338
|
return /* @__PURE__ */ jsx7(View5, { style: [styles4.logoPlaceholder, { width: size, height: size, borderRadius: size / 2 }] });
|
|
2251
2339
|
}
|
|
@@ -2425,7 +2513,7 @@ var styles5 = StyleSheet6.create({
|
|
|
2425
2513
|
});
|
|
2426
2514
|
|
|
2427
2515
|
// src/ui/game/PickWinnerCard.tsx
|
|
2428
|
-
import { useState as
|
|
2516
|
+
import { useState as useState14, useMemo as useMemo4 } from "react";
|
|
2429
2517
|
import { StyleSheet as StyleSheet7, View as View7, Text as Text7, TouchableOpacity as TouchableOpacity4 } from "react-native";
|
|
2430
2518
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2431
2519
|
function PickWinnerCard({
|
|
@@ -2496,7 +2584,7 @@ function TeamOption({
|
|
|
2496
2584
|
ImageComponent,
|
|
2497
2585
|
t
|
|
2498
2586
|
}) {
|
|
2499
|
-
const [imgFailed, setImgFailed] =
|
|
2587
|
+
const [imgFailed, setImgFailed] = useState14(false);
|
|
2500
2588
|
const Img = ImageComponent || __require("react-native").Image;
|
|
2501
2589
|
const showImage = imageUrl && !imgFailed;
|
|
2502
2590
|
return /* @__PURE__ */ jsxs7(
|
|
@@ -2537,7 +2625,7 @@ var styles6 = StyleSheet7.create({
|
|
|
2537
2625
|
});
|
|
2538
2626
|
|
|
2539
2627
|
// src/ui/game/PlayersCard.tsx
|
|
2540
|
-
import { useState as
|
|
2628
|
+
import { useState as useState15 } from "react";
|
|
2541
2629
|
import { StyleSheet as StyleSheet8, View as View8, Text as Text8 } from "react-native";
|
|
2542
2630
|
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2543
2631
|
function truncateWallet(addr, chars) {
|
|
@@ -2586,7 +2674,7 @@ function BettorRow({
|
|
|
2586
2674
|
ImageComponent,
|
|
2587
2675
|
t
|
|
2588
2676
|
}) {
|
|
2589
|
-
const [imgFailed, setImgFailed] =
|
|
2677
|
+
const [imgFailed, setImgFailed] = useState15(false);
|
|
2590
2678
|
const Img = ImageComponent || __require("react-native").Image;
|
|
2591
2679
|
const showAvatar = bettor.avatar && !imgFailed;
|
|
2592
2680
|
return /* @__PURE__ */ jsxs8(View8, { style: [styles7.row, !isFirst && { borderTopColor: t.border, borderTopWidth: 1 }], children: [
|
|
@@ -2663,9 +2751,368 @@ var styles8 = StyleSheet9.create({
|
|
|
2663
2751
|
buttonText: { color: "#000", fontSize: 16, fontWeight: "800" },
|
|
2664
2752
|
joiningRow: { flexDirection: "row", alignItems: "center", gap: 10 }
|
|
2665
2753
|
});
|
|
2754
|
+
|
|
2755
|
+
// src/ui/game/CreateCustomGameSheet.tsx
|
|
2756
|
+
import { useState as useState16, useEffect as useEffect8, useRef as useRef4, useCallback as useCallback13 } from "react";
|
|
2757
|
+
import {
|
|
2758
|
+
View as View10,
|
|
2759
|
+
Text as Text10,
|
|
2760
|
+
TextInput as TextInput2,
|
|
2761
|
+
TouchableOpacity as TouchableOpacity6,
|
|
2762
|
+
ActivityIndicator as ActivityIndicator5,
|
|
2763
|
+
Modal,
|
|
2764
|
+
Animated as Animated2,
|
|
2765
|
+
StyleSheet as StyleSheet10,
|
|
2766
|
+
KeyboardAvoidingView as KeyboardAvoidingView2,
|
|
2767
|
+
Platform as Platform2
|
|
2768
|
+
} from "react-native";
|
|
2769
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2770
|
+
var STATUS_LABELS2 = {
|
|
2771
|
+
building: "Building transaction...",
|
|
2772
|
+
signing: "Approve in wallet...",
|
|
2773
|
+
confirming: "Confirming...",
|
|
2774
|
+
success: "Game Created!"
|
|
2775
|
+
};
|
|
2776
|
+
function CreateCustomGameSheet({
|
|
2777
|
+
visible,
|
|
2778
|
+
onDismiss,
|
|
2779
|
+
title,
|
|
2780
|
+
maxPlayers = 2,
|
|
2781
|
+
fee = 5,
|
|
2782
|
+
presetAmounts = [0.01, 0.1, 0.5, 1],
|
|
2783
|
+
defaultAmount = 0.01,
|
|
2784
|
+
metadata,
|
|
2785
|
+
onSuccess,
|
|
2786
|
+
onError
|
|
2787
|
+
}) {
|
|
2788
|
+
const t = useDubsTheme();
|
|
2789
|
+
const { wallet } = useDubs();
|
|
2790
|
+
const mutation = useCreateCustomGame();
|
|
2791
|
+
const [selectedAmount, setSelectedAmount] = useState16(null);
|
|
2792
|
+
const [customAmount, setCustomAmount] = useState16("");
|
|
2793
|
+
const [isCustom, setIsCustom] = useState16(false);
|
|
2794
|
+
const overlayOpacity = useRef4(new Animated2.Value(0)).current;
|
|
2795
|
+
useEffect8(() => {
|
|
2796
|
+
Animated2.timing(overlayOpacity, {
|
|
2797
|
+
toValue: visible ? 1 : 0,
|
|
2798
|
+
duration: 250,
|
|
2799
|
+
useNativeDriver: true
|
|
2800
|
+
}).start();
|
|
2801
|
+
}, [visible, overlayOpacity]);
|
|
2802
|
+
useEffect8(() => {
|
|
2803
|
+
if (visible) {
|
|
2804
|
+
setSelectedAmount(defaultAmount ?? null);
|
|
2805
|
+
setCustomAmount("");
|
|
2806
|
+
setIsCustom(false);
|
|
2807
|
+
mutation.reset();
|
|
2808
|
+
}
|
|
2809
|
+
}, [visible]);
|
|
2810
|
+
useEffect8(() => {
|
|
2811
|
+
if (mutation.status === "success" && mutation.data) {
|
|
2812
|
+
onSuccess?.(mutation.data);
|
|
2813
|
+
const timer = setTimeout(() => {
|
|
2814
|
+
onDismiss();
|
|
2815
|
+
}, 1500);
|
|
2816
|
+
return () => clearTimeout(timer);
|
|
2817
|
+
}
|
|
2818
|
+
}, [mutation.status, mutation.data]);
|
|
2819
|
+
useEffect8(() => {
|
|
2820
|
+
if (mutation.status === "error" && mutation.error) {
|
|
2821
|
+
onError?.(mutation.error);
|
|
2822
|
+
}
|
|
2823
|
+
}, [mutation.status, mutation.error]);
|
|
2824
|
+
const handlePresetSelect = useCallback13((amount) => {
|
|
2825
|
+
setSelectedAmount(amount);
|
|
2826
|
+
setIsCustom(false);
|
|
2827
|
+
setCustomAmount("");
|
|
2828
|
+
}, []);
|
|
2829
|
+
const handleCustomSelect = useCallback13(() => {
|
|
2830
|
+
setIsCustom(true);
|
|
2831
|
+
setSelectedAmount(null);
|
|
2832
|
+
}, []);
|
|
2833
|
+
const handleCustomAmountChange = useCallback13((text) => {
|
|
2834
|
+
const cleaned = text.replace(/[^0-9.]/g, "").replace(/(\..*?)\..*/g, "$1");
|
|
2835
|
+
setCustomAmount(cleaned);
|
|
2836
|
+
const parsed = parseFloat(cleaned);
|
|
2837
|
+
setSelectedAmount(parsed > 0 ? parsed : null);
|
|
2838
|
+
}, []);
|
|
2839
|
+
const effectiveAmount = selectedAmount;
|
|
2840
|
+
const playerCount = maxPlayers || 2;
|
|
2841
|
+
const pot = effectiveAmount ? effectiveAmount * playerCount : 0;
|
|
2842
|
+
const winnerTakes = pot * (1 - fee / 100);
|
|
2843
|
+
const isMutating = mutation.status !== "idle" && mutation.status !== "success" && mutation.status !== "error";
|
|
2844
|
+
const canCreate = effectiveAmount !== null && effectiveAmount > 0 && !isMutating && mutation.status !== "success";
|
|
2845
|
+
const handleCreate = useCallback13(async () => {
|
|
2846
|
+
if (!effectiveAmount || !wallet.publicKey) return;
|
|
2847
|
+
try {
|
|
2848
|
+
await mutation.execute({
|
|
2849
|
+
playerWallet: wallet.publicKey.toBase58(),
|
|
2850
|
+
teamChoice: "home",
|
|
2851
|
+
wagerAmount: effectiveAmount,
|
|
2852
|
+
title,
|
|
2853
|
+
maxPlayers,
|
|
2854
|
+
metadata
|
|
2855
|
+
});
|
|
2856
|
+
} catch {
|
|
2857
|
+
}
|
|
2858
|
+
}, [effectiveAmount, wallet.publicKey, mutation.execute, title, maxPlayers, metadata]);
|
|
2859
|
+
const statusLabel = STATUS_LABELS2[mutation.status] || "";
|
|
2860
|
+
const playersLabel = playerCount === 2 ? "2 (1v1)" : `${playerCount} players`;
|
|
2861
|
+
return /* @__PURE__ */ jsxs10(
|
|
2862
|
+
Modal,
|
|
2863
|
+
{
|
|
2864
|
+
visible,
|
|
2865
|
+
animationType: "slide",
|
|
2866
|
+
transparent: true,
|
|
2867
|
+
onRequestClose: onDismiss,
|
|
2868
|
+
children: [
|
|
2869
|
+
/* @__PURE__ */ jsx12(Animated2.View, { style: [styles9.overlay, { opacity: overlayOpacity }], children: /* @__PURE__ */ jsx12(TouchableOpacity6, { style: styles9.overlayTap, activeOpacity: 1, onPress: onDismiss }) }),
|
|
2870
|
+
/* @__PURE__ */ jsx12(
|
|
2871
|
+
KeyboardAvoidingView2,
|
|
2872
|
+
{
|
|
2873
|
+
style: styles9.keyboardView,
|
|
2874
|
+
behavior: Platform2.OS === "ios" ? "padding" : void 0,
|
|
2875
|
+
children: /* @__PURE__ */ jsx12(View10, { style: styles9.sheetPositioner, children: /* @__PURE__ */ jsxs10(View10, { style: [styles9.sheet, { backgroundColor: t.background }], children: [
|
|
2876
|
+
/* @__PURE__ */ jsx12(View10, { style: styles9.handleRow, children: /* @__PURE__ */ jsx12(View10, { style: [styles9.handle, { backgroundColor: t.textMuted }] }) }),
|
|
2877
|
+
/* @__PURE__ */ jsxs10(View10, { style: styles9.header, children: [
|
|
2878
|
+
/* @__PURE__ */ jsx12(Text10, { style: [styles9.headerTitle, { color: t.text }], children: "New Game" }),
|
|
2879
|
+
/* @__PURE__ */ jsx12(TouchableOpacity6, { onPress: onDismiss, activeOpacity: 0.8, children: /* @__PURE__ */ jsx12(Text10, { style: [styles9.closeButton, { color: t.textMuted }], children: "\u2715" }) })
|
|
2880
|
+
] }),
|
|
2881
|
+
/* @__PURE__ */ jsxs10(View10, { style: styles9.section, children: [
|
|
2882
|
+
/* @__PURE__ */ jsx12(Text10, { style: [styles9.sectionLabel, { color: t.textSecondary }], children: "Buy-In Amount" }),
|
|
2883
|
+
/* @__PURE__ */ jsxs10(View10, { style: styles9.chipsRow, children: [
|
|
2884
|
+
presetAmounts.map((amount) => {
|
|
2885
|
+
const active = !isCustom && selectedAmount === amount;
|
|
2886
|
+
return /* @__PURE__ */ jsx12(
|
|
2887
|
+
TouchableOpacity6,
|
|
2888
|
+
{
|
|
2889
|
+
style: [
|
|
2890
|
+
styles9.chip,
|
|
2891
|
+
{ borderColor: active ? t.accent : t.border },
|
|
2892
|
+
active && { backgroundColor: t.accent }
|
|
2893
|
+
],
|
|
2894
|
+
onPress: () => handlePresetSelect(amount),
|
|
2895
|
+
activeOpacity: 0.8,
|
|
2896
|
+
children: /* @__PURE__ */ jsxs10(Text10, { style: [styles9.chipText, { color: active ? "#FFFFFF" : t.text }], children: [
|
|
2897
|
+
amount,
|
|
2898
|
+
" SOL"
|
|
2899
|
+
] })
|
|
2900
|
+
},
|
|
2901
|
+
amount
|
|
2902
|
+
);
|
|
2903
|
+
}),
|
|
2904
|
+
/* @__PURE__ */ jsx12(
|
|
2905
|
+
TouchableOpacity6,
|
|
2906
|
+
{
|
|
2907
|
+
style: [
|
|
2908
|
+
styles9.chip,
|
|
2909
|
+
{ borderColor: isCustom ? t.accent : t.border },
|
|
2910
|
+
isCustom && { backgroundColor: t.accent }
|
|
2911
|
+
],
|
|
2912
|
+
onPress: handleCustomSelect,
|
|
2913
|
+
activeOpacity: 0.8,
|
|
2914
|
+
children: /* @__PURE__ */ jsx12(Text10, { style: [styles9.chipText, { color: isCustom ? "#FFFFFF" : t.text }], children: "Custom" })
|
|
2915
|
+
}
|
|
2916
|
+
)
|
|
2917
|
+
] }),
|
|
2918
|
+
isCustom && /* @__PURE__ */ jsx12(
|
|
2919
|
+
TextInput2,
|
|
2920
|
+
{
|
|
2921
|
+
style: [styles9.input, { backgroundColor: t.surface, color: t.text, borderColor: t.accent }],
|
|
2922
|
+
placeholder: "Enter amount in SOL",
|
|
2923
|
+
placeholderTextColor: t.textDim,
|
|
2924
|
+
keyboardType: "decimal-pad",
|
|
2925
|
+
value: customAmount,
|
|
2926
|
+
onChangeText: handleCustomAmountChange,
|
|
2927
|
+
autoFocus: true
|
|
2928
|
+
}
|
|
2929
|
+
)
|
|
2930
|
+
] }),
|
|
2931
|
+
/* @__PURE__ */ jsxs10(View10, { style: [styles9.summaryCard, { backgroundColor: t.surface, borderColor: t.border }], children: [
|
|
2932
|
+
/* @__PURE__ */ jsxs10(View10, { style: styles9.summaryRow, children: [
|
|
2933
|
+
/* @__PURE__ */ jsx12(Text10, { style: [styles9.summaryLabel, { color: t.textMuted }], children: "Your buy-in" }),
|
|
2934
|
+
/* @__PURE__ */ jsx12(Text10, { style: [styles9.summaryValue, { color: t.text }], children: effectiveAmount ? `${effectiveAmount} SOL` : "\u2014" })
|
|
2935
|
+
] }),
|
|
2936
|
+
/* @__PURE__ */ jsx12(View10, { style: [styles9.summarySep, { backgroundColor: t.border }] }),
|
|
2937
|
+
/* @__PURE__ */ jsxs10(View10, { style: styles9.summaryRow, children: [
|
|
2938
|
+
/* @__PURE__ */ jsx12(Text10, { style: [styles9.summaryLabel, { color: t.textMuted }], children: "Players" }),
|
|
2939
|
+
/* @__PURE__ */ jsx12(Text10, { style: [styles9.summaryValue, { color: t.text }], children: playersLabel })
|
|
2940
|
+
] }),
|
|
2941
|
+
/* @__PURE__ */ jsx12(View10, { style: [styles9.summarySep, { backgroundColor: t.border }] }),
|
|
2942
|
+
/* @__PURE__ */ jsxs10(View10, { style: styles9.summaryRow, children: [
|
|
2943
|
+
/* @__PURE__ */ jsx12(Text10, { style: [styles9.summaryLabel, { color: t.textMuted }], children: "Winner Takes" }),
|
|
2944
|
+
/* @__PURE__ */ jsxs10(View10, { style: styles9.winnerCol, children: [
|
|
2945
|
+
/* @__PURE__ */ jsx12(Text10, { style: [styles9.summaryValue, { color: t.success }], children: effectiveAmount ? `${winnerTakes.toFixed(4)} SOL` : "\u2014" }),
|
|
2946
|
+
effectiveAmount ? /* @__PURE__ */ jsxs10(Text10, { style: [styles9.feeNote, { color: t.textDim }], children: [
|
|
2947
|
+
fee,
|
|
2948
|
+
"% platform fee"
|
|
2949
|
+
] }) : null
|
|
2950
|
+
] })
|
|
2951
|
+
] })
|
|
2952
|
+
] }),
|
|
2953
|
+
mutation.error && /* @__PURE__ */ jsx12(View10, { style: [styles9.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ jsx12(Text10, { style: [styles9.errorText, { color: t.errorText }], children: mutation.error.message }) }),
|
|
2954
|
+
/* @__PURE__ */ jsx12(
|
|
2955
|
+
TouchableOpacity6,
|
|
2956
|
+
{
|
|
2957
|
+
style: [
|
|
2958
|
+
styles9.ctaButton,
|
|
2959
|
+
{ backgroundColor: canCreate ? t.accent : t.border }
|
|
2960
|
+
],
|
|
2961
|
+
disabled: !canCreate,
|
|
2962
|
+
onPress: handleCreate,
|
|
2963
|
+
activeOpacity: 0.8,
|
|
2964
|
+
children: isMutating ? /* @__PURE__ */ jsxs10(View10, { style: styles9.ctaLoading, children: [
|
|
2965
|
+
/* @__PURE__ */ jsx12(ActivityIndicator5, { size: "small", color: "#FFFFFF" }),
|
|
2966
|
+
/* @__PURE__ */ jsx12(Text10, { style: styles9.ctaText, children: statusLabel })
|
|
2967
|
+
] }) : mutation.status === "success" ? /* @__PURE__ */ jsx12(Text10, { style: styles9.ctaText, children: STATUS_LABELS2.success }) : /* @__PURE__ */ jsx12(Text10, { style: [styles9.ctaText, !canCreate && { opacity: 0.5 }], children: effectiveAmount ? `Create Game \u2014 ${effectiveAmount} SOL` : "Select buy-in amount" })
|
|
2968
|
+
}
|
|
2969
|
+
)
|
|
2970
|
+
] }) })
|
|
2971
|
+
}
|
|
2972
|
+
)
|
|
2973
|
+
]
|
|
2974
|
+
}
|
|
2975
|
+
);
|
|
2976
|
+
}
|
|
2977
|
+
var styles9 = StyleSheet10.create({
|
|
2978
|
+
overlay: {
|
|
2979
|
+
...StyleSheet10.absoluteFillObject,
|
|
2980
|
+
backgroundColor: "rgba(0,0,0,0.5)"
|
|
2981
|
+
},
|
|
2982
|
+
overlayTap: {
|
|
2983
|
+
flex: 1
|
|
2984
|
+
},
|
|
2985
|
+
keyboardView: {
|
|
2986
|
+
flex: 1,
|
|
2987
|
+
justifyContent: "flex-end"
|
|
2988
|
+
},
|
|
2989
|
+
sheetPositioner: {
|
|
2990
|
+
justifyContent: "flex-end"
|
|
2991
|
+
},
|
|
2992
|
+
sheet: {
|
|
2993
|
+
borderTopLeftRadius: 24,
|
|
2994
|
+
borderTopRightRadius: 24,
|
|
2995
|
+
paddingHorizontal: 20,
|
|
2996
|
+
paddingBottom: 40
|
|
2997
|
+
},
|
|
2998
|
+
handleRow: {
|
|
2999
|
+
alignItems: "center",
|
|
3000
|
+
paddingTop: 10,
|
|
3001
|
+
paddingBottom: 8
|
|
3002
|
+
},
|
|
3003
|
+
handle: {
|
|
3004
|
+
width: 36,
|
|
3005
|
+
height: 4,
|
|
3006
|
+
borderRadius: 2,
|
|
3007
|
+
opacity: 0.4
|
|
3008
|
+
},
|
|
3009
|
+
header: {
|
|
3010
|
+
flexDirection: "row",
|
|
3011
|
+
alignItems: "center",
|
|
3012
|
+
justifyContent: "space-between",
|
|
3013
|
+
paddingVertical: 12
|
|
3014
|
+
},
|
|
3015
|
+
headerTitle: {
|
|
3016
|
+
fontSize: 20,
|
|
3017
|
+
fontWeight: "700"
|
|
3018
|
+
},
|
|
3019
|
+
closeButton: {
|
|
3020
|
+
fontSize: 20,
|
|
3021
|
+
padding: 4
|
|
3022
|
+
},
|
|
3023
|
+
section: {
|
|
3024
|
+
gap: 12,
|
|
3025
|
+
paddingTop: 8
|
|
3026
|
+
},
|
|
3027
|
+
sectionLabel: {
|
|
3028
|
+
fontSize: 15,
|
|
3029
|
+
fontWeight: "600"
|
|
3030
|
+
},
|
|
3031
|
+
chipsRow: {
|
|
3032
|
+
flexDirection: "row",
|
|
3033
|
+
flexWrap: "wrap",
|
|
3034
|
+
gap: 10
|
|
3035
|
+
},
|
|
3036
|
+
chip: {
|
|
3037
|
+
paddingHorizontal: 18,
|
|
3038
|
+
paddingVertical: 10,
|
|
3039
|
+
borderRadius: 14,
|
|
3040
|
+
borderWidth: 1.5
|
|
3041
|
+
},
|
|
3042
|
+
chipText: {
|
|
3043
|
+
fontSize: 15,
|
|
3044
|
+
fontWeight: "600"
|
|
3045
|
+
},
|
|
3046
|
+
input: {
|
|
3047
|
+
height: 56,
|
|
3048
|
+
borderRadius: 16,
|
|
3049
|
+
borderWidth: 1.5,
|
|
3050
|
+
paddingHorizontal: 16,
|
|
3051
|
+
fontSize: 16
|
|
3052
|
+
},
|
|
3053
|
+
summaryCard: {
|
|
3054
|
+
marginTop: 20,
|
|
3055
|
+
borderRadius: 16,
|
|
3056
|
+
borderWidth: 1,
|
|
3057
|
+
overflow: "hidden"
|
|
3058
|
+
},
|
|
3059
|
+
summaryRow: {
|
|
3060
|
+
flexDirection: "row",
|
|
3061
|
+
alignItems: "center",
|
|
3062
|
+
justifyContent: "space-between",
|
|
3063
|
+
paddingHorizontal: 16,
|
|
3064
|
+
paddingVertical: 14
|
|
3065
|
+
},
|
|
3066
|
+
summaryLabel: {
|
|
3067
|
+
fontSize: 14
|
|
3068
|
+
},
|
|
3069
|
+
summaryValue: {
|
|
3070
|
+
fontSize: 15,
|
|
3071
|
+
fontWeight: "700"
|
|
3072
|
+
},
|
|
3073
|
+
summarySep: {
|
|
3074
|
+
height: 1,
|
|
3075
|
+
marginHorizontal: 16
|
|
3076
|
+
},
|
|
3077
|
+
winnerCol: {
|
|
3078
|
+
alignItems: "flex-end",
|
|
3079
|
+
gap: 2
|
|
3080
|
+
},
|
|
3081
|
+
feeNote: {
|
|
3082
|
+
fontSize: 11
|
|
3083
|
+
},
|
|
3084
|
+
errorBox: {
|
|
3085
|
+
marginTop: 16,
|
|
3086
|
+
borderRadius: 12,
|
|
3087
|
+
borderWidth: 1,
|
|
3088
|
+
padding: 12
|
|
3089
|
+
},
|
|
3090
|
+
errorText: {
|
|
3091
|
+
fontSize: 13,
|
|
3092
|
+
fontWeight: "500"
|
|
3093
|
+
},
|
|
3094
|
+
ctaButton: {
|
|
3095
|
+
marginTop: 20,
|
|
3096
|
+
height: 56,
|
|
3097
|
+
borderRadius: 14,
|
|
3098
|
+
justifyContent: "center",
|
|
3099
|
+
alignItems: "center"
|
|
3100
|
+
},
|
|
3101
|
+
ctaText: {
|
|
3102
|
+
color: "#FFFFFF",
|
|
3103
|
+
fontSize: 16,
|
|
3104
|
+
fontWeight: "700"
|
|
3105
|
+
},
|
|
3106
|
+
ctaLoading: {
|
|
3107
|
+
flexDirection: "row",
|
|
3108
|
+
alignItems: "center",
|
|
3109
|
+
gap: 10
|
|
3110
|
+
}
|
|
3111
|
+
});
|
|
2666
3112
|
export {
|
|
2667
3113
|
AuthGate,
|
|
2668
3114
|
ConnectWalletScreen,
|
|
3115
|
+
CreateCustomGameSheet,
|
|
2669
3116
|
DEFAULT_BASE_URL,
|
|
2670
3117
|
DEFAULT_RPC_URL,
|
|
2671
3118
|
DubsApiError,
|
|
@@ -2689,6 +3136,7 @@ export {
|
|
|
2689
3136
|
useAppConfig,
|
|
2690
3137
|
useAuth,
|
|
2691
3138
|
useClaim,
|
|
3139
|
+
useCreateCustomGame,
|
|
2692
3140
|
useCreateGame,
|
|
2693
3141
|
useDubs,
|
|
2694
3142
|
useDubsTheme,
|