@dubsdotapp/expo 0.2.44 → 0.2.46
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 +45 -4
- package/dist/index.d.mts +42 -4
- package/dist/index.d.ts +42 -4
- package/dist/index.js +182 -125
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +156 -100
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +9 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useUFCFighterDetail.ts +34 -0
- package/src/index.ts +2 -0
- package/src/types.ts +33 -1
- package/src/ui/game/CreateCustomGameSheet.tsx +75 -64
- package/src/ui/game/JoinGameSheet.tsx +47 -26
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -36,6 +36,7 @@ import type {
|
|
|
36
36
|
LiveScore,
|
|
37
37
|
UiConfig,
|
|
38
38
|
UFCEvent,
|
|
39
|
+
UFCFighterDetail,
|
|
39
40
|
} from './types';
|
|
40
41
|
|
|
41
42
|
export interface DubsClientConfig {
|
|
@@ -156,6 +157,14 @@ export class DubsClient {
|
|
|
156
157
|
return res.events;
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
async getUFCFighterDetail(athleteId: string): Promise<UFCFighterDetail> {
|
|
161
|
+
const res = await this.request<{ success: true; fighter: UFCFighterDetail }>(
|
|
162
|
+
'GET',
|
|
163
|
+
`/ufc/fighters/${encodeURIComponent(athleteId)}`,
|
|
164
|
+
);
|
|
165
|
+
return res.fighter;
|
|
166
|
+
}
|
|
167
|
+
|
|
159
168
|
// ── Game Lifecycle ──
|
|
160
169
|
|
|
161
170
|
async validateEvent(id: string): Promise<ValidateEventResult> {
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { useDubs } from '../provider';
|
|
3
|
+
import type { UFCFighterDetail, QueryResult } from '../types';
|
|
4
|
+
|
|
5
|
+
export function useUFCFighterDetail(athleteId: string | null): QueryResult<UFCFighterDetail> {
|
|
6
|
+
const { client } = useDubs();
|
|
7
|
+
const [data, setData] = useState<UFCFighterDetail | null>(null);
|
|
8
|
+
const [loading, setLoading] = useState(false);
|
|
9
|
+
const [error, setError] = useState<Error | null>(null);
|
|
10
|
+
|
|
11
|
+
const fetchData = useCallback(async () => {
|
|
12
|
+
if (!athleteId) {
|
|
13
|
+
setData(null);
|
|
14
|
+
setLoading(false);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
setLoading(true);
|
|
18
|
+
setError(null);
|
|
19
|
+
try {
|
|
20
|
+
const result = await client.getUFCFighterDetail(athleteId);
|
|
21
|
+
setData(result);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
24
|
+
} finally {
|
|
25
|
+
setLoading(false);
|
|
26
|
+
}
|
|
27
|
+
}, [client, athleteId]);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
fetchData();
|
|
31
|
+
}, [fetchData]);
|
|
32
|
+
|
|
33
|
+
return { data, loading, error, refetch: fetchData };
|
|
34
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -60,6 +60,7 @@ export type {
|
|
|
60
60
|
LiveScoreCompetitor,
|
|
61
61
|
UiConfig,
|
|
62
62
|
UFCFighter,
|
|
63
|
+
UFCFighterDetail,
|
|
63
64
|
UFCData,
|
|
64
65
|
UFCFight,
|
|
65
66
|
UFCEvent,
|
|
@@ -89,6 +90,7 @@ export {
|
|
|
89
90
|
useHasClaimed,
|
|
90
91
|
useAuth,
|
|
91
92
|
useUFCFightCard,
|
|
93
|
+
useUFCFighterDetail,
|
|
92
94
|
} from './hooks';
|
|
93
95
|
export type {
|
|
94
96
|
CreateGameMutationResult,
|
package/src/types.ts
CHANGED
|
@@ -419,12 +419,44 @@ export interface LiveScore {
|
|
|
419
419
|
|
|
420
420
|
export interface UFCFighter {
|
|
421
421
|
name: string;
|
|
422
|
-
|
|
422
|
+
athleteId: string | null;
|
|
423
|
+
headshotUrl: string | null;
|
|
424
|
+
flagUrl: string | null;
|
|
425
|
+
country: string | null;
|
|
423
426
|
abbreviation: string;
|
|
424
427
|
record: string | null;
|
|
425
428
|
winner: boolean;
|
|
426
429
|
}
|
|
427
430
|
|
|
431
|
+
export interface UFCFighterDetail {
|
|
432
|
+
athleteId: string;
|
|
433
|
+
firstName: string | null;
|
|
434
|
+
lastName: string | null;
|
|
435
|
+
fullName: string | null;
|
|
436
|
+
nickname: string | null;
|
|
437
|
+
shortName: string | null;
|
|
438
|
+
height: string | null;
|
|
439
|
+
heightInches: number | null;
|
|
440
|
+
weight: string | null;
|
|
441
|
+
weightLbs: number | null;
|
|
442
|
+
reach: string | null;
|
|
443
|
+
reachInches: number | null;
|
|
444
|
+
age: number | null;
|
|
445
|
+
dateOfBirth: string | null;
|
|
446
|
+
stance: string | null;
|
|
447
|
+
weightClass: string | null;
|
|
448
|
+
citizenship: string | null;
|
|
449
|
+
citizenshipAbbreviation: string | null;
|
|
450
|
+
gym: string | null;
|
|
451
|
+
gymCountry: string | null;
|
|
452
|
+
active: boolean;
|
|
453
|
+
headshotUrl: string | null;
|
|
454
|
+
flagUrl: string | null;
|
|
455
|
+
stanceImageUrl: string | null;
|
|
456
|
+
espnUrl: string | null;
|
|
457
|
+
slug: string | null;
|
|
458
|
+
}
|
|
459
|
+
|
|
428
460
|
export interface UFCData {
|
|
429
461
|
currentRound: number;
|
|
430
462
|
totalRounds: number;
|
|
@@ -28,6 +28,8 @@ export interface CreateCustomGameSheetProps {
|
|
|
28
28
|
onAmountChange?: (amount: number | null) => void;
|
|
29
29
|
onSuccess?: (result: CreateCustomGameMutationResult) => void;
|
|
30
30
|
onError?: (error: Error) => void;
|
|
31
|
+
/** Pool mode: hides buy-in selection, uses defaultAmount, auto-assigns team, shows "Create Pool" labels */
|
|
32
|
+
isPoolModeEnabled?: boolean;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
const STATUS_LABELS: Record<string, string> = {
|
|
@@ -49,6 +51,7 @@ export function CreateCustomGameSheet({
|
|
|
49
51
|
onAmountChange,
|
|
50
52
|
onSuccess,
|
|
51
53
|
onError,
|
|
54
|
+
isPoolModeEnabled = false,
|
|
52
55
|
}: CreateCustomGameSheetProps) {
|
|
53
56
|
const t = useDubsTheme();
|
|
54
57
|
const { wallet } = useDubs();
|
|
@@ -122,20 +125,24 @@ export function CreateCustomGameSheet({
|
|
|
122
125
|
|
|
123
126
|
const effectiveAmount = selectedAmount;
|
|
124
127
|
const playerCount = maxPlayers || 2;
|
|
125
|
-
|
|
128
|
+
|
|
129
|
+
// In pool mode, always use defaultAmount
|
|
130
|
+
const finalAmount = isPoolModeEnabled ? (defaultAmount ?? 0.1) : effectiveAmount;
|
|
131
|
+
|
|
132
|
+
const pot = finalAmount ? finalAmount * playerCount : 0;
|
|
126
133
|
const winnerTakes = pot * (1 - fee / 100);
|
|
127
134
|
|
|
128
135
|
const isMutating = mutation.status !== 'idle' && mutation.status !== 'success' && mutation.status !== 'error';
|
|
129
|
-
const canCreate =
|
|
136
|
+
const canCreate = finalAmount !== null && finalAmount > 0 && !isMutating && mutation.status !== 'success';
|
|
130
137
|
|
|
131
138
|
const handleCreate = useCallback(async () => {
|
|
132
|
-
if (!
|
|
139
|
+
if (!finalAmount || !wallet.publicKey) return;
|
|
133
140
|
|
|
134
141
|
try {
|
|
135
142
|
await mutation.execute({
|
|
136
143
|
playerWallet: wallet.publicKey.toBase58(),
|
|
137
144
|
teamChoice: 'home',
|
|
138
|
-
wagerAmount:
|
|
145
|
+
wagerAmount: finalAmount,
|
|
139
146
|
title,
|
|
140
147
|
maxPlayers,
|
|
141
148
|
metadata,
|
|
@@ -143,7 +150,7 @@ export function CreateCustomGameSheet({
|
|
|
143
150
|
} catch {
|
|
144
151
|
// Error is already captured in mutation state
|
|
145
152
|
}
|
|
146
|
-
}, [
|
|
153
|
+
}, [finalAmount, wallet.publicKey, mutation.execute, title, maxPlayers, metadata]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
147
154
|
|
|
148
155
|
const statusLabel = STATUS_LABELS[mutation.status] || '';
|
|
149
156
|
|
|
@@ -173,84 +180,86 @@ export function CreateCustomGameSheet({
|
|
|
173
180
|
|
|
174
181
|
{/* Header */}
|
|
175
182
|
<View style={styles.header}>
|
|
176
|
-
<Text style={[styles.headerTitle, { color: t.text }]}>New Game</Text>
|
|
183
|
+
<Text style={[styles.headerTitle, { color: t.text }]}>{isPoolModeEnabled ? 'Create Pool' : 'New Game'}</Text>
|
|
177
184
|
<TouchableOpacity onPress={onDismiss} activeOpacity={0.8}>
|
|
178
185
|
<Text style={[styles.closeButton, { color: t.textMuted }]}>{'\u2715'}</Text>
|
|
179
186
|
</TouchableOpacity>
|
|
180
187
|
</View>
|
|
181
188
|
|
|
182
|
-
{/* Buy-In Section */}
|
|
183
|
-
|
|
184
|
-
<
|
|
185
|
-
|
|
186
|
-
{
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
{
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
189
|
+
{/* Buy-In Section — hidden in pool mode (uses defaultAmount) */}
|
|
190
|
+
{!isPoolModeEnabled && (
|
|
191
|
+
<View style={styles.section}>
|
|
192
|
+
<Text style={[styles.sectionLabel, { color: t.textSecondary }]}>Buy-In Amount</Text>
|
|
193
|
+
<View style={styles.chipsRow}>
|
|
194
|
+
{presetAmounts.map((amount) => {
|
|
195
|
+
const active = !isCustom && selectedAmount === amount;
|
|
196
|
+
return (
|
|
197
|
+
<TouchableOpacity
|
|
198
|
+
key={amount}
|
|
199
|
+
style={[
|
|
200
|
+
styles.chip,
|
|
201
|
+
{ borderColor: active ? t.accent : t.border },
|
|
202
|
+
active && { backgroundColor: t.accent },
|
|
203
|
+
]}
|
|
204
|
+
onPress={() => handlePresetSelect(amount)}
|
|
205
|
+
activeOpacity={0.8}
|
|
206
|
+
>
|
|
207
|
+
<Text style={[styles.chipText, { color: active ? '#FFFFFF' : t.text }]}>
|
|
208
|
+
{amount} SOL
|
|
209
|
+
</Text>
|
|
210
|
+
</TouchableOpacity>
|
|
211
|
+
);
|
|
212
|
+
})}
|
|
213
|
+
<TouchableOpacity
|
|
214
|
+
style={[
|
|
215
|
+
styles.chip,
|
|
216
|
+
{ borderColor: isCustom ? t.accent : t.border },
|
|
217
|
+
isCustom && { backgroundColor: t.accent },
|
|
218
|
+
]}
|
|
219
|
+
onPress={handleCustomSelect}
|
|
220
|
+
activeOpacity={0.8}
|
|
221
|
+
>
|
|
222
|
+
<Text style={[styles.chipText, { color: isCustom ? '#FFFFFF' : t.text }]}>
|
|
223
|
+
Custom
|
|
224
|
+
</Text>
|
|
225
|
+
</TouchableOpacity>
|
|
226
|
+
</View>
|
|
219
227
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
{isCustom && (
|
|
229
|
+
<TextInput
|
|
230
|
+
style={[styles.input, { backgroundColor: t.surface, color: t.text, borderColor: t.accent }]}
|
|
231
|
+
placeholder="Enter amount in SOL"
|
|
232
|
+
placeholderTextColor={t.textDim}
|
|
233
|
+
keyboardType="decimal-pad"
|
|
234
|
+
value={customAmount}
|
|
235
|
+
onChangeText={handleCustomAmountChange}
|
|
236
|
+
autoFocus
|
|
237
|
+
/>
|
|
238
|
+
)}
|
|
239
|
+
</View>
|
|
240
|
+
)}
|
|
232
241
|
|
|
233
242
|
{/* Summary Card */}
|
|
234
243
|
<View style={[styles.summaryCard, { backgroundColor: t.surface, borderColor: t.border }]}>
|
|
235
244
|
<View style={styles.summaryRow}>
|
|
236
|
-
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>
|
|
245
|
+
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>Buy-in</Text>
|
|
237
246
|
<Text style={[styles.summaryValue, { color: t.text }]}>
|
|
238
|
-
{
|
|
247
|
+
{finalAmount ? `${finalAmount} SOL` : '—'}
|
|
239
248
|
</Text>
|
|
240
249
|
</View>
|
|
241
250
|
<View style={[styles.summarySep, { backgroundColor: t.border }]} />
|
|
242
251
|
<View style={styles.summaryRow}>
|
|
243
|
-
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>Players</Text>
|
|
244
|
-
<Text style={[styles.summaryValue, { color: t.text }]}>{playersLabel}</Text>
|
|
252
|
+
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>{isPoolModeEnabled ? 'Max players' : 'Players'}</Text>
|
|
253
|
+
<Text style={[styles.summaryValue, { color: t.text }]}>{isPoolModeEnabled ? playerCount : playersLabel}</Text>
|
|
245
254
|
</View>
|
|
246
255
|
<View style={[styles.summarySep, { backgroundColor: t.border }]} />
|
|
247
256
|
<View style={styles.summaryRow}>
|
|
248
|
-
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>Winner Takes</Text>
|
|
257
|
+
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>{isPoolModeEnabled ? 'Max pot' : 'Winner Takes'}</Text>
|
|
249
258
|
<View style={styles.winnerCol}>
|
|
250
259
|
<Text style={[styles.summaryValue, { color: t.success }]}>
|
|
251
|
-
{
|
|
260
|
+
{finalAmount ? `${(finalAmount * playerCount * (1 - fee / 100)).toFixed(4)} SOL` : '—'}
|
|
252
261
|
</Text>
|
|
253
|
-
{
|
|
262
|
+
{finalAmount ? (
|
|
254
263
|
<Text style={[styles.feeNote, { color: t.textDim }]}>{fee}% platform fee</Text>
|
|
255
264
|
) : null}
|
|
256
265
|
</View>
|
|
@@ -280,10 +289,12 @@ export function CreateCustomGameSheet({
|
|
|
280
289
|
<Text style={styles.ctaText}>{statusLabel}</Text>
|
|
281
290
|
</View>
|
|
282
291
|
) : mutation.status === 'success' ? (
|
|
283
|
-
<Text style={styles.ctaText}>{STATUS_LABELS.success}</Text>
|
|
292
|
+
<Text style={styles.ctaText}>{isPoolModeEnabled ? 'Pool Created!' : STATUS_LABELS.success}</Text>
|
|
284
293
|
) : (
|
|
285
294
|
<Text style={[styles.ctaText, !canCreate && { opacity: 0.5 }]}>
|
|
286
|
-
{
|
|
295
|
+
{isPoolModeEnabled
|
|
296
|
+
? `Create Pool \u2014 ${finalAmount} SOL`
|
|
297
|
+
: effectiveAmount ? `Create Game \u2014 ${effectiveAmount} SOL` : 'Select buy-in amount'}
|
|
287
298
|
</Text>
|
|
288
299
|
)}
|
|
289
300
|
</TouchableOpacity>
|
|
@@ -30,6 +30,8 @@ export interface JoinGameSheetProps {
|
|
|
30
30
|
/** Callbacks */
|
|
31
31
|
onSuccess?: (result: JoinGameMutationResult) => void;
|
|
32
32
|
onError?: (error: Error) => void;
|
|
33
|
+
/** Pool mode: hides team selection, auto-assigns team, shows "Join Pool" labels */
|
|
34
|
+
isPoolModeEnabled?: boolean;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
const STATUS_LABELS: Record<string, string> = {
|
|
@@ -51,6 +53,7 @@ export function JoinGameSheet({
|
|
|
51
53
|
awayColor = '#EF4444',
|
|
52
54
|
onSuccess,
|
|
53
55
|
onError,
|
|
56
|
+
isPoolModeEnabled = false,
|
|
54
57
|
}: JoinGameSheetProps) {
|
|
55
58
|
const t = useDubsTheme();
|
|
56
59
|
const { wallet } = useDubs();
|
|
@@ -58,7 +61,7 @@ export function JoinGameSheet({
|
|
|
58
61
|
|
|
59
62
|
const isCustomGame = game.gameMode === CUSTOM_GAME_MODE;
|
|
60
63
|
|
|
61
|
-
//
|
|
64
|
+
// Pool mode and custom games auto-assign team — no team selection needed.
|
|
62
65
|
// For sports/esports games the user picks a team.
|
|
63
66
|
const [selectedTeam, setSelectedTeam] = useState<'home' | 'away' | null>(null);
|
|
64
67
|
|
|
@@ -76,7 +79,7 @@ export function JoinGameSheet({
|
|
|
76
79
|
// Reset state when sheet opens
|
|
77
80
|
useEffect(() => {
|
|
78
81
|
if (visible) {
|
|
79
|
-
setSelectedTeam(isCustomGame ? 'away' : null);
|
|
82
|
+
setSelectedTeam(isPoolModeEnabled ? 'home' : isCustomGame ? 'away' : null);
|
|
80
83
|
mutation.reset();
|
|
81
84
|
}
|
|
82
85
|
}, [visible]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
@@ -173,14 +176,14 @@ export function JoinGameSheet({
|
|
|
173
176
|
|
|
174
177
|
{/* Header */}
|
|
175
178
|
<View style={styles.header}>
|
|
176
|
-
<Text style={[styles.headerTitle, { color: t.text }]}>Join Game</Text>
|
|
179
|
+
<Text style={[styles.headerTitle, { color: t.text }]}>{isPoolModeEnabled ? 'Join Pool' : 'Join Game'}</Text>
|
|
177
180
|
<TouchableOpacity onPress={onDismiss} activeOpacity={0.8}>
|
|
178
181
|
<Text style={[styles.closeButton, { color: t.textMuted }]}>{'\u2715'}</Text>
|
|
179
182
|
</TouchableOpacity>
|
|
180
183
|
</View>
|
|
181
184
|
|
|
182
|
-
{/* Team Selection —
|
|
183
|
-
{!isCustomGame && (
|
|
185
|
+
{/* Team Selection — hidden in pool mode and custom games */}
|
|
186
|
+
{!isCustomGame && !isPoolModeEnabled && (
|
|
184
187
|
<View style={styles.section}>
|
|
185
188
|
<Text style={[styles.sectionLabel, { color: t.textSecondary }]}>Pick Your Side</Text>
|
|
186
189
|
<View style={styles.teamsRow}>
|
|
@@ -217,28 +220,44 @@ export function JoinGameSheet({
|
|
|
217
220
|
<Text style={[styles.summaryValue, { color: t.text }]}>{buyIn} SOL</Text>
|
|
218
221
|
</View>
|
|
219
222
|
<View style={[styles.summarySep, { backgroundColor: t.border }]} />
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
223
|
+
{isPoolModeEnabled ? (
|
|
224
|
+
<>
|
|
225
|
+
<View style={styles.summaryRow}>
|
|
226
|
+
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>Players in</Text>
|
|
227
|
+
<Text style={[styles.summaryValue, { color: t.text }]}>{bettors.length}</Text>
|
|
228
|
+
</View>
|
|
229
|
+
<View style={[styles.summarySep, { backgroundColor: t.border }]} />
|
|
230
|
+
<View style={styles.summaryRow}>
|
|
231
|
+
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>Current pot</Text>
|
|
232
|
+
<Text style={[styles.summaryValue, { color: t.success }]}>{totalPool} SOL</Text>
|
|
233
|
+
</View>
|
|
234
|
+
</>
|
|
235
|
+
) : (
|
|
236
|
+
<>
|
|
237
|
+
<View style={styles.summaryRow}>
|
|
238
|
+
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>Your side</Text>
|
|
239
|
+
<Text style={[styles.summaryValue, { color: t.text }]}>{selectedName}</Text>
|
|
240
|
+
</View>
|
|
241
|
+
<View style={[styles.summarySep, { backgroundColor: t.border }]} />
|
|
242
|
+
<View style={styles.summaryRow}>
|
|
243
|
+
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>Total pool</Text>
|
|
244
|
+
<Text style={[styles.summaryValue, { color: t.text }]}>{poolAfterJoin} SOL</Text>
|
|
245
|
+
</View>
|
|
246
|
+
<View style={[styles.summarySep, { backgroundColor: t.border }]} />
|
|
247
|
+
<View style={styles.summaryRow}>
|
|
248
|
+
<Text style={[styles.summaryLabel, { color: t.textMuted }]}>Potential winnings</Text>
|
|
249
|
+
<Text style={[styles.summaryValue, { color: t.success }]}>
|
|
250
|
+
{potentialWinnings !== '—' ? `${potentialWinnings} SOL` : '—'}
|
|
251
|
+
</Text>
|
|
252
|
+
</View>
|
|
253
|
+
</>
|
|
254
|
+
)}
|
|
236
255
|
</View>
|
|
237
256
|
|
|
238
257
|
{/* Already Joined Notice */}
|
|
239
258
|
{alreadyJoined && (
|
|
240
259
|
<View style={[styles.errorBox, { backgroundColor: t.surface, borderColor: t.border }]}>
|
|
241
|
-
<Text style={[styles.errorText, { color: t.textMuted }]}>You've already joined this game
|
|
260
|
+
<Text style={[styles.errorText, { color: t.textMuted }]}>{isPoolModeEnabled ? "You've already joined this pool." : "You've already joined this game."}</Text>
|
|
242
261
|
</View>
|
|
243
262
|
)}
|
|
244
263
|
|
|
@@ -265,14 +284,16 @@ export function JoinGameSheet({
|
|
|
265
284
|
<Text style={styles.ctaText}>{statusLabel}</Text>
|
|
266
285
|
</View>
|
|
267
286
|
) : mutation.status === 'success' ? (
|
|
268
|
-
<Text style={styles.ctaText}>{STATUS_LABELS.success}</Text>
|
|
287
|
+
<Text style={styles.ctaText}>{isPoolModeEnabled ? 'Joined!' : STATUS_LABELS.success}</Text>
|
|
269
288
|
) : (
|
|
270
289
|
<Text style={[styles.ctaText, !canJoin && { opacity: 0.5 }]}>
|
|
271
290
|
{alreadyJoined
|
|
272
291
|
? 'Already Joined'
|
|
273
|
-
:
|
|
274
|
-
? `Join
|
|
275
|
-
:
|
|
292
|
+
: isPoolModeEnabled
|
|
293
|
+
? `Join Pool \u2014 ${buyIn} SOL`
|
|
294
|
+
: selectedTeam
|
|
295
|
+
? `Join Game \u2014 ${buyIn} SOL`
|
|
296
|
+
: 'Pick a side to join'}
|
|
276
297
|
</Text>
|
|
277
298
|
)}
|
|
278
299
|
</TouchableOpacity>
|