@dubsdotapp/expo 0.1.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 +158 -0
- package/dist/index.d.mts +577 -0
- package/dist/index.d.ts +577 -0
- package/dist/index.js +1364 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1318 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +57 -0
- package/src/client.ts +355 -0
- package/src/constants.ts +3 -0
- package/src/errors.ts +127 -0
- package/src/hooks/index.ts +12 -0
- package/src/hooks/useAuth.ts +180 -0
- package/src/hooks/useClaim.ts +64 -0
- package/src/hooks/useCreateGame.ts +78 -0
- package/src/hooks/useEvents.ts +34 -0
- package/src/hooks/useGame.ts +30 -0
- package/src/hooks/useGames.ts +31 -0
- package/src/hooks/useJoinGame.ts +78 -0
- package/src/hooks/useNetworkGames.ts +31 -0
- package/src/index.ts +83 -0
- package/src/provider.tsx +39 -0
- package/src/types.ts +340 -0
- package/src/ui/ConnectWalletScreen.tsx +145 -0
- package/src/ui/SettingsSheet.tsx +173 -0
- package/src/ui/UserProfileCard.tsx +90 -0
- package/src/ui/index.ts +8 -0
- package/src/ui/theme.ts +57 -0
- package/src/utils/transaction.ts +67 -0
- package/src/wallet/index.ts +3 -0
- package/src/wallet/mwa-adapter.ts +156 -0
- package/src/wallet/types.ts +30 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Core
|
|
2
|
+
export { DubsClient } from './client';
|
|
3
|
+
export type { DubsClientConfig } from './client';
|
|
4
|
+
export { DubsApiError, parseSolanaError, SOLANA_PROGRAM_ERRORS } from './errors';
|
|
5
|
+
export { DEFAULT_BASE_URL, DEFAULT_RPC_URL } from './constants';
|
|
6
|
+
|
|
7
|
+
// Types
|
|
8
|
+
export type {
|
|
9
|
+
UnifiedEvent,
|
|
10
|
+
Opponent,
|
|
11
|
+
EventMedia,
|
|
12
|
+
EventStream,
|
|
13
|
+
EventMeta,
|
|
14
|
+
Pagination,
|
|
15
|
+
EsportsMatchDetail,
|
|
16
|
+
EsportsMatchOpponent,
|
|
17
|
+
EsportsMatchResult,
|
|
18
|
+
ValidateEventResult,
|
|
19
|
+
CreateGameParams,
|
|
20
|
+
CreateGameResult,
|
|
21
|
+
JoinGameParams,
|
|
22
|
+
JoinGameResult,
|
|
23
|
+
ConfirmGameParams,
|
|
24
|
+
ConfirmGameResult,
|
|
25
|
+
BuildClaimParams,
|
|
26
|
+
BuildClaimResult,
|
|
27
|
+
GameDetail,
|
|
28
|
+
GameMedia,
|
|
29
|
+
GameListItem,
|
|
30
|
+
GameListOpponent,
|
|
31
|
+
GetGamesParams,
|
|
32
|
+
GetNetworkGamesParams,
|
|
33
|
+
GetUpcomingEventsParams,
|
|
34
|
+
ParsedError,
|
|
35
|
+
SolanaErrorCode,
|
|
36
|
+
MutationStatus,
|
|
37
|
+
QueryResult,
|
|
38
|
+
MutationResult,
|
|
39
|
+
DubsUser,
|
|
40
|
+
DubsPublicUser,
|
|
41
|
+
DubsAppUser,
|
|
42
|
+
NonceResult,
|
|
43
|
+
AuthenticateParams,
|
|
44
|
+
AuthenticateResult,
|
|
45
|
+
RegisterParams,
|
|
46
|
+
RegisterResult,
|
|
47
|
+
CheckUsernameResult,
|
|
48
|
+
AuthStatus,
|
|
49
|
+
} from './types';
|
|
50
|
+
|
|
51
|
+
// Provider
|
|
52
|
+
export { DubsProvider, useDubs } from './provider';
|
|
53
|
+
export type { DubsProviderProps, DubsContextValue } from './provider';
|
|
54
|
+
|
|
55
|
+
// Wallet
|
|
56
|
+
export type { WalletAdapter } from './wallet';
|
|
57
|
+
export { MwaWalletAdapter } from './wallet';
|
|
58
|
+
export type { MwaAdapterConfig, MwaTransactFn } from './wallet';
|
|
59
|
+
|
|
60
|
+
// Hooks
|
|
61
|
+
export {
|
|
62
|
+
useEvents,
|
|
63
|
+
useGame,
|
|
64
|
+
useGames,
|
|
65
|
+
useNetworkGames,
|
|
66
|
+
useCreateGame,
|
|
67
|
+
useJoinGame,
|
|
68
|
+
useClaim,
|
|
69
|
+
useAuth,
|
|
70
|
+
} from './hooks';
|
|
71
|
+
export type {
|
|
72
|
+
CreateGameMutationResult,
|
|
73
|
+
JoinGameMutationResult,
|
|
74
|
+
ClaimMutationResult,
|
|
75
|
+
UseAuthResult,
|
|
76
|
+
} from './hooks';
|
|
77
|
+
|
|
78
|
+
// UI
|
|
79
|
+
export { ConnectWalletScreen, UserProfileCard, SettingsSheet, useDubsTheme } from './ui';
|
|
80
|
+
export type { ConnectWalletScreenProps, UserProfileCardProps, SettingsSheetProps, DubsTheme } from './ui';
|
|
81
|
+
|
|
82
|
+
// Utils
|
|
83
|
+
export { signAndSendBase64Transaction, pollTransactionConfirmation } from './utils/transaction';
|
package/src/provider.tsx
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React, { createContext, useContext, useMemo } from 'react';
|
|
2
|
+
import { Connection } from '@solana/web3.js';
|
|
3
|
+
import { DubsClient } from './client';
|
|
4
|
+
import { DEFAULT_RPC_URL } from './constants';
|
|
5
|
+
import type { WalletAdapter } from './wallet/types';
|
|
6
|
+
|
|
7
|
+
export interface DubsContextValue {
|
|
8
|
+
client: DubsClient;
|
|
9
|
+
wallet: WalletAdapter;
|
|
10
|
+
connection: Connection;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const DubsContext = createContext<DubsContextValue | null>(null);
|
|
14
|
+
|
|
15
|
+
export interface DubsProviderProps {
|
|
16
|
+
apiKey: string;
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
rpcUrl?: string;
|
|
19
|
+
wallet: WalletAdapter;
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function DubsProvider({ apiKey, baseUrl, rpcUrl, wallet, children }: DubsProviderProps) {
|
|
24
|
+
const value = useMemo<DubsContextValue>(() => {
|
|
25
|
+
const client = new DubsClient({ apiKey, baseUrl });
|
|
26
|
+
const connection = new Connection(rpcUrl || DEFAULT_RPC_URL, { commitment: 'confirmed' });
|
|
27
|
+
return { client, wallet, connection };
|
|
28
|
+
}, [apiKey, baseUrl, rpcUrl, wallet]);
|
|
29
|
+
|
|
30
|
+
return <DubsContext.Provider value={value}>{children}</DubsContext.Provider>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function useDubs(): DubsContextValue {
|
|
34
|
+
const ctx = useContext(DubsContext);
|
|
35
|
+
if (!ctx) {
|
|
36
|
+
throw new Error('useDubs must be used within a <DubsProvider>');
|
|
37
|
+
}
|
|
38
|
+
return ctx;
|
|
39
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
// ββ Unified Event (returned by /events/upcoming, /sports/events/:league, /esports/matches/upcoming) ββ
|
|
2
|
+
|
|
3
|
+
export interface Opponent {
|
|
4
|
+
name: string | null;
|
|
5
|
+
imageUrl: string | null;
|
|
6
|
+
score: number | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface EventMedia {
|
|
10
|
+
poster: string | null;
|
|
11
|
+
thumbnail: string | null;
|
|
12
|
+
streams: EventStream[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface EventStream {
|
|
16
|
+
url: string | null;
|
|
17
|
+
language: string | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface EventMeta {
|
|
21
|
+
matchType: string | null;
|
|
22
|
+
numberOfGames: number | null;
|
|
23
|
+
tournament: string | null;
|
|
24
|
+
country: string | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface UnifiedEvent {
|
|
28
|
+
id: string;
|
|
29
|
+
type: 'sports' | 'esports';
|
|
30
|
+
title: string;
|
|
31
|
+
league: string | null;
|
|
32
|
+
game: string | null;
|
|
33
|
+
startTime: string | null;
|
|
34
|
+
status: 'upcoming' | 'live' | 'finished' | 'canceled';
|
|
35
|
+
tier: string | null;
|
|
36
|
+
venue: string | null;
|
|
37
|
+
opponents: Opponent[];
|
|
38
|
+
media: EventMedia;
|
|
39
|
+
meta: EventMeta;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface Pagination {
|
|
43
|
+
page: number;
|
|
44
|
+
perPage: number;
|
|
45
|
+
total: number;
|
|
46
|
+
totalPages: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ββ Esports Match Detail (returned by /esports/matches/:matchId) ββ
|
|
50
|
+
|
|
51
|
+
export interface EsportsMatchOpponent {
|
|
52
|
+
id: number;
|
|
53
|
+
name: string;
|
|
54
|
+
acronym: string | null;
|
|
55
|
+
imageUrl: string | null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface EsportsMatchResult {
|
|
59
|
+
teamId: number;
|
|
60
|
+
score: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface EsportsMatchDetail {
|
|
64
|
+
matchId: number;
|
|
65
|
+
title: string;
|
|
66
|
+
status: string;
|
|
67
|
+
videogame: string | null;
|
|
68
|
+
league: string | null;
|
|
69
|
+
serie: string | null;
|
|
70
|
+
tournament: string | null;
|
|
71
|
+
tier: string | null;
|
|
72
|
+
startTime: string | null;
|
|
73
|
+
endTime: string | null;
|
|
74
|
+
matchType: string | null;
|
|
75
|
+
numberOfGames: number | null;
|
|
76
|
+
opponents: EsportsMatchOpponent[];
|
|
77
|
+
results: EsportsMatchResult[];
|
|
78
|
+
winnerId: number | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ββ Validate Event ββ
|
|
82
|
+
|
|
83
|
+
export interface ValidateEventResult {
|
|
84
|
+
bettable: boolean;
|
|
85
|
+
gameMode: number;
|
|
86
|
+
lockTimestamp: number;
|
|
87
|
+
startTime: string | null;
|
|
88
|
+
status: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ββ Create Game ββ
|
|
92
|
+
|
|
93
|
+
export interface CreateGameParams {
|
|
94
|
+
id: string;
|
|
95
|
+
playerWallet: string;
|
|
96
|
+
teamChoice: 'home' | 'away' | 'draw';
|
|
97
|
+
wagerAmount: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface CreateGameResult {
|
|
101
|
+
gameId: string;
|
|
102
|
+
gameAddress: string;
|
|
103
|
+
transaction: string;
|
|
104
|
+
lockTimestamp: number;
|
|
105
|
+
event: UnifiedEvent;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ββ Join Game ββ
|
|
109
|
+
|
|
110
|
+
export interface JoinGameParams {
|
|
111
|
+
playerWallet: string;
|
|
112
|
+
gameId: string;
|
|
113
|
+
teamChoice: 'home' | 'away' | 'draw';
|
|
114
|
+
amount: number;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface JoinGameResult {
|
|
118
|
+
gameId: string;
|
|
119
|
+
transaction: string;
|
|
120
|
+
gameAddress: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ββ Confirm Game ββ
|
|
124
|
+
|
|
125
|
+
export interface ConfirmGameParams {
|
|
126
|
+
gameId: string;
|
|
127
|
+
playerWallet: string;
|
|
128
|
+
signature: string;
|
|
129
|
+
teamChoice?: 'home' | 'away' | 'draw';
|
|
130
|
+
wagerAmount?: number;
|
|
131
|
+
role?: 'creator' | 'joiner';
|
|
132
|
+
gameAddress?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface ConfirmGameResult {
|
|
136
|
+
gameId: string;
|
|
137
|
+
signature: string;
|
|
138
|
+
explorerUrl: string;
|
|
139
|
+
message: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ββ Build Claim Transaction ββ
|
|
143
|
+
|
|
144
|
+
export interface BuildClaimParams {
|
|
145
|
+
playerWallet: string;
|
|
146
|
+
gameId: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface BuildClaimResult {
|
|
150
|
+
transaction: string;
|
|
151
|
+
gameAddress: string;
|
|
152
|
+
message: string;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ββ Game Detail (returned by /games/:gameId) ββ
|
|
156
|
+
|
|
157
|
+
export interface GameMedia {
|
|
158
|
+
poster: string | null;
|
|
159
|
+
thumbnail: string | null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface GameDetail {
|
|
163
|
+
gameId: string;
|
|
164
|
+
gameAddress: string;
|
|
165
|
+
title: string;
|
|
166
|
+
buyIn: number;
|
|
167
|
+
gameMode: number;
|
|
168
|
+
isLocked: boolean;
|
|
169
|
+
isResolved: boolean;
|
|
170
|
+
status: string;
|
|
171
|
+
lockTimestamp: number | null;
|
|
172
|
+
homePlayers: string[];
|
|
173
|
+
awayPlayers: string[];
|
|
174
|
+
drawPlayers: string[];
|
|
175
|
+
homePool: number;
|
|
176
|
+
awayPool: number;
|
|
177
|
+
drawPool: number;
|
|
178
|
+
totalPool: number;
|
|
179
|
+
sportsEvent: Record<string, unknown> | null;
|
|
180
|
+
media: GameMedia;
|
|
181
|
+
createdAt: string;
|
|
182
|
+
updatedAt: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ββ Game List Item (returned by /games) ββ
|
|
186
|
+
|
|
187
|
+
export interface GameListOpponent {
|
|
188
|
+
name: string | null;
|
|
189
|
+
imageUrl: string | null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface GameListItem {
|
|
193
|
+
gameId: string;
|
|
194
|
+
title: string;
|
|
195
|
+
buyIn: number;
|
|
196
|
+
gameMode: number;
|
|
197
|
+
isLocked: boolean;
|
|
198
|
+
isResolved: boolean;
|
|
199
|
+
status: string;
|
|
200
|
+
totalPool: number;
|
|
201
|
+
league: string | null;
|
|
202
|
+
lockTimestamp: number | null;
|
|
203
|
+
createdAt: string;
|
|
204
|
+
opponents: GameListOpponent[];
|
|
205
|
+
media: GameMedia;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface GetGamesParams {
|
|
209
|
+
wallet?: string;
|
|
210
|
+
status?: 'open' | 'locked' | 'resolved';
|
|
211
|
+
limit?: number;
|
|
212
|
+
offset?: number;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ββ Network Games Query ββ
|
|
216
|
+
|
|
217
|
+
export interface GetNetworkGamesParams {
|
|
218
|
+
league?: string;
|
|
219
|
+
limit?: number;
|
|
220
|
+
offset?: number;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ββ Upcoming Events Query ββ
|
|
224
|
+
|
|
225
|
+
export interface GetUpcomingEventsParams {
|
|
226
|
+
type?: 'sports' | 'esports';
|
|
227
|
+
game?: string;
|
|
228
|
+
page?: number;
|
|
229
|
+
per_page?: number;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ββ Error Parsing ββ
|
|
233
|
+
|
|
234
|
+
export interface ParsedError {
|
|
235
|
+
code: string;
|
|
236
|
+
message: string;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface SolanaErrorCode {
|
|
240
|
+
code: string;
|
|
241
|
+
message: string;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ββ User Auth ββ
|
|
245
|
+
|
|
246
|
+
export interface DubsUser {
|
|
247
|
+
walletAddress: string;
|
|
248
|
+
username: string;
|
|
249
|
+
avatar: string | null;
|
|
250
|
+
myReferralCode: string | null;
|
|
251
|
+
onboardingComplete: boolean;
|
|
252
|
+
createdAt: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface DubsPublicUser {
|
|
256
|
+
walletAddress: string;
|
|
257
|
+
username: string;
|
|
258
|
+
avatar: string | null;
|
|
259
|
+
createdAt: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export interface DubsAppUser extends DubsPublicUser {
|
|
263
|
+
firstSeenAt: string;
|
|
264
|
+
lastSeenAt: string;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export interface NonceResult {
|
|
268
|
+
nonce: string;
|
|
269
|
+
message: string;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface AuthenticateParams {
|
|
273
|
+
walletAddress: string;
|
|
274
|
+
signature: string;
|
|
275
|
+
nonce: string;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export interface AuthenticateResult {
|
|
279
|
+
needsRegistration: boolean;
|
|
280
|
+
user?: DubsUser;
|
|
281
|
+
token?: string;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export interface RegisterParams {
|
|
285
|
+
walletAddress: string;
|
|
286
|
+
signature: string;
|
|
287
|
+
nonce: string;
|
|
288
|
+
username: string;
|
|
289
|
+
referralCode?: string;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export interface RegisterResult {
|
|
293
|
+
user: DubsUser;
|
|
294
|
+
token: string;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export interface CheckUsernameResult {
|
|
298
|
+
available: boolean;
|
|
299
|
+
reason?: string;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export type AuthStatus =
|
|
303
|
+
| 'idle'
|
|
304
|
+
| 'authenticating'
|
|
305
|
+
| 'signing'
|
|
306
|
+
| 'verifying'
|
|
307
|
+
| 'needsRegistration'
|
|
308
|
+
| 'registering'
|
|
309
|
+
| 'authenticated'
|
|
310
|
+
| 'error';
|
|
311
|
+
|
|
312
|
+
// ββ Mutation Hook Status ββ
|
|
313
|
+
|
|
314
|
+
export type MutationStatus =
|
|
315
|
+
| 'idle'
|
|
316
|
+
| 'building'
|
|
317
|
+
| 'signing'
|
|
318
|
+
| 'confirming'
|
|
319
|
+
| 'saving'
|
|
320
|
+
| 'success'
|
|
321
|
+
| 'error';
|
|
322
|
+
|
|
323
|
+
// ββ Query Hook Result ββ
|
|
324
|
+
|
|
325
|
+
export interface QueryResult<T> {
|
|
326
|
+
data: T | null;
|
|
327
|
+
loading: boolean;
|
|
328
|
+
error: Error | null;
|
|
329
|
+
refetch: () => void;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// ββ Mutation Hook Result ββ
|
|
333
|
+
|
|
334
|
+
export interface MutationResult<TParams, TResult> {
|
|
335
|
+
execute: (params: TParams) => Promise<TResult>;
|
|
336
|
+
status: MutationStatus;
|
|
337
|
+
error: Error | null;
|
|
338
|
+
data: TResult | null;
|
|
339
|
+
reset: () => void;
|
|
340
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
ActivityIndicator,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
import { useDubsTheme } from './theme';
|
|
10
|
+
|
|
11
|
+
export interface ConnectWalletScreenProps {
|
|
12
|
+
/** Called when the user taps Connect Wallet */
|
|
13
|
+
onConnect: () => void | Promise<void>;
|
|
14
|
+
/** Show a loading spinner on the button while connecting */
|
|
15
|
+
connecting?: boolean;
|
|
16
|
+
/** Error message to display (e.g. "User rejected the request") */
|
|
17
|
+
error?: string | null;
|
|
18
|
+
/** App name shown in the header. Defaults to "Dubs" */
|
|
19
|
+
appName?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function ConnectWalletScreen({
|
|
23
|
+
onConnect,
|
|
24
|
+
connecting = false,
|
|
25
|
+
error = null,
|
|
26
|
+
appName = 'Dubs',
|
|
27
|
+
}: ConnectWalletScreenProps) {
|
|
28
|
+
const t = useDubsTheme();
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<View style={[styles.container, { backgroundColor: t.background }]}>
|
|
32
|
+
<View style={styles.content}>
|
|
33
|
+
{/* Branding */}
|
|
34
|
+
<View style={styles.brandingSection}>
|
|
35
|
+
<View style={[styles.logoCircle, { backgroundColor: t.accent }]}>
|
|
36
|
+
<Text style={styles.logoText}>D</Text>
|
|
37
|
+
</View>
|
|
38
|
+
<Text style={[styles.appName, { color: t.text }]}>{appName}</Text>
|
|
39
|
+
<Text style={[styles.subtitle, { color: t.textMuted }]}>
|
|
40
|
+
Connect your Solana wallet to get started
|
|
41
|
+
</Text>
|
|
42
|
+
</View>
|
|
43
|
+
|
|
44
|
+
{/* Action */}
|
|
45
|
+
<View style={styles.actionSection}>
|
|
46
|
+
{error ? (
|
|
47
|
+
<View
|
|
48
|
+
style={[
|
|
49
|
+
styles.errorBox,
|
|
50
|
+
{ backgroundColor: t.errorBg, borderColor: t.errorBorder },
|
|
51
|
+
]}
|
|
52
|
+
>
|
|
53
|
+
<Text style={[styles.errorText, { color: t.errorText }]}>{error}</Text>
|
|
54
|
+
</View>
|
|
55
|
+
) : null}
|
|
56
|
+
|
|
57
|
+
<TouchableOpacity
|
|
58
|
+
style={[styles.connectButton, { backgroundColor: t.accent }]}
|
|
59
|
+
onPress={onConnect}
|
|
60
|
+
disabled={connecting}
|
|
61
|
+
activeOpacity={0.8}
|
|
62
|
+
>
|
|
63
|
+
{connecting ? (
|
|
64
|
+
<ActivityIndicator color="#FFFFFF" size="small" />
|
|
65
|
+
) : (
|
|
66
|
+
<Text style={styles.connectButtonText}>Connect Wallet</Text>
|
|
67
|
+
)}
|
|
68
|
+
</TouchableOpacity>
|
|
69
|
+
|
|
70
|
+
<Text style={[styles.hint, { color: t.textDim }]}>
|
|
71
|
+
Phantom, Solflare, or any Solana wallet
|
|
72
|
+
</Text>
|
|
73
|
+
</View>
|
|
74
|
+
</View>
|
|
75
|
+
</View>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const styles = StyleSheet.create({
|
|
80
|
+
container: {
|
|
81
|
+
flex: 1,
|
|
82
|
+
justifyContent: 'center',
|
|
83
|
+
},
|
|
84
|
+
content: {
|
|
85
|
+
flex: 1,
|
|
86
|
+
justifyContent: 'space-between',
|
|
87
|
+
paddingHorizontal: 32,
|
|
88
|
+
paddingTop: 120,
|
|
89
|
+
paddingBottom: 80,
|
|
90
|
+
},
|
|
91
|
+
brandingSection: {
|
|
92
|
+
alignItems: 'center',
|
|
93
|
+
gap: 12,
|
|
94
|
+
},
|
|
95
|
+
logoCircle: {
|
|
96
|
+
width: 80,
|
|
97
|
+
height: 80,
|
|
98
|
+
borderRadius: 40,
|
|
99
|
+
justifyContent: 'center',
|
|
100
|
+
alignItems: 'center',
|
|
101
|
+
marginBottom: 8,
|
|
102
|
+
},
|
|
103
|
+
logoText: {
|
|
104
|
+
fontSize: 36,
|
|
105
|
+
fontWeight: '800',
|
|
106
|
+
color: '#FFFFFF',
|
|
107
|
+
},
|
|
108
|
+
appName: {
|
|
109
|
+
fontSize: 32,
|
|
110
|
+
fontWeight: '800',
|
|
111
|
+
},
|
|
112
|
+
subtitle: {
|
|
113
|
+
fontSize: 16,
|
|
114
|
+
textAlign: 'center',
|
|
115
|
+
lineHeight: 22,
|
|
116
|
+
},
|
|
117
|
+
actionSection: {
|
|
118
|
+
gap: 16,
|
|
119
|
+
},
|
|
120
|
+
errorBox: {
|
|
121
|
+
borderWidth: 1,
|
|
122
|
+
borderRadius: 12,
|
|
123
|
+
paddingHorizontal: 16,
|
|
124
|
+
paddingVertical: 12,
|
|
125
|
+
},
|
|
126
|
+
errorText: {
|
|
127
|
+
fontSize: 14,
|
|
128
|
+
textAlign: 'center',
|
|
129
|
+
},
|
|
130
|
+
connectButton: {
|
|
131
|
+
height: 56,
|
|
132
|
+
borderRadius: 16,
|
|
133
|
+
justifyContent: 'center',
|
|
134
|
+
alignItems: 'center',
|
|
135
|
+
},
|
|
136
|
+
connectButtonText: {
|
|
137
|
+
color: '#FFFFFF',
|
|
138
|
+
fontSize: 18,
|
|
139
|
+
fontWeight: '700',
|
|
140
|
+
},
|
|
141
|
+
hint: {
|
|
142
|
+
fontSize: 13,
|
|
143
|
+
textAlign: 'center',
|
|
144
|
+
},
|
|
145
|
+
});
|