@dubsdotapp/expo 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -850,7 +850,7 @@ function useAuth() {
850
850
  setStatus("error");
851
851
  }
852
852
  }, [client, wallet]);
853
- const register = useCallback8(async (username, referralCode) => {
853
+ const register = useCallback8(async (username, referralCode, avatarUrl) => {
854
854
  try {
855
855
  const pending = pendingAuth.current;
856
856
  if (!pending) {
@@ -863,7 +863,8 @@ function useAuth() {
863
863
  signature: pending.signature,
864
864
  nonce: pending.nonce,
865
865
  username,
866
- referralCode
866
+ referralCode,
867
+ avatarUrl
867
868
  });
868
869
  pendingAuth.current = null;
869
870
  setUser(result.user);
@@ -915,13 +916,21 @@ function useAuth() {
915
916
  };
916
917
  }
917
918
 
918
- // src/ui/ConnectWalletScreen.tsx
919
+ // src/ui/AuthGate.tsx
920
+ import React2, { useState as useState9, useEffect as useEffect5, useRef as useRef2, useCallback as useCallback9 } from "react";
919
921
  import {
920
922
  View,
921
923
  Text,
924
+ TextInput,
922
925
  TouchableOpacity,
923
926
  ActivityIndicator,
924
- StyleSheet
927
+ StyleSheet,
928
+ Keyboard,
929
+ KeyboardAvoidingView,
930
+ Platform,
931
+ Image,
932
+ Animated,
933
+ ScrollView
925
934
  } from "react-native";
926
935
 
927
936
  // src/ui/theme.ts
@@ -963,8 +972,509 @@ function useDubsTheme() {
963
972
  return scheme === "light" ? light : dark;
964
973
  }
965
974
 
975
+ // src/ui/AuthGate.tsx
976
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
977
+ var DICEBEAR_STYLES = [
978
+ "adventurer",
979
+ "avataaars",
980
+ "fun-emoji",
981
+ "bottts",
982
+ "big-smile",
983
+ "thumbs"
984
+ ];
985
+ function generateSeed() {
986
+ return Math.random().toString(36).slice(2, 10);
987
+ }
988
+ function getAvatarUrl(style, seed, size = 256) {
989
+ return `https://api.dicebear.com/9.x/${style}/png?seed=${seed}&size=${size}`;
990
+ }
991
+ function AuthGate({
992
+ children,
993
+ onSaveToken,
994
+ onLoadToken,
995
+ renderLoading,
996
+ renderError,
997
+ renderRegistration,
998
+ appName = "Dubs"
999
+ }) {
1000
+ const { client } = useDubs();
1001
+ const auth = useAuth();
1002
+ const [phase, setPhase] = useState9("init");
1003
+ const [registrationPhase, setRegistrationPhase] = useState9(false);
1004
+ useEffect5(() => {
1005
+ let cancelled = false;
1006
+ (async () => {
1007
+ try {
1008
+ const savedToken = await onLoadToken();
1009
+ if (cancelled) return;
1010
+ if (savedToken) {
1011
+ const restored = await auth.restoreSession(savedToken);
1012
+ if (cancelled) return;
1013
+ if (restored) {
1014
+ setPhase("active");
1015
+ return;
1016
+ }
1017
+ await onSaveToken(null);
1018
+ }
1019
+ if (cancelled) return;
1020
+ setPhase("active");
1021
+ await auth.authenticate();
1022
+ } catch {
1023
+ if (!cancelled) setPhase("active");
1024
+ }
1025
+ })();
1026
+ return () => {
1027
+ cancelled = true;
1028
+ };
1029
+ }, []);
1030
+ useEffect5(() => {
1031
+ if (auth.status === "needsRegistration") setRegistrationPhase(true);
1032
+ }, [auth.status]);
1033
+ useEffect5(() => {
1034
+ if (auth.token) onSaveToken(auth.token);
1035
+ }, [auth.token]);
1036
+ const retry = useCallback9(() => {
1037
+ setRegistrationPhase(false);
1038
+ auth.reset();
1039
+ auth.authenticate();
1040
+ }, [auth]);
1041
+ const handleRegister = useCallback9(
1042
+ (username, referralCode, avatarUrl) => {
1043
+ auth.register(username, referralCode, avatarUrl);
1044
+ },
1045
+ [auth]
1046
+ );
1047
+ if (phase === "init") {
1048
+ if (renderLoading) return /* @__PURE__ */ jsx2(Fragment, { children: renderLoading("authenticating") });
1049
+ return /* @__PURE__ */ jsx2(DefaultLoadingScreen, { status: "authenticating", appName });
1050
+ }
1051
+ if (auth.status === "authenticated") return /* @__PURE__ */ jsx2(Fragment, { children });
1052
+ if (registrationPhase) {
1053
+ const isRegistering = auth.status === "registering";
1054
+ const regError = auth.status === "error" ? auth.error : null;
1055
+ if (renderRegistration) {
1056
+ return /* @__PURE__ */ jsx2(Fragment, { children: renderRegistration({ onRegister: handleRegister, registering: isRegistering, error: regError, client }) });
1057
+ }
1058
+ return /* @__PURE__ */ jsx2(
1059
+ DefaultRegistrationScreen,
1060
+ {
1061
+ onRegister: handleRegister,
1062
+ registering: isRegistering,
1063
+ error: regError,
1064
+ client,
1065
+ appName
1066
+ }
1067
+ );
1068
+ }
1069
+ if (auth.status === "error" && auth.error) {
1070
+ if (renderError) return /* @__PURE__ */ jsx2(Fragment, { children: renderError(auth.error, retry) });
1071
+ return /* @__PURE__ */ jsx2(DefaultErrorScreen, { error: auth.error, onRetry: retry, appName });
1072
+ }
1073
+ if (renderLoading) return /* @__PURE__ */ jsx2(Fragment, { children: renderLoading(auth.status) });
1074
+ return /* @__PURE__ */ jsx2(DefaultLoadingScreen, { status: auth.status, appName });
1075
+ }
1076
+ function DefaultLoadingScreen({ status, appName }) {
1077
+ const t = useDubsTheme();
1078
+ const statusText = {
1079
+ idle: "Initializing...",
1080
+ authenticating: "Connecting...",
1081
+ signing: "Approve in your wallet...",
1082
+ verifying: "Verifying...",
1083
+ registering: "Creating account...",
1084
+ needsRegistration: "Almost there...",
1085
+ authenticated: "Ready!",
1086
+ error: "Something went wrong"
1087
+ };
1088
+ return /* @__PURE__ */ jsx2(View, { style: [s.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs(View, { style: s.centerContent, children: [
1089
+ /* @__PURE__ */ jsxs(View, { style: s.brandingSection, children: [
1090
+ /* @__PURE__ */ jsx2(View, { style: [s.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ jsx2(Text, { style: s.logoText, children: "D" }) }),
1091
+ /* @__PURE__ */ jsx2(Text, { style: [s.appNameText, { color: t.text }], children: appName })
1092
+ ] }),
1093
+ /* @__PURE__ */ jsxs(View, { style: s.loadingSection, children: [
1094
+ /* @__PURE__ */ jsx2(ActivityIndicator, { size: "large", color: t.accent }),
1095
+ /* @__PURE__ */ jsx2(Text, { style: [s.statusText, { color: t.textMuted }], children: statusText[status] || "Loading..." })
1096
+ ] })
1097
+ ] }) });
1098
+ }
1099
+ function DefaultErrorScreen({ error, onRetry, appName }) {
1100
+ const t = useDubsTheme();
1101
+ return /* @__PURE__ */ jsx2(View, { style: [s.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs(View, { style: s.spreadContent, children: [
1102
+ /* @__PURE__ */ jsxs(View, { style: s.brandingSection, children: [
1103
+ /* @__PURE__ */ jsx2(View, { style: [s.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ jsx2(Text, { style: s.logoText, children: "D" }) }),
1104
+ /* @__PURE__ */ jsx2(Text, { style: [s.appNameText, { color: t.text }], children: appName })
1105
+ ] }),
1106
+ /* @__PURE__ */ jsxs(View, { style: { gap: 16 }, children: [
1107
+ /* @__PURE__ */ jsx2(View, { style: [s.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ jsx2(Text, { style: [s.errorText, { color: t.errorText }], children: error.message }) }),
1108
+ /* @__PURE__ */ jsx2(TouchableOpacity, { style: [s.primaryBtn, { backgroundColor: t.accent }], onPress: onRetry, activeOpacity: 0.8, children: /* @__PURE__ */ jsx2(Text, { style: s.primaryBtnText, children: "Try Again" }) })
1109
+ ] })
1110
+ ] }) });
1111
+ }
1112
+ function StepIndicator({ currentStep }) {
1113
+ const t = useDubsTheme();
1114
+ const steps = [0, 1, 2, 3];
1115
+ return /* @__PURE__ */ jsx2(View, { style: s.stepRow, children: steps.map((i) => /* @__PURE__ */ jsxs(React2.Fragment, { children: [
1116
+ i > 0 && /* @__PURE__ */ jsx2(View, { style: [s.stepLine, { backgroundColor: i <= currentStep ? t.success : t.border }] }),
1117
+ /* @__PURE__ */ jsx2(
1118
+ View,
1119
+ {
1120
+ style: [
1121
+ s.stepCircle,
1122
+ i < currentStep ? { backgroundColor: t.success } : i === currentStep ? { backgroundColor: t.accent } : { backgroundColor: "transparent", borderWidth: 2, borderColor: t.border }
1123
+ ],
1124
+ children: i < currentStep ? /* @__PURE__ */ jsx2(Text, { style: s.stepCheck, children: "\u2713" }) : /* @__PURE__ */ jsx2(Text, { style: [s.stepNum, { color: i === currentStep ? "#FFF" : t.textMuted }], children: i + 1 })
1125
+ }
1126
+ )
1127
+ ] }, i)) });
1128
+ }
1129
+ function DefaultRegistrationScreen({
1130
+ onRegister,
1131
+ registering,
1132
+ error,
1133
+ client,
1134
+ appName
1135
+ }) {
1136
+ const t = useDubsTheme();
1137
+ const [step, setStep] = useState9(0);
1138
+ const [avatarSeed, setAvatarSeed] = useState9(generateSeed);
1139
+ const [avatarStyle, setAvatarStyle] = useState9("adventurer");
1140
+ const [showStyles, setShowStyles] = useState9(false);
1141
+ const [username, setUsername] = useState9("");
1142
+ const [referralCode, setReferralCode] = useState9("");
1143
+ const [checking, setChecking] = useState9(false);
1144
+ const [availability, setAvailability] = useState9(null);
1145
+ const debounceRef = useRef2(null);
1146
+ const fadeAnim = useRef2(new Animated.Value(1)).current;
1147
+ const slideAnim = useRef2(new Animated.Value(0)).current;
1148
+ const avatarUrl = getAvatarUrl(avatarStyle, avatarSeed);
1149
+ useEffect5(() => {
1150
+ if (debounceRef.current) clearTimeout(debounceRef.current);
1151
+ const trimmed = username.trim();
1152
+ if (trimmed.length < 3) {
1153
+ setAvailability(null);
1154
+ setChecking(false);
1155
+ return;
1156
+ }
1157
+ setChecking(true);
1158
+ debounceRef.current = setTimeout(async () => {
1159
+ try {
1160
+ const result = await client.checkUsername(trimmed);
1161
+ setAvailability(result);
1162
+ } catch {
1163
+ setAvailability(null);
1164
+ } finally {
1165
+ setChecking(false);
1166
+ }
1167
+ }, 500);
1168
+ return () => {
1169
+ if (debounceRef.current) clearTimeout(debounceRef.current);
1170
+ };
1171
+ }, [username, client]);
1172
+ const animateToStep = useCallback9((newStep) => {
1173
+ const dir = newStep > step ? 1 : -1;
1174
+ Keyboard.dismiss();
1175
+ Animated.parallel([
1176
+ Animated.timing(fadeAnim, { toValue: 0, duration: 120, useNativeDriver: true }),
1177
+ Animated.timing(slideAnim, { toValue: -dir * 40, duration: 120, useNativeDriver: true })
1178
+ ]).start(() => {
1179
+ setStep(newStep);
1180
+ slideAnim.setValue(dir * 40);
1181
+ Animated.parallel([
1182
+ Animated.timing(fadeAnim, { toValue: 1, duration: 200, useNativeDriver: true }),
1183
+ Animated.timing(slideAnim, { toValue: 0, duration: 200, useNativeDriver: true })
1184
+ ]).start();
1185
+ });
1186
+ }, [step, fadeAnim, slideAnim]);
1187
+ const canContinueUsername = username.trim().length >= 3 && availability?.available === true && !checking;
1188
+ const handleSubmit = () => {
1189
+ Keyboard.dismiss();
1190
+ onRegister(username.trim(), referralCode.trim() || void 0, avatarUrl);
1191
+ };
1192
+ const renderAvatarStep = () => /* @__PURE__ */ jsxs(View, { style: s.stepContainer, children: [
1193
+ /* @__PURE__ */ jsxs(View, { style: s.stepTop, children: [
1194
+ /* @__PURE__ */ jsx2(Text, { style: [s.title, { color: t.text }], children: "Choose Your Avatar" }),
1195
+ /* @__PURE__ */ jsx2(Text, { style: [s.subtitle, { color: t.textMuted }], children: "Pick a look that represents you" }),
1196
+ /* @__PURE__ */ jsx2(StepIndicator, { currentStep: 0 }),
1197
+ /* @__PURE__ */ jsx2(View, { style: s.avatarCenter, children: /* @__PURE__ */ jsxs(View, { style: [s.avatarFrame, { borderColor: t.accent }], children: [
1198
+ /* @__PURE__ */ jsx2(Image, { source: { uri: avatarUrl }, style: s.avatarLarge }),
1199
+ /* @__PURE__ */ jsx2(View, { style: [s.checkBadge, { backgroundColor: t.success }], children: /* @__PURE__ */ jsx2(Text, { style: s.checkBadgeText, children: "\u2713" }) })
1200
+ ] }) }),
1201
+ /* @__PURE__ */ jsxs(View, { style: s.avatarActions, children: [
1202
+ /* @__PURE__ */ jsx2(
1203
+ TouchableOpacity,
1204
+ {
1205
+ style: [s.outlineBtn, { borderColor: t.border }],
1206
+ onPress: () => setAvatarSeed(generateSeed()),
1207
+ activeOpacity: 0.7,
1208
+ children: /* @__PURE__ */ jsx2(Text, { style: [s.outlineBtnText, { color: t.text }], children: "\u21BB Shuffle" })
1209
+ }
1210
+ ),
1211
+ /* @__PURE__ */ jsx2(
1212
+ TouchableOpacity,
1213
+ {
1214
+ style: [s.outlineBtn, { borderColor: t.accent, backgroundColor: t.accent + "15" }],
1215
+ onPress: () => setShowStyles(!showStyles),
1216
+ activeOpacity: 0.7,
1217
+ children: /* @__PURE__ */ jsx2(Text, { style: [s.outlineBtnText, { color: t.accent }], children: "\u263A Customize" })
1218
+ }
1219
+ )
1220
+ ] }),
1221
+ showStyles && /* @__PURE__ */ jsx2(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: s.styleScroll, children: DICEBEAR_STYLES.map((st) => /* @__PURE__ */ jsx2(
1222
+ TouchableOpacity,
1223
+ {
1224
+ onPress: () => setAvatarStyle(st),
1225
+ style: [s.styleThumbWrap, { borderColor: st === avatarStyle ? t.accent : t.border }],
1226
+ children: /* @__PURE__ */ jsx2(Image, { source: { uri: getAvatarUrl(st, avatarSeed, 80) }, style: s.styleThumb })
1227
+ },
1228
+ st
1229
+ )) })
1230
+ ] }),
1231
+ /* @__PURE__ */ jsx2(View, { style: s.bottomRow, children: /* @__PURE__ */ jsx2(
1232
+ TouchableOpacity,
1233
+ {
1234
+ style: [s.primaryBtn, { backgroundColor: t.accent, flex: 1 }],
1235
+ onPress: () => animateToStep(1),
1236
+ activeOpacity: 0.8,
1237
+ children: /* @__PURE__ */ jsx2(Text, { style: s.primaryBtnText, children: "Continue \u203A" })
1238
+ }
1239
+ ) })
1240
+ ] });
1241
+ const renderUsernameStep = () => /* @__PURE__ */ jsxs(View, { style: s.stepContainer, children: [
1242
+ /* @__PURE__ */ jsxs(View, { style: s.stepTop, children: [
1243
+ /* @__PURE__ */ jsxs(View, { style: s.headerRow, children: [
1244
+ /* @__PURE__ */ jsx2(TouchableOpacity, { onPress: () => animateToStep(0), hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }, children: /* @__PURE__ */ jsx2(Text, { style: [s.backChevron, { color: t.text }], children: "\u2039" }) }),
1245
+ /* @__PURE__ */ jsx2(Text, { style: [s.titleInline, { color: t.text }], children: "Pick a Username" })
1246
+ ] }),
1247
+ /* @__PURE__ */ jsx2(Text, { style: [s.subtitle, { color: t.textMuted }], children: "This is how others will see you" }),
1248
+ /* @__PURE__ */ jsx2(StepIndicator, { currentStep: 1 }),
1249
+ /* @__PURE__ */ jsx2(View, { style: s.avatarCenter, children: /* @__PURE__ */ jsxs(View, { style: [s.avatarFrameSmall, { borderColor: t.accent }], children: [
1250
+ /* @__PURE__ */ jsx2(Image, { source: { uri: avatarUrl }, style: s.avatarSmall }),
1251
+ /* @__PURE__ */ jsx2(View, { style: [s.checkBadgeSm, { backgroundColor: t.success }], children: /* @__PURE__ */ jsx2(Text, { style: s.checkBadgeTextSm, children: "\u2713" }) })
1252
+ ] }) }),
1253
+ /* @__PURE__ */ jsxs(View, { style: s.inputGroup, children: [
1254
+ /* @__PURE__ */ jsxs(Text, { style: [s.inputLabel, { color: t.text }], children: [
1255
+ "Username ",
1256
+ /* @__PURE__ */ jsx2(Text, { style: { color: t.errorText }, children: "*" })
1257
+ ] }),
1258
+ /* @__PURE__ */ jsx2(
1259
+ TextInput,
1260
+ {
1261
+ style: [s.input, { backgroundColor: t.surface, color: t.text, borderColor: t.accent }],
1262
+ placeholder: "Enter username",
1263
+ placeholderTextColor: t.textDim,
1264
+ value: username,
1265
+ onChangeText: setUsername,
1266
+ autoCapitalize: "none",
1267
+ autoCorrect: false,
1268
+ autoFocus: true
1269
+ }
1270
+ ),
1271
+ checking ? /* @__PURE__ */ jsx2(Text, { style: [s.hint, { color: t.textDim }], children: "Checking..." }) : availability ? /* @__PURE__ */ jsx2(Text, { style: [s.hint, { color: availability.available ? t.success : t.errorText }], children: availability.available ? "\u2713 Available!" : availability.reason || "Username taken" }) : username.trim().length > 0 && username.trim().length < 3 ? /* @__PURE__ */ jsx2(Text, { style: [s.hint, { color: t.textDim }], children: "At least 3 characters" }) : null
1272
+ ] })
1273
+ ] }),
1274
+ /* @__PURE__ */ jsxs(View, { style: s.bottomRow, children: [
1275
+ /* @__PURE__ */ jsx2(
1276
+ TouchableOpacity,
1277
+ {
1278
+ style: [s.secondaryBtn, { borderColor: t.border }],
1279
+ onPress: () => animateToStep(0),
1280
+ activeOpacity: 0.7,
1281
+ children: /* @__PURE__ */ jsx2(Text, { style: [s.secondaryBtnText, { color: t.text }], children: "\u2039 Back" })
1282
+ }
1283
+ ),
1284
+ /* @__PURE__ */ jsx2(
1285
+ TouchableOpacity,
1286
+ {
1287
+ style: [s.primaryBtn, { backgroundColor: t.accent, flex: 1, opacity: canContinueUsername ? 1 : 0.4 }],
1288
+ onPress: () => animateToStep(2),
1289
+ disabled: !canContinueUsername,
1290
+ activeOpacity: 0.8,
1291
+ children: /* @__PURE__ */ jsx2(Text, { style: s.primaryBtnText, children: "Continue \u203A" })
1292
+ }
1293
+ )
1294
+ ] })
1295
+ ] });
1296
+ const renderReferralStep = () => /* @__PURE__ */ jsxs(View, { style: s.stepContainer, children: [
1297
+ /* @__PURE__ */ jsxs(View, { style: s.stepTop, children: [
1298
+ /* @__PURE__ */ jsxs(View, { style: s.headerRow, children: [
1299
+ /* @__PURE__ */ jsx2(TouchableOpacity, { onPress: () => animateToStep(1), hitSlop: { top: 12, bottom: 12, left: 12, right: 12 }, children: /* @__PURE__ */ jsx2(Text, { style: [s.backChevron, { color: t.text }], children: "\u2039" }) }),
1300
+ /* @__PURE__ */ jsx2(Text, { style: [s.titleInline, { color: t.text }], children: "Almost There!" })
1301
+ ] }),
1302
+ /* @__PURE__ */ jsx2(Text, { style: [s.subtitle, { color: t.textMuted }], children: "Got a referral code? (optional)" }),
1303
+ /* @__PURE__ */ jsx2(StepIndicator, { currentStep: 2 }),
1304
+ /* @__PURE__ */ jsxs(View, { style: [s.profileCard, { borderColor: t.border }], children: [
1305
+ /* @__PURE__ */ jsx2(Text, { style: [s.profileLabel, { color: t.textMuted }], children: "Your Profile" }),
1306
+ /* @__PURE__ */ jsxs(View, { style: s.profileRow, children: [
1307
+ /* @__PURE__ */ jsx2(Image, { source: { uri: avatarUrl }, style: s.profileAvatar }),
1308
+ /* @__PURE__ */ jsxs(View, { style: { gap: 4 }, children: [
1309
+ /* @__PURE__ */ jsxs(Text, { style: [s.profileUsername, { color: t.text }], children: [
1310
+ "@",
1311
+ username
1312
+ ] }),
1313
+ /* @__PURE__ */ jsxs(Text, { style: [s.profileReady, { color: t.success }], children: [
1314
+ "\u2713",
1315
+ " Ready to go!"
1316
+ ] })
1317
+ ] })
1318
+ ] })
1319
+ ] }),
1320
+ error ? /* @__PURE__ */ jsx2(View, { style: [s.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }], children: /* @__PURE__ */ jsx2(Text, { style: [s.errorText, { color: t.errorText }], children: error.message }) }) : null,
1321
+ /* @__PURE__ */ jsxs(View, { style: s.inputGroup, children: [
1322
+ /* @__PURE__ */ jsxs(Text, { style: [s.inputLabel, { color: t.text }], children: [
1323
+ "Referral Code ",
1324
+ /* @__PURE__ */ jsx2(Text, { style: { color: t.textMuted }, children: "(optional)" })
1325
+ ] }),
1326
+ /* @__PURE__ */ jsx2(
1327
+ TextInput,
1328
+ {
1329
+ style: [s.input, { backgroundColor: t.surface, color: t.text, borderColor: t.border }],
1330
+ placeholder: "Enter referral code",
1331
+ placeholderTextColor: t.textDim,
1332
+ value: referralCode,
1333
+ onChangeText: setReferralCode,
1334
+ autoCapitalize: "none",
1335
+ autoCorrect: false,
1336
+ editable: !registering
1337
+ }
1338
+ ),
1339
+ /* @__PURE__ */ jsxs(Text, { style: [s.hint, { color: t.textMuted }], children: [
1340
+ "\u{1F381}",
1341
+ " If a friend invited you, enter their code to give them credit!"
1342
+ ] })
1343
+ ] })
1344
+ ] }),
1345
+ /* @__PURE__ */ jsxs(View, { style: s.bottomRow, children: [
1346
+ /* @__PURE__ */ jsx2(
1347
+ TouchableOpacity,
1348
+ {
1349
+ style: [s.secondaryBtn, { borderColor: t.border }],
1350
+ onPress: () => animateToStep(1),
1351
+ disabled: registering,
1352
+ activeOpacity: 0.7,
1353
+ children: /* @__PURE__ */ jsx2(Text, { style: [s.secondaryBtnText, { color: t.text }], children: "\u2039 Back" })
1354
+ }
1355
+ ),
1356
+ /* @__PURE__ */ jsx2(
1357
+ TouchableOpacity,
1358
+ {
1359
+ style: [s.primaryBtn, { backgroundColor: t.accent, flex: 1, opacity: registering ? 0.7 : 1 }],
1360
+ onPress: handleSubmit,
1361
+ disabled: registering,
1362
+ activeOpacity: 0.8,
1363
+ children: registering ? /* @__PURE__ */ jsx2(ActivityIndicator, { color: "#FFFFFF", size: "small" }) : /* @__PURE__ */ jsx2(Text, { style: s.primaryBtnText, children: "Create Account" })
1364
+ }
1365
+ )
1366
+ ] })
1367
+ ] });
1368
+ const renderStep = () => {
1369
+ switch (step) {
1370
+ case 0:
1371
+ return renderAvatarStep();
1372
+ case 1:
1373
+ return renderUsernameStep();
1374
+ case 2:
1375
+ return renderReferralStep();
1376
+ default:
1377
+ return null;
1378
+ }
1379
+ };
1380
+ return /* @__PURE__ */ jsx2(
1381
+ KeyboardAvoidingView,
1382
+ {
1383
+ style: [s.container, { backgroundColor: t.background }],
1384
+ behavior: Platform.OS === "ios" ? "padding" : void 0,
1385
+ children: /* @__PURE__ */ jsx2(
1386
+ ScrollView,
1387
+ {
1388
+ contentContainerStyle: { flexGrow: 1 },
1389
+ keyboardShouldPersistTaps: "handled",
1390
+ bounces: false,
1391
+ children: /* @__PURE__ */ jsx2(
1392
+ Animated.View,
1393
+ {
1394
+ style: [
1395
+ { flex: 1 },
1396
+ { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }
1397
+ ],
1398
+ children: renderStep()
1399
+ }
1400
+ )
1401
+ }
1402
+ )
1403
+ }
1404
+ );
1405
+ }
1406
+ var s = StyleSheet.create({
1407
+ container: { flex: 1 },
1408
+ // Loading / Error
1409
+ centerContent: { flex: 1, justifyContent: "center", alignItems: "center", paddingHorizontal: 32, gap: 48 },
1410
+ spreadContent: { flex: 1, justifyContent: "space-between", paddingHorizontal: 32, paddingTop: 120, paddingBottom: 80 },
1411
+ brandingSection: { alignItems: "center", gap: 12 },
1412
+ logoCircle: { width: 80, height: 80, borderRadius: 40, justifyContent: "center", alignItems: "center", marginBottom: 8 },
1413
+ logoText: { fontSize: 36, fontWeight: "800", color: "#FFFFFF" },
1414
+ appNameText: { fontSize: 32, fontWeight: "800" },
1415
+ loadingSection: { alignItems: "center", gap: 16 },
1416
+ statusText: { fontSize: 16, textAlign: "center" },
1417
+ errorBox: { borderWidth: 1, borderRadius: 12, paddingHorizontal: 16, paddingVertical: 12 },
1418
+ errorText: { fontSize: 14, textAlign: "center" },
1419
+ // Step indicator
1420
+ stepRow: { flexDirection: "row", alignItems: "center", paddingHorizontal: 24, marginVertical: 16 },
1421
+ stepLine: { flex: 1, height: 2 },
1422
+ stepCircle: { width: 36, height: 36, borderRadius: 18, justifyContent: "center", alignItems: "center" },
1423
+ stepCheck: { color: "#FFF", fontSize: 16, fontWeight: "700" },
1424
+ stepNum: { fontSize: 14, fontWeight: "700" },
1425
+ // Onboarding layout
1426
+ stepContainer: { flex: 1, justifyContent: "space-between", paddingBottom: 40 },
1427
+ stepTop: { gap: 8, paddingTop: 64 },
1428
+ headerRow: { flexDirection: "row", alignItems: "center", gap: 8, paddingHorizontal: 24 },
1429
+ backChevron: { fontSize: 32, fontWeight: "300", lineHeight: 36, marginTop: -2 },
1430
+ title: { fontSize: 28, fontWeight: "800", paddingHorizontal: 24 },
1431
+ titleInline: { fontSize: 28, fontWeight: "800" },
1432
+ subtitle: { fontSize: 15, paddingHorizontal: 24, lineHeight: 20 },
1433
+ // Avatar
1434
+ avatarCenter: { alignItems: "center", marginVertical: 12 },
1435
+ avatarFrame: { borderWidth: 3, borderRadius: 20, padding: 4 },
1436
+ avatarLarge: { width: 160, height: 160, borderRadius: 16, backgroundColor: "#E5E5EA" },
1437
+ checkBadge: { position: "absolute", bottom: -6, right: -6, width: 28, height: 28, borderRadius: 14, justifyContent: "center", alignItems: "center" },
1438
+ checkBadgeText: { color: "#FFF", fontSize: 15, fontWeight: "700" },
1439
+ avatarFrameSmall: { borderWidth: 3, borderRadius: 14, padding: 3 },
1440
+ avatarSmall: { width: 100, height: 100, borderRadius: 12, backgroundColor: "#E5E5EA" },
1441
+ checkBadgeSm: { position: "absolute", bottom: -4, right: -4, width: 22, height: 22, borderRadius: 11, justifyContent: "center", alignItems: "center" },
1442
+ checkBadgeTextSm: { color: "#FFF", fontSize: 12, fontWeight: "700" },
1443
+ avatarActions: { flexDirection: "row", justifyContent: "center", gap: 12, paddingHorizontal: 24 },
1444
+ outlineBtn: { borderWidth: 1.5, borderRadius: 12, paddingHorizontal: 20, paddingVertical: 12 },
1445
+ outlineBtnText: { fontSize: 15, fontWeight: "600" },
1446
+ styleScroll: { paddingHorizontal: 24, marginTop: 4 },
1447
+ styleThumbWrap: { borderWidth: 2, borderRadius: 12, padding: 3, marginRight: 10 },
1448
+ styleThumb: { width: 52, height: 52, borderRadius: 10, backgroundColor: "#E5E5EA" },
1449
+ // Input
1450
+ inputGroup: { paddingHorizontal: 24, gap: 6 },
1451
+ inputLabel: { fontSize: 15, fontWeight: "600" },
1452
+ input: { height: 56, borderRadius: 16, borderWidth: 1.5, paddingHorizontal: 16, fontSize: 16 },
1453
+ hint: { fontSize: 13, paddingLeft: 4 },
1454
+ // Profile card
1455
+ profileCard: { marginHorizontal: 24, borderWidth: 1, borderRadius: 16, padding: 16, gap: 12 },
1456
+ profileLabel: { fontSize: 13 },
1457
+ profileRow: { flexDirection: "row", alignItems: "center", gap: 14 },
1458
+ profileAvatar: { width: 56, height: 56, borderRadius: 12, backgroundColor: "#E5E5EA" },
1459
+ profileUsername: { fontSize: 20, fontWeight: "800" },
1460
+ profileReady: { fontSize: 14, fontWeight: "600" },
1461
+ // Buttons
1462
+ bottomRow: { flexDirection: "row", gap: 12, paddingHorizontal: 24 },
1463
+ primaryBtn: { height: 56, borderRadius: 16, justifyContent: "center", alignItems: "center" },
1464
+ primaryBtnText: { color: "#FFFFFF", fontSize: 18, fontWeight: "700" },
1465
+ secondaryBtn: { height: 56, borderRadius: 16, borderWidth: 1.5, justifyContent: "center", alignItems: "center", paddingHorizontal: 24 },
1466
+ secondaryBtnText: { fontSize: 16, fontWeight: "600" }
1467
+ });
1468
+
966
1469
  // src/ui/ConnectWalletScreen.tsx
967
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
1470
+ import {
1471
+ View as View2,
1472
+ Text as Text2,
1473
+ TouchableOpacity as TouchableOpacity2,
1474
+ ActivityIndicator as ActivityIndicator2,
1475
+ StyleSheet as StyleSheet2
1476
+ } from "react-native";
1477
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
968
1478
  function ConnectWalletScreen({
969
1479
  onConnect,
970
1480
  connecting = false,
@@ -972,38 +1482,38 @@ function ConnectWalletScreen({
972
1482
  appName = "Dubs"
973
1483
  }) {
974
1484
  const t = useDubsTheme();
975
- return /* @__PURE__ */ jsx2(View, { style: [styles.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs(View, { style: styles.content, children: [
976
- /* @__PURE__ */ jsxs(View, { style: styles.brandingSection, children: [
977
- /* @__PURE__ */ jsx2(View, { style: [styles.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ jsx2(Text, { style: styles.logoText, children: "D" }) }),
978
- /* @__PURE__ */ jsx2(Text, { style: [styles.appName, { color: t.text }], children: appName }),
979
- /* @__PURE__ */ jsx2(Text, { style: [styles.subtitle, { color: t.textMuted }], children: "Connect your Solana wallet to get started" })
1485
+ return /* @__PURE__ */ jsx3(View2, { style: [styles.container, { backgroundColor: t.background }], children: /* @__PURE__ */ jsxs2(View2, { style: styles.content, children: [
1486
+ /* @__PURE__ */ jsxs2(View2, { style: styles.brandingSection, children: [
1487
+ /* @__PURE__ */ jsx3(View2, { style: [styles.logoCircle, { backgroundColor: t.accent }], children: /* @__PURE__ */ jsx3(Text2, { style: styles.logoText, children: "D" }) }),
1488
+ /* @__PURE__ */ jsx3(Text2, { style: [styles.appName, { color: t.text }], children: appName }),
1489
+ /* @__PURE__ */ jsx3(Text2, { style: [styles.subtitle, { color: t.textMuted }], children: "Connect your Solana wallet to get started" })
980
1490
  ] }),
981
- /* @__PURE__ */ jsxs(View, { style: styles.actionSection, children: [
982
- error ? /* @__PURE__ */ jsx2(
983
- View,
1491
+ /* @__PURE__ */ jsxs2(View2, { style: styles.actionSection, children: [
1492
+ error ? /* @__PURE__ */ jsx3(
1493
+ View2,
984
1494
  {
985
1495
  style: [
986
1496
  styles.errorBox,
987
1497
  { backgroundColor: t.errorBg, borderColor: t.errorBorder }
988
1498
  ],
989
- children: /* @__PURE__ */ jsx2(Text, { style: [styles.errorText, { color: t.errorText }], children: error })
1499
+ children: /* @__PURE__ */ jsx3(Text2, { style: [styles.errorText, { color: t.errorText }], children: error })
990
1500
  }
991
1501
  ) : null,
992
- /* @__PURE__ */ jsx2(
993
- TouchableOpacity,
1502
+ /* @__PURE__ */ jsx3(
1503
+ TouchableOpacity2,
994
1504
  {
995
1505
  style: [styles.connectButton, { backgroundColor: t.accent }],
996
1506
  onPress: onConnect,
997
1507
  disabled: connecting,
998
1508
  activeOpacity: 0.8,
999
- children: connecting ? /* @__PURE__ */ jsx2(ActivityIndicator, { color: "#FFFFFF", size: "small" }) : /* @__PURE__ */ jsx2(Text, { style: styles.connectButtonText, children: "Connect Wallet" })
1509
+ children: connecting ? /* @__PURE__ */ jsx3(ActivityIndicator2, { color: "#FFFFFF", size: "small" }) : /* @__PURE__ */ jsx3(Text2, { style: styles.connectButtonText, children: "Connect Wallet" })
1000
1510
  }
1001
1511
  ),
1002
- /* @__PURE__ */ jsx2(Text, { style: [styles.hint, { color: t.textDim }], children: "Phantom, Solflare, or any Solana wallet" })
1512
+ /* @__PURE__ */ jsx3(Text2, { style: [styles.hint, { color: t.textDim }], children: "Phantom, Solflare, or any Solana wallet" })
1003
1513
  ] })
1004
1514
  ] }) });
1005
1515
  }
1006
- var styles = StyleSheet.create({
1516
+ var styles = StyleSheet2.create({
1007
1517
  container: {
1008
1518
  flex: 1,
1009
1519
  justifyContent: "center"
@@ -1073,8 +1583,8 @@ var styles = StyleSheet.create({
1073
1583
 
1074
1584
  // src/ui/UserProfileCard.tsx
1075
1585
  import { useMemo as useMemo2 } from "react";
1076
- import { View as View2, Text as Text2, Image, StyleSheet as StyleSheet2 } from "react-native";
1077
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1586
+ import { View as View3, Text as Text3, Image as Image2, StyleSheet as StyleSheet3 } from "react-native";
1587
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1078
1588
  function truncateAddress(address, chars = 4) {
1079
1589
  if (address.length <= chars * 2 + 3) return address;
1080
1590
  return `${address.slice(0, chars)}...${address.slice(-chars)}`;
@@ -1096,16 +1606,16 @@ function UserProfileCard({
1096
1606
  () => avatarUrl || `https://api.dicebear.com/9.x/avataaars/png?seed=${walletAddress}&size=128`,
1097
1607
  [avatarUrl, walletAddress]
1098
1608
  );
1099
- return /* @__PURE__ */ jsxs2(View2, { style: [styles2.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
1100
- /* @__PURE__ */ jsx3(Image, { source: { uri: imageUri }, style: styles2.avatar }),
1101
- /* @__PURE__ */ jsxs2(View2, { style: styles2.info, children: [
1102
- username ? /* @__PURE__ */ jsx3(Text2, { style: [styles2.username, { color: t.text }], children: username }) : null,
1103
- /* @__PURE__ */ jsx3(Text2, { style: [styles2.address, { color: t.textMuted }], children: truncateAddress(walletAddress) }),
1104
- memberSince ? /* @__PURE__ */ jsx3(Text2, { style: [styles2.memberSince, { color: t.textDim }], children: formatMemberSince(memberSince) }) : null
1609
+ return /* @__PURE__ */ jsxs3(View3, { style: [styles2.card, { backgroundColor: t.surface, borderColor: t.border }], children: [
1610
+ /* @__PURE__ */ jsx4(Image2, { source: { uri: imageUri }, style: styles2.avatar }),
1611
+ /* @__PURE__ */ jsxs3(View3, { style: styles2.info, children: [
1612
+ username ? /* @__PURE__ */ jsx4(Text3, { style: [styles2.username, { color: t.text }], children: username }) : null,
1613
+ /* @__PURE__ */ jsx4(Text3, { style: [styles2.address, { color: t.textMuted }], children: truncateAddress(walletAddress) }),
1614
+ memberSince ? /* @__PURE__ */ jsx4(Text3, { style: [styles2.memberSince, { color: t.textDim }], children: formatMemberSince(memberSince) }) : null
1105
1615
  ] })
1106
1616
  ] });
1107
1617
  }
1108
- var styles2 = StyleSheet2.create({
1618
+ var styles2 = StyleSheet3.create({
1109
1619
  card: {
1110
1620
  flexDirection: "row",
1111
1621
  alignItems: "center",
@@ -1140,14 +1650,14 @@ var styles2 = StyleSheet2.create({
1140
1650
 
1141
1651
  // src/ui/SettingsSheet.tsx
1142
1652
  import {
1143
- View as View3,
1144
- Text as Text3,
1145
- ScrollView,
1146
- TouchableOpacity as TouchableOpacity2,
1147
- ActivityIndicator as ActivityIndicator2,
1148
- StyleSheet as StyleSheet3
1653
+ View as View4,
1654
+ Text as Text4,
1655
+ ScrollView as ScrollView2,
1656
+ TouchableOpacity as TouchableOpacity3,
1657
+ ActivityIndicator as ActivityIndicator3,
1658
+ StyleSheet as StyleSheet4
1149
1659
  } from "react-native";
1150
- import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1660
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1151
1661
  function truncateAddress2(address, chars = 4) {
1152
1662
  if (address.length <= chars * 2 + 3) return address;
1153
1663
  return `${address.slice(0, chars)}...${address.slice(-chars)}`;
@@ -1164,13 +1674,13 @@ function SettingsSheet({
1164
1674
  loggingOut = false
1165
1675
  }) {
1166
1676
  const t = useDubsTheme();
1167
- return /* @__PURE__ */ jsxs3(
1168
- ScrollView,
1677
+ return /* @__PURE__ */ jsxs4(
1678
+ ScrollView2,
1169
1679
  {
1170
1680
  style: [styles3.container, { backgroundColor: t.background }],
1171
1681
  contentContainerStyle: styles3.content,
1172
1682
  children: [
1173
- /* @__PURE__ */ jsx4(
1683
+ /* @__PURE__ */ jsx5(
1174
1684
  UserProfileCard,
1175
1685
  {
1176
1686
  walletAddress,
@@ -1179,49 +1689,49 @@ function SettingsSheet({
1179
1689
  memberSince
1180
1690
  }
1181
1691
  ),
1182
- /* @__PURE__ */ jsxs3(View3, { style: [styles3.actionsCard, { backgroundColor: t.surface, borderColor: t.border }], children: [
1183
- onCopyAddress ? /* @__PURE__ */ jsxs3(
1184
- TouchableOpacity2,
1692
+ /* @__PURE__ */ jsxs4(View4, { style: [styles3.actionsCard, { backgroundColor: t.surface, borderColor: t.border }], children: [
1693
+ onCopyAddress ? /* @__PURE__ */ jsxs4(
1694
+ TouchableOpacity3,
1185
1695
  {
1186
1696
  style: styles3.actionRow,
1187
1697
  onPress: onCopyAddress,
1188
1698
  activeOpacity: 0.7,
1189
1699
  children: [
1190
- /* @__PURE__ */ jsxs3(View3, { style: styles3.actionRowLeft, children: [
1191
- /* @__PURE__ */ jsx4(Text3, { style: [styles3.actionLabel, { color: t.text }], children: "Wallet Address" }),
1192
- /* @__PURE__ */ jsx4(Text3, { style: [styles3.actionValue, { color: t.textMuted }], children: truncateAddress2(walletAddress) })
1700
+ /* @__PURE__ */ jsxs4(View4, { style: styles3.actionRowLeft, children: [
1701
+ /* @__PURE__ */ jsx5(Text4, { style: [styles3.actionLabel, { color: t.text }], children: "Wallet Address" }),
1702
+ /* @__PURE__ */ jsx5(Text4, { style: [styles3.actionValue, { color: t.textMuted }], children: truncateAddress2(walletAddress) })
1193
1703
  ] }),
1194
- /* @__PURE__ */ jsx4(Text3, { style: [styles3.copyLabel, { color: t.accent }], children: "Copy" })
1704
+ /* @__PURE__ */ jsx5(Text4, { style: [styles3.copyLabel, { color: t.accent }], children: "Copy" })
1195
1705
  ]
1196
1706
  }
1197
1707
  ) : null,
1198
- onSupport ? /* @__PURE__ */ jsxs3(Fragment, { children: [
1199
- onCopyAddress ? /* @__PURE__ */ jsx4(View3, { style: [styles3.separator, { backgroundColor: t.border }] }) : null,
1200
- /* @__PURE__ */ jsxs3(
1201
- TouchableOpacity2,
1708
+ onSupport ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
1709
+ onCopyAddress ? /* @__PURE__ */ jsx5(View4, { style: [styles3.separator, { backgroundColor: t.border }] }) : null,
1710
+ /* @__PURE__ */ jsxs4(
1711
+ TouchableOpacity3,
1202
1712
  {
1203
1713
  style: styles3.actionRow,
1204
1714
  onPress: onSupport,
1205
1715
  activeOpacity: 0.7,
1206
1716
  children: [
1207
- /* @__PURE__ */ jsx4(Text3, { style: [styles3.actionLabel, { color: t.text }], children: "Help & Support" }),
1208
- /* @__PURE__ */ jsx4(Text3, { style: [styles3.chevron, { color: t.textMuted }], children: "\u203A" })
1717
+ /* @__PURE__ */ jsx5(Text4, { style: [styles3.actionLabel, { color: t.text }], children: "Help & Support" }),
1718
+ /* @__PURE__ */ jsx5(Text4, { style: [styles3.chevron, { color: t.textMuted }], children: "\u203A" })
1209
1719
  ]
1210
1720
  }
1211
1721
  )
1212
1722
  ] }) : null
1213
1723
  ] }),
1214
- /* @__PURE__ */ jsx4(
1215
- TouchableOpacity2,
1724
+ /* @__PURE__ */ jsx5(
1725
+ TouchableOpacity3,
1216
1726
  {
1217
1727
  style: [styles3.logoutButton, { borderColor: t.live }],
1218
1728
  onPress: onLogout,
1219
1729
  disabled: loggingOut,
1220
1730
  activeOpacity: 0.7,
1221
- children: loggingOut ? /* @__PURE__ */ jsx4(ActivityIndicator2, { color: t.live, size: "small" }) : /* @__PURE__ */ jsx4(Text3, { style: [styles3.logoutText, { color: t.live }], children: "Log Out" })
1731
+ children: loggingOut ? /* @__PURE__ */ jsx5(ActivityIndicator3, { color: t.live, size: "small" }) : /* @__PURE__ */ jsx5(Text4, { style: [styles3.logoutText, { color: t.live }], children: "Log Out" })
1222
1732
  }
1223
1733
  ),
1224
- appVersion ? /* @__PURE__ */ jsxs3(Text3, { style: [styles3.version, { color: t.textDim }], children: [
1734
+ appVersion ? /* @__PURE__ */ jsxs4(Text4, { style: [styles3.version, { color: t.textDim }], children: [
1225
1735
  "v",
1226
1736
  appVersion
1227
1737
  ] }) : null
@@ -1229,7 +1739,7 @@ function SettingsSheet({
1229
1739
  }
1230
1740
  );
1231
1741
  }
1232
- var styles3 = StyleSheet3.create({
1742
+ var styles3 = StyleSheet4.create({
1233
1743
  container: {
1234
1744
  flex: 1
1235
1745
  },
@@ -1291,6 +1801,7 @@ var styles3 = StyleSheet3.create({
1291
1801
  }
1292
1802
  });
1293
1803
  export {
1804
+ AuthGate,
1294
1805
  ConnectWalletScreen,
1295
1806
  DEFAULT_BASE_URL,
1296
1807
  DEFAULT_RPC_URL,