@kryptos_connect/mobile-sdk 1.0.0 → 1.0.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.js CHANGED
@@ -38,8 +38,8 @@ __export(index_exports, {
38
38
  module.exports = __toCommonJS(index_exports);
39
39
 
40
40
  // src/KryptosConnectButton.tsx
41
- var import_react31 = __toESM(require("react"));
42
- var import_react_native17 = require("react-native");
41
+ var import_react36 = __toESM(require("react"));
42
+ var import_react_native21 = require("react-native");
43
43
 
44
44
  // src/assets/LogoIcon.tsx
45
45
  var import_react = __toESM(require("react"));
@@ -80,6 +80,152 @@ var LogoIcon = ({ size = 36 }) => {
80
80
 
81
81
  // src/contexts/KryptosContext.tsx
82
82
  var import_react2 = __toESM(require("react"));
83
+
84
+ // src/services/api.ts
85
+ var import_axios = __toESM(require("axios"));
86
+
87
+ // src/config/index.ts
88
+ var getBaseUrl = () => {
89
+ return getGlobalBaseUrl() || "https://connect-api.kryptos.io/";
90
+ };
91
+
92
+ // src/services/api.ts
93
+ var api = import_axios.default.create({
94
+ headers: {
95
+ "Content-Type": "application/json"
96
+ }
97
+ });
98
+ api.interceptors.request.use((config) => {
99
+ config.baseURL = getBaseUrl();
100
+ return config;
101
+ });
102
+ var SCOPES = "openid profile offline_access email portfolios:read transactions:read integrations:read tax:read accounting:read reports:read workspace:read users:read";
103
+ async function sendEmailOtp(linkToken, email, clientId) {
104
+ const res = await api.post(
105
+ "/v1/sendEmailOTP",
106
+ {
107
+ email,
108
+ purpose: "login",
109
+ clientId
110
+ },
111
+ {
112
+ headers: {
113
+ "X-LINK-TOKEN": linkToken
114
+ }
115
+ }
116
+ );
117
+ return res.data;
118
+ }
119
+ async function loginWithOtp(linkToken, email, code, clientId) {
120
+ const res = await api.post(
121
+ "/v1/loginUserUsingOTP",
122
+ {
123
+ email,
124
+ code,
125
+ clientId,
126
+ purpose: "login"
127
+ },
128
+ {
129
+ headers: {
130
+ "X-LINK-TOKEN": linkToken
131
+ }
132
+ }
133
+ );
134
+ return res.data;
135
+ }
136
+ async function createAnonymousUser(linkToken, clientId) {
137
+ const res = await api.post(
138
+ "/link-token/login",
139
+ { clientId },
140
+ {
141
+ headers: {
142
+ "X-LINK-TOKEN": linkToken
143
+ }
144
+ }
145
+ );
146
+ return res.data;
147
+ }
148
+ async function addUserIntegration(linkToken, integration) {
149
+ const res = await api.post(
150
+ "/integrations/keys",
151
+ { keys: [...integration] },
152
+ {
153
+ headers: {
154
+ "X-LINK-TOKEN": linkToken
155
+ }
156
+ }
157
+ );
158
+ return res.data?.data;
159
+ }
160
+ async function giveUserConsent(linkToken) {
161
+ const res = await api.post(
162
+ "/consent",
163
+ {
164
+ granted_scopes: SCOPES
165
+ },
166
+ {
167
+ headers: {
168
+ "X-LINK-TOKEN": linkToken
169
+ }
170
+ }
171
+ );
172
+ return res.data?.data;
173
+ }
174
+ async function testCredentials(linkToken, data) {
175
+ const res = await api.post("/integrations/credentials/test", data, {
176
+ headers: {
177
+ "X-LINK-TOKEN": linkToken
178
+ }
179
+ });
180
+ return res.data?.data;
181
+ }
182
+ async function getSupportedProviders(linkToken) {
183
+ const res = await api.get("/integrations/providers", {
184
+ headers: {
185
+ "X-LINK-TOKEN": linkToken
186
+ }
187
+ });
188
+ return res.data?.data;
189
+ }
190
+ async function getUserIntegrations(linkToken) {
191
+ const res = await api.get("/integrations", {
192
+ headers: {
193
+ "X-LINK-TOKEN": linkToken
194
+ }
195
+ });
196
+ return res.data?.data;
197
+ }
198
+ async function getUserUsedChains(linkToken, address) {
199
+ const res = await api.get("/integrations/user-used-chain", {
200
+ headers: {
201
+ "X-LINK-TOKEN": linkToken
202
+ },
203
+ params: {
204
+ id: address
205
+ }
206
+ });
207
+ return res.data?.data?.chains || [];
208
+ }
209
+ async function getClientInfo(linkToken) {
210
+ const res = await api.get("/client", {
211
+ headers: {
212
+ "X-LINK-TOKEN": linkToken
213
+ }
214
+ });
215
+ return res.data?.data;
216
+ }
217
+ async function getUserInfo(linkToken) {
218
+ const res = await api.get("/link-token/session", {
219
+ headers: {
220
+ "X-LINK-TOKEN": linkToken
221
+ }
222
+ });
223
+ return res.data?.data;
224
+ }
225
+
226
+ // src/contexts/KryptosContext.tsx
227
+ var globalBaseUrl;
228
+ var getGlobalBaseUrl = () => globalBaseUrl;
83
229
  var KryptosContext = import_react2.default.createContext(
84
230
  void 0
85
231
  );
@@ -91,6 +237,20 @@ var KryptosConnectProvider = ({ children, config }) => {
91
237
  const [userConsent, setUserConsent] = import_react2.default.useState(
92
238
  null
93
239
  );
240
+ const [isAuthorized, setIsAuthorized] = import_react2.default.useState(false);
241
+ const [clientInfo, setClientInfo] = import_react2.default.useState(null);
242
+ import_react2.default.useEffect(() => {
243
+ globalBaseUrl = config.baseUrl;
244
+ }, [config.baseUrl]);
245
+ import_react2.default.useEffect(() => {
246
+ const fetchClientInfo = async () => {
247
+ if (linkToken) {
248
+ const res = await getClientInfo(linkToken);
249
+ setClientInfo(res);
250
+ }
251
+ };
252
+ fetchClientInfo();
253
+ }, [linkToken]);
94
254
  return /* @__PURE__ */ import_react2.default.createElement(
95
255
  KryptosContext.Provider,
96
256
  {
@@ -105,7 +265,10 @@ var KryptosConnectProvider = ({ children, config }) => {
105
265
  email,
106
266
  setEmail,
107
267
  userConsent,
108
- setUserConsent
268
+ setUserConsent,
269
+ clientInfo,
270
+ isAuthorized,
271
+ setIsAuthorized
109
272
  }
110
273
  },
111
274
  children
@@ -142,6 +305,7 @@ var lightTheme = {
142
305
  successLight: "#D1FAE5",
143
306
  warning: "#F59E0B",
144
307
  warningLight: "#FEF3C7",
308
+ warningText: "#92400E",
145
309
  overlay: "rgba(0, 0, 0, 0.5)",
146
310
  white: "#FFFFFF",
147
311
  black: "#000000"
@@ -221,6 +385,7 @@ var darkTheme = {
221
385
  successLight: "#065F46",
222
386
  warning: "#F59E0B",
223
387
  warningLight: "#78350F",
388
+ warningText: "#FEF3C7",
224
389
  overlay: "rgba(0, 0, 0, 0.7)",
225
390
  white: "#FFFFFF",
226
391
  black: "#000000"
@@ -266,192 +431,56 @@ var useTheme = () => {
266
431
  return currentTheme;
267
432
  };
268
433
 
269
- // src/molecules/Auth.tsx
270
- var import_react12 = __toESM(require("react"));
271
- var import_react_native5 = require("react-native");
272
-
273
- // src/assets/LinkIcon.tsx
434
+ // src/components/Button.tsx
274
435
  var import_react4 = __toESM(require("react"));
275
- var import_react_native_svg2 = __toESM(require("react-native-svg"));
276
- var LinkIcon = ({
277
- size = 20,
278
- color = "#00C693"
279
- }) => {
280
- return /* @__PURE__ */ import_react4.default.createElement(import_react_native_svg2.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react4.default.createElement(
281
- import_react_native_svg2.Path,
282
- {
283
- d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",
284
- stroke: color,
285
- strokeWidth: 2,
286
- strokeLinecap: "round",
287
- strokeLinejoin: "round"
288
- }
289
- ), /* @__PURE__ */ import_react4.default.createElement(
290
- import_react_native_svg2.Path,
291
- {
292
- d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71",
293
- stroke: color,
294
- strokeWidth: 2,
295
- strokeLinecap: "round",
296
- strokeLinejoin: "round"
297
- }
298
- ));
299
- };
300
-
301
- // src/assets/ShieldIcon.tsx
302
- var import_react5 = __toESM(require("react"));
303
- var import_react_native_svg3 = __toESM(require("react-native-svg"));
304
- var ShieldIcon = ({
305
- size = 20,
306
- color = "#00C693"
307
- }) => {
308
- return /* @__PURE__ */ import_react5.default.createElement(import_react_native_svg3.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react5.default.createElement(
309
- import_react_native_svg3.Path,
310
- {
311
- d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",
312
- stroke: color,
313
- strokeWidth: 2,
314
- strokeLinecap: "round",
315
- strokeLinejoin: "round"
316
- }
317
- ), /* @__PURE__ */ import_react5.default.createElement(
318
- import_react_native_svg3.Path,
319
- {
320
- d: "m9 12 2 2 4-4",
321
- stroke: color,
322
- strokeWidth: 2,
323
- strokeLinecap: "round",
324
- strokeLinejoin: "round"
325
- }
326
- ));
327
- };
328
-
329
- // src/components/Alert.tsx
330
- var import_react6 = __toESM(require("react"));
331
436
  var import_react_native = require("react-native");
332
- var Alert = ({
333
- variant = "default",
437
+ var Button = ({
438
+ variant = "primary",
439
+ size = "md",
334
440
  children,
335
- style
441
+ onPress,
442
+ disabled = false,
443
+ loading = false,
444
+ style,
445
+ textStyle
336
446
  }) => {
337
447
  const theme = useTheme();
338
448
  const getVariantStyles = () => {
339
449
  switch (variant) {
340
- case "destructive":
450
+ case "primary":
341
451
  return {
342
- backgroundColor: theme.colors.errorLight,
343
- borderColor: theme.colors.error
452
+ backgroundColor: disabled ? theme.colors.textTertiary : theme.colors.primary,
453
+ borderWidth: 0
344
454
  };
345
- default:
455
+ case "secondary":
346
456
  return {
347
- backgroundColor: theme.colors.surface,
457
+ backgroundColor: disabled ? theme.colors.surfaceSecondary : theme.colors.surface,
458
+ borderWidth: 1,
348
459
  borderColor: theme.colors.border
349
460
  };
350
- }
351
- };
352
- return /* @__PURE__ */ import_react6.default.createElement(
353
- import_react_native.View,
354
- {
355
- style: [
356
- styles.alert,
357
- {
358
- borderRadius: theme.borderRadius.md,
359
- padding: theme.spacing.md
360
- },
361
- getVariantStyles(),
362
- style
363
- ]
364
- },
365
- children
366
- );
367
- };
368
- var AlertDescription = ({
369
- children,
370
- style
371
- }) => {
372
- const theme = useTheme();
373
- return /* @__PURE__ */ import_react6.default.createElement(
374
- import_react_native.Text,
375
- {
376
- style: [
377
- styles.description,
378
- {
379
- color: theme.colors.text,
380
- fontSize: theme.fontSize.md
381
- },
382
- style
383
- ]
384
- },
385
- children
386
- );
387
- };
388
- var styles = import_react_native.StyleSheet.create({
389
- alert: {
390
- borderWidth: 1,
391
- marginVertical: 12
392
- // theme.spacing.md - consistent alert spacing
393
- },
394
- title: {
395
- fontWeight: "600",
396
- marginBottom: 4
397
- // theme.spacing.xs
398
- },
399
- description: {
400
- lineHeight: 18,
401
- textAlign: "center"
402
- }
403
- });
404
-
405
- // src/components/Button.tsx
406
- var import_react7 = __toESM(require("react"));
407
- var import_react_native2 = require("react-native");
408
- var Button = ({
409
- variant = "primary",
410
- size = "md",
411
- children,
412
- onPress,
413
- disabled = false,
414
- loading = false,
415
- style,
416
- textStyle
417
- }) => {
418
- const theme = useTheme();
419
- const getVariantStyles = () => {
420
- switch (variant) {
421
- case "primary":
422
- return {
423
- backgroundColor: disabled ? theme.colors.textTertiary : theme.colors.primary,
424
- borderWidth: 0
425
- };
426
- case "secondary":
427
- return {
428
- backgroundColor: disabled ? theme.colors.surfaceSecondary : theme.colors.surface,
429
- borderWidth: 1,
430
- borderColor: theme.colors.border
431
- };
432
- case "outline":
433
- return {
434
- backgroundColor: "transparent",
435
- borderWidth: 1,
436
- borderColor: disabled ? theme.colors.textTertiary : theme.colors.primary
437
- };
438
- case "ghost":
439
- return {
440
- backgroundColor: "transparent",
441
- borderWidth: 0
442
- };
443
- case "success":
444
- return {
445
- backgroundColor: disabled ? theme.colors.textTertiary : theme.colors.success,
446
- borderWidth: 0
447
- };
448
- case "error":
449
- return {
450
- backgroundColor: disabled ? theme.colors.textTertiary : theme.colors.error,
451
- borderWidth: 0
452
- };
453
- default:
454
- return {};
461
+ case "outline":
462
+ return {
463
+ backgroundColor: "transparent",
464
+ borderWidth: 1,
465
+ borderColor: disabled ? theme.colors.textTertiary : theme.colors.primary
466
+ };
467
+ case "ghost":
468
+ return {
469
+ backgroundColor: "transparent",
470
+ borderWidth: 0
471
+ };
472
+ case "success":
473
+ return {
474
+ backgroundColor: disabled ? theme.colors.textTertiary : theme.colors.success,
475
+ borderWidth: 0
476
+ };
477
+ case "error":
478
+ return {
479
+ backgroundColor: disabled ? theme.colors.textTertiary : theme.colors.error,
480
+ borderWidth: 0
481
+ };
482
+ default:
483
+ return {};
455
484
  }
456
485
  };
457
486
  const getTextColor = () => {
@@ -516,35 +545,35 @@ var Button = ({
516
545
  }
517
546
  };
518
547
  const sizeStyles = getSizeStyles();
519
- return /* @__PURE__ */ import_react7.default.createElement(
520
- import_react_native2.TouchableOpacity,
548
+ return /* @__PURE__ */ import_react4.default.createElement(
549
+ import_react_native.TouchableOpacity,
521
550
  {
522
551
  onPress,
523
552
  disabled: disabled || loading,
524
553
  activeOpacity: 0.7,
525
554
  style: [
526
- styles2.button,
555
+ styles.button,
527
556
  getVariantStyles(),
528
557
  sizeStyles.button,
529
- disabled && styles2.disabled,
558
+ disabled && styles.disabled,
530
559
  style
531
560
  ]
532
561
  },
533
- loading ? /* @__PURE__ */ import_react7.default.createElement(import_react_native2.ActivityIndicator, { size: "small", color: getTextColor() }) : typeof children === "string" ? /* @__PURE__ */ import_react7.default.createElement(
534
- import_react_native2.Text,
562
+ loading ? /* @__PURE__ */ import_react4.default.createElement(import_react_native.ActivityIndicator, { size: "small", color: getTextColor() }) : typeof children === "string" ? /* @__PURE__ */ import_react4.default.createElement(
563
+ import_react_native.Text,
535
564
  {
536
565
  style: [
537
- styles2.text,
566
+ styles.text,
538
567
  { color: getTextColor() },
539
568
  sizeStyles.text,
540
569
  textStyle
541
570
  ]
542
571
  },
543
572
  children
544
- ) : /* @__PURE__ */ import_react7.default.createElement(import_react_native2.View, { style: styles2.contentContainer }, children)
573
+ ) : /* @__PURE__ */ import_react4.default.createElement(import_react_native.View, { style: styles.contentContainer }, children)
545
574
  );
546
575
  };
547
- var styles2 = import_react_native2.StyleSheet.create({
576
+ var styles = import_react_native.StyleSheet.create({
548
577
  button: {
549
578
  flexDirection: "row",
550
579
  alignItems: "center",
@@ -565,165 +594,342 @@ var styles2 = import_react_native2.StyleSheet.create({
565
594
  }
566
595
  });
567
596
 
568
- // src/components/Modal.tsx
569
- var import_react9 = __toESM(require("react"));
570
- var import_react_native3 = require("react-native");
571
-
572
- // src/assets/CloseIcon.tsx
573
- var import_react8 = __toESM(require("react"));
574
- var import_react_native_svg4 = __toESM(require("react-native-svg"));
575
- var CloseIcon = ({
576
- size = 20,
577
- color = "#000"
578
- }) => {
579
- return /* @__PURE__ */ import_react8.default.createElement(import_react_native_svg4.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none" }, /* @__PURE__ */ import_react8.default.createElement(
580
- import_react_native_svg4.Path,
581
- {
582
- d: "M15 5L5 15M5 5L15 15",
583
- stroke: color,
584
- strokeWidth: 2,
585
- strokeLinecap: "round",
586
- strokeLinejoin: "round"
587
- }
588
- ));
589
- };
590
-
591
- // src/components/Modal.tsx
592
- var { height: SCREEN_HEIGHT } = import_react_native3.Dimensions.get("window");
593
- var Modal = ({
594
- isOpen,
595
- onClose,
596
- children,
597
- size = "md",
598
- closeOnOverlayClick = true,
599
- disableClose = true,
600
- style
597
+ // src/components/Input.tsx
598
+ var import_react5 = __toESM(require("react"));
599
+ var import_react_native2 = require("react-native");
600
+ var Input = ({
601
+ label,
602
+ error,
603
+ helperText,
604
+ status = "default",
605
+ containerStyle,
606
+ inputStyle,
607
+ labelStyle,
608
+ ...props
601
609
  }) => {
602
610
  const theme = useTheme();
603
- const getSizeStyles = () => {
604
- switch (size) {
605
- case "xs":
606
- return { maxHeight: SCREEN_HEIGHT * 0.35 };
607
- case "sm":
608
- return { maxHeight: SCREEN_HEIGHT * 0.45 };
609
- case "md":
610
- return { maxHeight: SCREEN_HEIGHT * 0.55 };
611
- case "lg":
612
- return { maxHeight: SCREEN_HEIGHT * 0.65 };
613
- case "xl":
614
- return { maxHeight: SCREEN_HEIGHT * 0.75 };
615
- case "full":
616
- return { maxHeight: SCREEN_HEIGHT * 0.85 };
611
+ const inputStatus = error ? "error" : status;
612
+ const getBorderColor = () => {
613
+ switch (inputStatus) {
614
+ case "error":
615
+ return theme.colors.error;
616
+ case "success":
617
+ return theme.colors.success;
617
618
  default:
618
- return { maxHeight: SCREEN_HEIGHT * 0.6 };
619
+ return theme.colors.border;
619
620
  }
620
621
  };
621
- const handleOverlayPress = () => {
622
- if (!disableClose && closeOnOverlayClick) onClose();
623
- };
624
- return /* @__PURE__ */ import_react9.default.createElement(
625
- import_react_native3.KeyboardAvoidingView,
622
+ return /* @__PURE__ */ import_react5.default.createElement(import_react_native2.View, { style: [styles2.wrapper, containerStyle] }, label && /* @__PURE__ */ import_react5.default.createElement(
623
+ import_react_native2.Text,
626
624
  {
627
- behavior: import_react_native3.Platform.OS === "ios" ? "padding" : "height",
628
- style: styles3.keyboardView
625
+ style: [
626
+ styles2.label,
627
+ { color: theme.colors.text, fontSize: theme.fontSize.sm },
628
+ labelStyle
629
+ ]
629
630
  },
630
- /* @__PURE__ */ import_react9.default.createElement(
631
- import_react_native3.Modal,
632
- {
633
- visible: isOpen,
634
- transparent: true,
635
- animationType: "none",
636
- statusBarTranslucent: true,
637
- onRequestClose: disableClose ? void 0 : onClose
638
- },
639
- /* @__PURE__ */ import_react9.default.createElement(
640
- import_react_native3.TouchableOpacity,
641
- {
642
- activeOpacity: 1,
643
- style: [styles3.overlay, { backgroundColor: theme.colors.overlay }],
644
- onPress: handleOverlayPress
645
- },
646
- /* @__PURE__ */ import_react9.default.createElement(
647
- import_react_native3.View,
648
- {
649
- style: [
650
- styles3.container,
651
- {
652
- backgroundColor: theme.colors.background,
653
- borderTopLeftRadius: theme.borderRadius.xl,
654
- borderTopRightRadius: theme.borderRadius.xl,
655
- ...theme.shadow.lg,
656
- paddingBottom: theme.spacing.xl
657
- // 20
658
- },
659
- getSizeStyles(),
660
- style
661
- ],
662
- onStartShouldSetResponder: () => true
663
- },
664
- children
665
- )
666
- )
667
- )
668
- );
669
- };
670
- var ModalHeader = ({
671
- children,
672
- onClose,
673
- showCloseButton = true,
674
- style
675
- }) => {
676
- const theme = useTheme();
677
- return /* @__PURE__ */ import_react9.default.createElement(
678
- import_react_native3.View,
631
+ label
632
+ ), /* @__PURE__ */ import_react5.default.createElement(
633
+ import_react_native2.TextInput,
679
634
  {
635
+ placeholderTextColor: theme.colors.textTertiary,
680
636
  style: [
681
- styles3.header,
637
+ styles2.input,
682
638
  {
683
- borderBottomColor: theme.colors.border,
639
+ backgroundColor: theme.colors.surface,
640
+ borderColor: getBorderColor(),
641
+ color: theme.colors.text,
642
+ fontSize: theme.fontSize.md,
643
+ borderRadius: theme.borderRadius.md,
684
644
  paddingHorizontal: theme.spacing.lg,
685
645
  paddingVertical: theme.spacing.md
686
646
  },
687
- style
647
+ inputStyle
648
+ ],
649
+ ...props
650
+ }
651
+ ), error && /* @__PURE__ */ import_react5.default.createElement(
652
+ import_react_native2.Text,
653
+ {
654
+ style: [
655
+ styles2.error,
656
+ { color: theme.colors.error, fontSize: theme.fontSize.sm }
688
657
  ]
689
658
  },
690
- /* @__PURE__ */ import_react9.default.createElement(import_react_native3.View, { style: styles3.headerContent }, typeof children === "string" ? /* @__PURE__ */ import_react9.default.createElement(
691
- import_react_native3.Text,
692
- {
693
- style: [
694
- styles3.title,
695
- { color: theme.colors.text, fontSize: theme.fontSize.lg }
696
- ]
697
- },
698
- children
699
- ) : children),
700
- showCloseButton && onClose && /* @__PURE__ */ import_react9.default.createElement(
701
- import_react_native3.TouchableOpacity,
702
- {
703
- onPress: onClose,
704
- hitSlop: { top: 10, bottom: 10, left: 10, right: 10 },
705
- style: [
706
- styles3.closeButton,
707
- { backgroundColor: theme.colors.surface }
708
- ]
709
- },
710
- /* @__PURE__ */ import_react9.default.createElement(CloseIcon, { color: theme.colors.text, size: 20 })
711
- )
712
- );
659
+ error
660
+ ), helperText && !error && /* @__PURE__ */ import_react5.default.createElement(
661
+ import_react_native2.Text,
662
+ {
663
+ style: [
664
+ styles2.helper,
665
+ {
666
+ color: theme.colors.textSecondary,
667
+ fontSize: theme.fontSize.sm
668
+ }
669
+ ]
670
+ },
671
+ helperText
672
+ ));
713
673
  };
714
- var ModalBody = ({
715
- children,
716
- style,
717
- scrollable = true
718
- }) => {
719
- const theme = useTheme();
720
- if (scrollable) {
721
- return /* @__PURE__ */ import_react9.default.createElement(
722
- import_react_native3.ScrollView,
723
- {
724
- style: styles3.bodyScroll,
674
+ var styles2 = import_react_native2.StyleSheet.create({
675
+ wrapper: {
676
+ marginBottom: 16
677
+ // theme.spacing.lg - consistent form spacing
678
+ },
679
+ label: {
680
+ fontWeight: "500",
681
+ marginBottom: 8
682
+ // theme.spacing.sm
683
+ },
684
+ input: {
685
+ borderWidth: 1,
686
+ minHeight: 48
687
+ },
688
+ error: {
689
+ marginTop: 4
690
+ // theme.spacing.xs
691
+ },
692
+ helper: {
693
+ marginTop: 4
694
+ // theme.spacing.xs
695
+ }
696
+ });
697
+
698
+ // src/components/Alert.tsx
699
+ var import_react6 = __toESM(require("react"));
700
+ var import_react_native3 = require("react-native");
701
+ var Alert = ({
702
+ variant = "default",
703
+ children,
704
+ style
705
+ }) => {
706
+ const theme = useTheme();
707
+ const getVariantStyles = () => {
708
+ switch (variant) {
709
+ case "destructive":
710
+ return {
711
+ backgroundColor: theme.colors.errorLight,
712
+ borderColor: theme.colors.error
713
+ };
714
+ default:
715
+ return {
716
+ backgroundColor: theme.colors.surface,
717
+ borderColor: theme.colors.border
718
+ };
719
+ }
720
+ };
721
+ return /* @__PURE__ */ import_react6.default.createElement(
722
+ import_react_native3.View,
723
+ {
724
+ style: [
725
+ styles3.alert,
726
+ {
727
+ borderRadius: theme.borderRadius.md,
728
+ padding: theme.spacing.md
729
+ },
730
+ getVariantStyles(),
731
+ style
732
+ ]
733
+ },
734
+ children
735
+ );
736
+ };
737
+ var AlertDescription = ({
738
+ children,
739
+ style
740
+ }) => {
741
+ const theme = useTheme();
742
+ return /* @__PURE__ */ import_react6.default.createElement(
743
+ import_react_native3.Text,
744
+ {
745
+ style: [
746
+ styles3.description,
747
+ {
748
+ color: theme.colors.text,
749
+ fontSize: theme.fontSize.md
750
+ },
751
+ style
752
+ ]
753
+ },
754
+ children
755
+ );
756
+ };
757
+ var styles3 = import_react_native3.StyleSheet.create({
758
+ alert: {
759
+ borderWidth: 1,
760
+ marginVertical: 12
761
+ // theme.spacing.md - consistent alert spacing
762
+ },
763
+ title: {
764
+ fontWeight: "600",
765
+ marginBottom: 4
766
+ // theme.spacing.xs
767
+ },
768
+ description: {
769
+ lineHeight: 18,
770
+ textAlign: "center"
771
+ }
772
+ });
773
+
774
+ // src/components/Modal.tsx
775
+ var import_react8 = __toESM(require("react"));
776
+ var import_react_native4 = require("react-native");
777
+
778
+ // src/assets/CloseIcon.tsx
779
+ var import_react7 = __toESM(require("react"));
780
+ var import_react_native_svg2 = __toESM(require("react-native-svg"));
781
+ var CloseIcon = ({
782
+ size = 20,
783
+ color = "#000"
784
+ }) => {
785
+ return /* @__PURE__ */ import_react7.default.createElement(import_react_native_svg2.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none" }, /* @__PURE__ */ import_react7.default.createElement(
786
+ import_react_native_svg2.Path,
787
+ {
788
+ d: "M15 5L5 15M5 5L15 15",
789
+ stroke: color,
790
+ strokeWidth: 2,
791
+ strokeLinecap: "round",
792
+ strokeLinejoin: "round"
793
+ }
794
+ ));
795
+ };
796
+
797
+ // src/components/Modal.tsx
798
+ var { height: SCREEN_HEIGHT } = import_react_native4.Dimensions.get("window");
799
+ var Modal = ({
800
+ isOpen,
801
+ onClose,
802
+ children,
803
+ size = "md",
804
+ closeOnOverlayClick = true,
805
+ disableClose = true,
806
+ style
807
+ }) => {
808
+ const theme = useTheme();
809
+ const getSizeStyles = () => {
810
+ switch (size) {
811
+ case "xs":
812
+ return { maxHeight: SCREEN_HEIGHT * 0.35 };
813
+ case "sm":
814
+ return { maxHeight: SCREEN_HEIGHT * 0.45 };
815
+ case "md":
816
+ return { maxHeight: SCREEN_HEIGHT * 0.55 };
817
+ case "lg":
818
+ return { maxHeight: SCREEN_HEIGHT * 0.65 };
819
+ case "xl":
820
+ return { maxHeight: SCREEN_HEIGHT * 0.75 };
821
+ case "full":
822
+ return { maxHeight: SCREEN_HEIGHT * 0.85 };
823
+ default:
824
+ return { maxHeight: SCREEN_HEIGHT * 0.6 };
825
+ }
826
+ };
827
+ const handleOverlayPress = () => {
828
+ if (!disableClose && closeOnOverlayClick) onClose();
829
+ };
830
+ return /* @__PURE__ */ import_react8.default.createElement(
831
+ import_react_native4.KeyboardAvoidingView,
832
+ {
833
+ behavior: import_react_native4.Platform.OS === "ios" ? "padding" : "height",
834
+ style: styles4.keyboardView
835
+ },
836
+ /* @__PURE__ */ import_react8.default.createElement(
837
+ import_react_native4.Modal,
838
+ {
839
+ visible: isOpen,
840
+ transparent: true,
841
+ animationType: "none",
842
+ statusBarTranslucent: true,
843
+ onRequestClose: disableClose ? void 0 : onClose
844
+ },
845
+ /* @__PURE__ */ import_react8.default.createElement(
846
+ import_react_native4.TouchableOpacity,
847
+ {
848
+ activeOpacity: 1,
849
+ style: [styles4.overlay, { backgroundColor: theme.colors.overlay }],
850
+ onPress: handleOverlayPress
851
+ },
852
+ /* @__PURE__ */ import_react8.default.createElement(
853
+ import_react_native4.View,
854
+ {
855
+ style: [
856
+ styles4.container,
857
+ {
858
+ backgroundColor: theme.colors.background,
859
+ borderTopLeftRadius: theme.borderRadius.xl,
860
+ borderTopRightRadius: theme.borderRadius.xl,
861
+ ...theme.shadow.lg,
862
+ paddingBottom: theme.spacing.xl
863
+ // 20
864
+ },
865
+ getSizeStyles(),
866
+ style
867
+ ],
868
+ onStartShouldSetResponder: () => true
869
+ },
870
+ children
871
+ )
872
+ )
873
+ )
874
+ );
875
+ };
876
+ var ModalHeader = ({
877
+ children,
878
+ onClose,
879
+ showCloseButton = true,
880
+ style
881
+ }) => {
882
+ const theme = useTheme();
883
+ return /* @__PURE__ */ import_react8.default.createElement(
884
+ import_react_native4.View,
885
+ {
886
+ style: [
887
+ styles4.header,
888
+ {
889
+ borderBottomColor: theme.colors.border,
890
+ paddingHorizontal: theme.spacing.lg,
891
+ paddingVertical: theme.spacing.md
892
+ },
893
+ style
894
+ ]
895
+ },
896
+ /* @__PURE__ */ import_react8.default.createElement(import_react_native4.View, { style: styles4.headerContent }, typeof children === "string" ? /* @__PURE__ */ import_react8.default.createElement(
897
+ import_react_native4.Text,
898
+ {
899
+ style: [
900
+ styles4.title,
901
+ { color: theme.colors.text, fontSize: theme.fontSize.lg }
902
+ ]
903
+ },
904
+ children
905
+ ) : children),
906
+ showCloseButton && onClose && /* @__PURE__ */ import_react8.default.createElement(
907
+ import_react_native4.TouchableOpacity,
908
+ {
909
+ onPress: onClose,
910
+ hitSlop: { top: 10, bottom: 10, left: 10, right: 10 },
911
+ style: [
912
+ styles4.closeButton,
913
+ { backgroundColor: theme.colors.surface }
914
+ ]
915
+ },
916
+ /* @__PURE__ */ import_react8.default.createElement(CloseIcon, { color: theme.colors.text, size: 20 })
917
+ )
918
+ );
919
+ };
920
+ var ModalBody = ({
921
+ children,
922
+ style,
923
+ scrollable = true
924
+ }) => {
925
+ const theme = useTheme();
926
+ if (scrollable) {
927
+ return /* @__PURE__ */ import_react8.default.createElement(
928
+ import_react_native4.ScrollView,
929
+ {
930
+ style: styles4.bodyScroll,
725
931
  contentContainerStyle: [
726
- styles3.bodyContent,
932
+ styles4.bodyContent,
727
933
  { padding: theme.spacing.lg },
728
934
  style
729
935
  ],
@@ -733,18 +939,18 @@ var ModalBody = ({
733
939
  children
734
940
  );
735
941
  }
736
- return /* @__PURE__ */ import_react9.default.createElement(import_react_native3.View, { style: [styles3.body, { padding: theme.spacing.lg }, style] }, children);
942
+ return /* @__PURE__ */ import_react8.default.createElement(import_react_native4.View, { style: [styles4.body, { padding: theme.spacing.lg }, style] }, children);
737
943
  };
738
944
  var ModalFooter = ({
739
945
  children,
740
946
  style
741
947
  }) => {
742
948
  const theme = useTheme();
743
- return /* @__PURE__ */ import_react9.default.createElement(
744
- import_react_native3.View,
949
+ return /* @__PURE__ */ import_react8.default.createElement(
950
+ import_react_native4.View,
745
951
  {
746
952
  style: [
747
- styles3.footer,
953
+ styles4.footer,
748
954
  {
749
955
  borderTopColor: theme.colors.border,
750
956
  paddingHorizontal: theme.spacing.lg,
@@ -756,7 +962,7 @@ var ModalFooter = ({
756
962
  children
757
963
  );
758
964
  };
759
- var styles3 = import_react_native3.StyleSheet.create({
965
+ var styles4 = import_react_native4.StyleSheet.create({
760
966
  keyboardView: {
761
967
  flex: 1
762
968
  },
@@ -809,730 +1015,754 @@ var styles3 = import_react_native3.StyleSheet.create({
809
1015
  flex: 1
810
1016
  },
811
1017
  footer: {
812
- borderTopWidth: 1
1018
+ borderTopWidth: 1,
1019
+ marginBottom: 24
813
1020
  }
814
1021
  });
815
1022
 
816
- // src/services/api.ts
817
- var import_axios = __toESM(require("axios"));
818
-
819
- // src/config/index.ts
820
- var BASE_URL = "https://connect-api-dev.kryptos.io/";
821
-
822
- // src/services/api.ts
823
- var api = import_axios.default.create({
824
- baseURL: BASE_URL,
825
- headers: {
826
- "Content-Type": "application/json"
827
- }
828
- });
829
- var SCOPES = "openid profile offline_access email portfolios:read transactions:read integrations:read tax:read accounting:read reports:read workspace:read users:read";
830
- async function sendEmailOtp(linkToken, email, clientId) {
831
- const res = await api.post(
832
- "/v1/sendEmailOTP",
833
- {
834
- email,
835
- purpose: "login",
836
- clientId
837
- },
838
- {
839
- headers: {
840
- "X-LINK-TOKEN": linkToken
841
- }
842
- }
1023
+ // src/components/OTP.tsx
1024
+ var import_react9 = __toESM(require("react"));
1025
+ var import_react_native5 = require("react-native");
1026
+ var OTP = ({
1027
+ length = 6,
1028
+ value = "",
1029
+ onChange,
1030
+ onComplete,
1031
+ error,
1032
+ label,
1033
+ disabled = false,
1034
+ containerStyle,
1035
+ inputStyle,
1036
+ setErrorMessage
1037
+ }) => {
1038
+ const theme = useTheme();
1039
+ const AUTO_SUBMIT_DELAY = 500;
1040
+ const [otp, setOtp] = import_react9.default.useState(
1041
+ value.split("").concat(Array(length).fill("")).slice(0, length)
843
1042
  );
844
- return res.data;
845
- }
846
- async function loginWithOtp(linkToken, email, code, clientId) {
847
- const res = await api.post(
848
- "/v1/loginUserUsingOTP",
849
- {
850
- email,
851
- code,
852
- clientId,
853
- purpose: "login"
854
- },
855
- {
856
- headers: {
857
- "X-LINK-TOKEN": linkToken
858
- }
1043
+ const inputRefs = import_react9.default.useRef([]);
1044
+ import_react9.default.useEffect(() => {
1045
+ const isComplete = otp.every((digit) => digit !== "");
1046
+ let timer;
1047
+ if (isComplete && onComplete) {
1048
+ timer = setTimeout(() => {
1049
+ onComplete(otp.join(""));
1050
+ }, AUTO_SUBMIT_DELAY);
859
1051
  }
860
- );
861
- return res.data;
862
- }
863
- async function createAnonymousUser(linkToken, clientId) {
864
- const res = await api.post(
865
- "/link-token/login",
866
- { clientId },
867
- {
868
- headers: {
869
- "X-LINK-TOKEN": linkToken
1052
+ return () => {
1053
+ if (timer) clearTimeout(timer);
1054
+ };
1055
+ }, [otp, onComplete]);
1056
+ import_react9.default.useEffect(() => {
1057
+ setTimeout(() => {
1058
+ inputRefs.current[0]?.focus();
1059
+ }, 100);
1060
+ }, []);
1061
+ const handleChange = import_react9.default.useCallback(
1062
+ (index, val) => {
1063
+ if (disabled) return;
1064
+ setErrorMessage("");
1065
+ const numericValue = val.replace(/[^0-9]/g, "");
1066
+ const newValue = numericValue.slice(-1);
1067
+ if (val && !numericValue) {
1068
+ return;
870
1069
  }
871
- }
872
- );
873
- return res.data;
874
- }
875
- async function addUserIntegration(linkToken, integration) {
876
- const res = await api.post(
877
- "/integrations/keys",
878
- { keys: [...integration] },
879
- {
880
- headers: {
881
- "X-LINK-TOKEN": linkToken
1070
+ const newOtp = [...otp];
1071
+ newOtp[index] = newValue;
1072
+ setOtp(newOtp);
1073
+ const otpString = newOtp.join("");
1074
+ onChange?.(otpString);
1075
+ if (newValue && index < length - 1) {
1076
+ inputRefs.current[index + 1]?.focus();
882
1077
  }
883
- }
884
- );
885
- return res.data?.data;
886
- }
887
- async function giveUserConsent(linkToken) {
888
- const res = await api.post(
889
- "/consent",
890
- {
891
- granted_scopes: SCOPES
892
- },
893
- {
894
- headers: {
895
- "X-LINK-TOKEN": linkToken
1078
+ if (otpString.length === length && !otpString.includes("")) {
1079
+ onComplete?.(otpString);
896
1080
  }
897
- }
898
- );
899
- return res.data?.data;
900
- }
901
- async function testCredentials(linkToken, data) {
902
- const res = await api.post("/integrations/credentials/test", data, {
903
- headers: {
904
- "X-LINK-TOKEN": linkToken
905
- }
906
- });
907
- return res.data?.data;
908
- }
909
- async function getSupportedProviders(linkToken) {
910
- const res = await api.get("/integrations/providers", {
911
- headers: {
912
- "X-LINK-TOKEN": linkToken
913
- }
914
- });
915
- return res.data?.data;
916
- }
917
- async function getUserIntegrations(linkToken) {
918
- const res = await api.get("/integrations", {
919
- headers: {
920
- "X-LINK-TOKEN": linkToken
921
- }
922
- });
923
- return res.data?.data;
924
- }
925
- async function getUserUsedChains(linkToken, address) {
926
- const res = await api.get("/integrations/user-used-chain", {
927
- headers: {
928
- "X-LINK-TOKEN": linkToken
929
1081
  },
930
- params: {
931
- id: address
932
- }
933
- });
934
- return res.data?.data?.chains || [];
935
- }
936
-
937
- // src/molecules/ConnectLogo.tsx
938
- var import_react11 = __toESM(require("react"));
939
- var import_react_native4 = require("react-native");
940
-
941
- // src/assets/UnplugIcon.tsx
942
- var import_react10 = __toESM(require("react"));
943
- var import_react_native_svg5 = __toESM(require("react-native-svg"));
944
- var UnplugIcon = ({
945
- size = 24,
946
- color = "#6B7280"
947
- }) => {
948
- return /* @__PURE__ */ import_react10.default.createElement(import_react_native_svg5.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react10.default.createElement(
949
- import_react_native_svg5.Path,
950
- {
951
- d: "m19 5 3-3",
952
- stroke: color,
953
- strokeWidth: 2,
954
- strokeLinecap: "round",
955
- strokeLinejoin: "round"
956
- }
957
- ), /* @__PURE__ */ import_react10.default.createElement(
958
- import_react_native_svg5.Path,
959
- {
960
- d: "m2 22 3-3",
961
- stroke: color,
962
- strokeWidth: 2,
963
- strokeLinecap: "round",
964
- strokeLinejoin: "round"
965
- }
966
- ), /* @__PURE__ */ import_react10.default.createElement(
967
- import_react_native_svg5.Path,
968
- {
969
- d: "M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z",
970
- stroke: color,
971
- strokeWidth: 2,
972
- strokeLinecap: "round",
973
- strokeLinejoin: "round"
974
- }
975
- ), /* @__PURE__ */ import_react10.default.createElement(
976
- import_react_native_svg5.Path,
977
- {
978
- d: "m18 12-6-6 2.3-2.3a2.4 2.4 0 0 1 3.4 0l2.6 2.6a2.4 2.4 0 0 1 0 3.4Z",
979
- stroke: color,
980
- strokeWidth: 2,
981
- strokeLinecap: "round",
982
- strokeLinejoin: "round"
983
- }
984
- ), /* @__PURE__ */ import_react10.default.createElement(
985
- import_react_native_svg5.Line,
986
- {
987
- x1: 7.5,
988
- y1: 13.5,
989
- x2: 10.5,
990
- y2: 10.5,
991
- stroke: color,
992
- strokeWidth: 2,
993
- strokeLinecap: "round"
994
- }
995
- ));
996
- };
997
-
998
- // src/molecules/ConnectLogo.tsx
999
- var KryptosLogo = () => {
1000
- const theme = useTheme();
1001
- return /* @__PURE__ */ import_react11.default.createElement(
1002
- import_react_native4.View,
1003
- {
1004
- style: [styles4.logoContainer, { backgroundColor: theme.colors.surface }]
1005
- },
1006
- /* @__PURE__ */ import_react11.default.createElement(LogoIcon, { size: 36 })
1082
+ [otp, length, onChange, onComplete, disabled]
1007
1083
  );
1008
- };
1009
- var ConnectLogo = () => {
1010
- const { appName, appLogo } = useKryptosConnect();
1011
- const theme = useTheme();
1012
- const isValidUrl = (str) => {
1013
- try {
1014
- new URL(str);
1015
- return true;
1016
- } catch {
1017
- return false;
1018
- }
1019
- };
1020
- const renderLogo = () => {
1021
- if ((0, import_react11.isValidElement)(appLogo)) {
1022
- return appLogo;
1023
- } else if (typeof appLogo === "string" && isValidUrl(appLogo)) {
1024
- return /* @__PURE__ */ import_react11.default.createElement(
1025
- import_react_native4.Image,
1026
- {
1027
- source: { uri: appLogo },
1028
- style: styles4.appLogoImage,
1029
- resizeMode: "contain"
1030
- }
1031
- );
1032
- } else if (typeof appLogo === "number" || typeof appLogo === "object" && appLogo !== null) {
1033
- return /* @__PURE__ */ import_react11.default.createElement(
1034
- import_react_native4.Image,
1035
- {
1036
- source: appLogo,
1037
- style: styles4.appLogoImage,
1038
- resizeMode: "contain"
1084
+ const handleKeyPress = import_react9.default.useCallback(
1085
+ (index, e) => {
1086
+ if (disabled) return;
1087
+ if (e.nativeEvent.key === "Backspace") {
1088
+ if (!otp[index] && index > 0) {
1089
+ inputRefs.current[index - 1]?.focus();
1090
+ } else {
1091
+ const newOtp = [...otp];
1092
+ newOtp[index] = "";
1093
+ setOtp(newOtp);
1094
+ onChange?.(newOtp.join(""));
1039
1095
  }
1040
- );
1041
- } else if (appName) {
1042
- return /* @__PURE__ */ import_react11.default.createElement(import_react_native4.Text, { style: [styles4.appLogoText, { color: theme.colors.text }] }, appName.charAt(0).toUpperCase());
1043
- }
1044
- return /* @__PURE__ */ import_react11.default.createElement(import_react_native4.Text, { style: [styles4.appLogoText, { color: theme.colors.text }] }, "?");
1096
+ }
1097
+ },
1098
+ [otp, onChange, disabled]
1099
+ );
1100
+ const getBorderColor = (index) => {
1101
+ if (error) return theme.colors.error;
1102
+ if (otp[index]) return theme.colors.success;
1103
+ return theme.colors.border;
1045
1104
  };
1046
- return /* @__PURE__ */ import_react11.default.createElement(import_react_native4.View, { style: styles4.container }, /* @__PURE__ */ import_react11.default.createElement(KryptosLogo, null), /* @__PURE__ */ import_react11.default.createElement(import_react_native4.View, { style: styles4.iconContainer }, /* @__PURE__ */ import_react11.default.createElement(UnplugIcon, { size: 24, color: theme.colors.textSecondary })), /* @__PURE__ */ import_react11.default.createElement(
1047
- import_react_native4.View,
1105
+ return /* @__PURE__ */ import_react9.default.createElement(import_react_native5.View, { style: [styles5.wrapper, containerStyle] }, label && /* @__PURE__ */ import_react9.default.createElement(
1106
+ import_react_native5.Text,
1048
1107
  {
1049
1108
  style: [
1050
- styles4.logoContainer,
1051
- { backgroundColor: theme.colors.surface }
1109
+ styles5.label,
1110
+ { color: theme.colors.text, fontSize: theme.fontSize.sm }
1052
1111
  ]
1053
1112
  },
1054
- renderLogo()
1055
- ));
1056
- };
1057
- var styles4 = import_react_native4.StyleSheet.create({
1058
- container: {
1059
- flexDirection: "row",
1060
- alignItems: "center",
1061
- justifyContent: "center",
1062
- marginVertical: 24,
1063
- // theme.spacing.xxl
1064
- gap: 12
1065
- // theme.spacing.md
1066
- },
1067
- logoContainer: {
1068
- width: 56,
1069
- height: 56,
1070
- borderRadius: 12,
1071
- // theme.borderRadius.md
1072
- alignItems: "center",
1073
- justifyContent: "center",
1074
- overflow: "hidden"
1075
- },
1076
- iconContainer: {
1077
- paddingHorizontal: 8
1078
- // theme.spacing.sm
1079
- },
1080
- appLogoImage: {
1081
- width: 32,
1082
- height: 32
1083
- },
1084
- appLogoText: {
1085
- fontSize: 24,
1086
- // theme.fontSize.xxxl
1087
- fontWeight: "700"
1088
- }
1089
- });
1090
-
1091
- // src/molecules/Auth.tsx
1092
- var Auth = ({
1093
- open,
1094
- onEmailSuccess,
1095
- onGuestSuccess,
1096
- onClose
1097
- }) => {
1098
- const { appName, linkToken, clientId, setUser, setEmail } = useKryptosConnect();
1099
- const theme = useTheme();
1100
- const [isLoading, setIsLoading] = import_react12.default.useState(false);
1101
- const [errorMessage, setErrorMessage] = import_react12.default.useState("");
1102
- const [emailValue, setEmailValue] = import_react12.default.useState("");
1103
- const [emailError, setEmailError] = import_react12.default.useState("");
1104
- const [loadingType, setLoadingType] = import_react12.default.useState(null);
1105
- const validateEmail = (email) => {
1106
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1107
- if (!email) {
1108
- setEmailError("Email is required");
1109
- return false;
1110
- }
1111
- if (!emailRegex.test(email)) {
1112
- setEmailError("Invalid email address");
1113
- return false;
1114
- }
1115
- setEmailError("");
1116
- return true;
1117
- };
1118
- const handleClose = () => {
1119
- onClose();
1120
- setEmailValue("");
1121
- setEmailError("");
1122
- setErrorMessage("");
1123
- };
1124
- const handleEmailSubmit = async () => {
1125
- if (!validateEmail(emailValue)) return;
1126
- try {
1127
- setIsLoading(true);
1128
- setLoadingType("email");
1129
- setErrorMessage("");
1130
- await sendEmailOtp(linkToken, emailValue, clientId);
1131
- setEmail(emailValue);
1132
- setEmailError("");
1133
- onEmailSuccess();
1134
- } catch (error) {
1135
- const err = error;
1136
- setErrorMessage(
1137
- err?.response?.data?.message || "Failed to send email OTP"
1138
- );
1139
- } finally {
1140
- setIsLoading(false);
1141
- setLoadingType(null);
1142
- }
1143
- };
1144
- const handleContinueAsGuest = async () => {
1145
- try {
1146
- setIsLoading(true);
1147
- setLoadingType("guest");
1148
- setErrorMessage("");
1149
- const res = await createAnonymousUser(linkToken, clientId);
1150
- setUser(res);
1151
- setEmailError("");
1152
- onGuestSuccess();
1153
- } catch (error) {
1154
- const err = error;
1155
- console.error(error);
1156
- setErrorMessage(
1157
- err?.response?.data?.message || "Failed to continue as guest"
1158
- );
1159
- } finally {
1160
- setIsLoading(false);
1161
- setLoadingType(null);
1162
- }
1163
- };
1164
- const infoSections = [
1165
- {
1166
- icon: /* @__PURE__ */ import_react12.default.createElement(LinkIcon, { size: 20, color: theme.colors.primary }),
1167
- title: "Simple and secure",
1168
- text: "Connect your Web3 accounts with Kryptos in just a few clicks"
1169
- },
1113
+ label
1114
+ ), /* @__PURE__ */ import_react9.default.createElement(import_react_native5.View, { style: styles5.container }, Array.from({ length }, (_, index) => /* @__PURE__ */ import_react9.default.createElement(
1115
+ import_react_native5.TextInput,
1170
1116
  {
1171
- icon: /* @__PURE__ */ import_react12.default.createElement(ShieldIcon, { size: 20, color: theme.colors.primary }),
1172
- title: "Control what you share",
1173
- text: "We never share your data without your permission"
1117
+ key: index,
1118
+ ref: (el) => inputRefs.current[index] = el,
1119
+ style: [
1120
+ styles5.input,
1121
+ {
1122
+ backgroundColor: theme.colors.surface,
1123
+ borderColor: getBorderColor(index),
1124
+ color: theme.colors.text,
1125
+ fontSize: theme.fontSize.xxl,
1126
+ borderRadius: theme.borderRadius.md
1127
+ },
1128
+ inputStyle
1129
+ ],
1130
+ keyboardType: "numeric",
1131
+ maxLength: 1,
1132
+ value: otp[index] || "",
1133
+ onChangeText: (val) => handleChange(index, val),
1134
+ onKeyPress: (e) => handleKeyPress(index, e),
1135
+ editable: !disabled,
1136
+ selectTextOnFocus: true,
1137
+ caretHidden: true
1174
1138
  }
1175
- ];
1176
- return /* @__PURE__ */ import_react12.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react12.default.createElement(ModalHeader, { onClose: handleClose }, ""), /* @__PURE__ */ import_react12.default.createElement(ModalBody, null, /* @__PURE__ */ import_react12.default.createElement(import_react_native5.View, { style: styles5.container }, /* @__PURE__ */ import_react12.default.createElement(import_react_native5.Text, { style: [styles5.title, { color: theme.colors.text }] }, "Connect ", appName, " to your Kryptos account"), /* @__PURE__ */ import_react12.default.createElement(ConnectLogo, null), infoSections.map((section, index) => /* @__PURE__ */ import_react12.default.createElement(import_react_native5.View, { key: `info-${index}`, style: styles5.infoSection }, /* @__PURE__ */ import_react12.default.createElement(import_react_native5.View, { style: styles5.infoIcon }, section.icon), /* @__PURE__ */ import_react12.default.createElement(import_react_native5.View, { style: styles5.infoContent }, /* @__PURE__ */ import_react12.default.createElement(import_react_native5.Text, { style: [styles5.infoTitle, { color: theme.colors.text }] }, section.title), /* @__PURE__ */ import_react12.default.createElement(
1139
+ ))), error && /* @__PURE__ */ import_react9.default.createElement(
1177
1140
  import_react_native5.Text,
1178
1141
  {
1179
1142
  style: [
1180
- styles5.infoDescription,
1181
- { color: theme.colors.textSecondary }
1143
+ styles5.error,
1144
+ { color: theme.colors.error, fontSize: theme.fontSize.sm }
1182
1145
  ]
1183
1146
  },
1184
- section.text
1185
- )))), errorMessage ? /* @__PURE__ */ import_react12.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react12.default.createElement(AlertDescription, null, errorMessage)) : null, /* @__PURE__ */ import_react12.default.createElement(import_react_native5.Text, { style: [styles5.footer, { color: theme.colors.textSecondary }] }, "By continuing, you agree to Kryptos", " ", /* @__PURE__ */ import_react12.default.createElement(
1186
- import_react_native5.Text,
1187
- {
1188
- style: {
1189
- color: theme.colors.primary,
1190
- textDecorationLine: "underline"
1191
- }
1192
- },
1193
- "Privacy Policy"
1194
- )), /* @__PURE__ */ import_react12.default.createElement(
1195
- Button,
1196
- {
1197
- variant: "outline",
1198
- size: "lg",
1199
- onPress: handleContinueAsGuest,
1200
- loading: loadingType === "guest",
1201
- disabled: isLoading,
1202
- style: styles5.button
1203
- },
1204
- "Continue as guest"
1205
- ))));
1147
+ error
1148
+ ));
1206
1149
  };
1207
1150
  var styles5 = import_react_native5.StyleSheet.create({
1151
+ wrapper: {
1152
+ marginBottom: 16
1153
+ // theme.spacing.lg
1154
+ },
1155
+ label: {
1156
+ fontWeight: "500",
1157
+ marginBottom: 12,
1158
+ // theme.spacing.md - consistent label spacing
1159
+ textAlign: "center"
1160
+ },
1208
1161
  container: {
1209
- flex: 1
1162
+ flexDirection: "row",
1163
+ justifyContent: "center",
1164
+ gap: 8
1165
+ // theme.spacing.sm
1210
1166
  },
1211
- title: {
1212
- fontSize: 18,
1213
- // theme.fontSize.xl
1214
- fontWeight: "600",
1167
+ input: {
1168
+ width: 48,
1169
+ height: 56,
1170
+ borderWidth: 1,
1215
1171
  textAlign: "center",
1216
- marginBottom: 16
1217
- // theme.spacing.lg - consistent section spacing
1172
+ fontWeight: "600"
1218
1173
  },
1219
- infoSection: {
1174
+ error: {
1175
+ marginTop: 12,
1176
+ // theme.spacing.md - consistent error spacing
1177
+ textAlign: "center"
1178
+ }
1179
+ });
1180
+
1181
+ // src/components/SkeletonItem.tsx
1182
+ var import_react10 = __toESM(require("react"));
1183
+ var import_react_native6 = require("react-native");
1184
+ var SkeletonItem = () => {
1185
+ const opacity = (0, import_react10.useRef)(new import_react_native6.Animated.Value(0.3)).current;
1186
+ (0, import_react10.useEffect)(() => {
1187
+ import_react_native6.Animated.loop(
1188
+ import_react_native6.Animated.sequence([
1189
+ import_react_native6.Animated.timing(opacity, {
1190
+ toValue: 1,
1191
+ duration: 600,
1192
+ useNativeDriver: true
1193
+ }),
1194
+ import_react_native6.Animated.timing(opacity, {
1195
+ toValue: 0.3,
1196
+ duration: 600,
1197
+ useNativeDriver: true
1198
+ })
1199
+ ])
1200
+ ).start();
1201
+ }, []);
1202
+ return /* @__PURE__ */ import_react10.default.createElement(import_react_native6.Animated.View, { style: [styles6.row, { opacity }] }, /* @__PURE__ */ import_react10.default.createElement(import_react_native6.View, { style: styles6.iconCircle }), /* @__PURE__ */ import_react10.default.createElement(import_react_native6.View, { style: styles6.textBlock }, /* @__PURE__ */ import_react10.default.createElement(import_react_native6.View, { style: styles6.lineLong }), /* @__PURE__ */ import_react10.default.createElement(import_react_native6.View, { style: styles6.lineShort })));
1203
+ };
1204
+ var styles6 = import_react_native6.StyleSheet.create({
1205
+ row: {
1220
1206
  flexDirection: "row",
1221
- marginBottom: 16,
1222
- // theme.spacing.lg
1223
- alignItems: "flex-start"
1224
- },
1225
- infoIcon: {
1226
- width: 32,
1227
- height: 32,
1228
- borderRadius: 16,
1229
- // theme.borderRadius.lg
1230
1207
  alignItems: "center",
1231
- justifyContent: "center",
1232
- marginRight: 12
1233
- // theme.spacing.md
1208
+ paddingVertical: 16
1234
1209
  },
1235
- infoContent: {
1236
- flex: 1
1210
+ iconCircle: {
1211
+ width: 45,
1212
+ height: 45,
1213
+ borderRadius: 22.5,
1214
+ backgroundColor: "#E5E5E5"
1237
1215
  },
1238
- infoTitle: {
1239
- fontSize: 14,
1240
- // theme.fontSize.md
1241
- fontWeight: "600",
1242
- marginBottom: 4
1243
- // theme.spacing.xs
1216
+ textBlock: {
1217
+ marginLeft: 12,
1218
+ flex: 1
1244
1219
  },
1245
- infoDescription: {
1246
- fontSize: 13,
1247
- lineHeight: 18
1220
+ lineShort: {
1221
+ width: "50%",
1222
+ height: 14,
1223
+ borderRadius: 6,
1224
+ backgroundColor: "#E5E5E5"
1248
1225
  },
1249
- button: {
1226
+ lineLong: {
1227
+ marginBottom: 6,
1250
1228
  width: "100%",
1251
- marginTop: 16
1252
- // theme.spacing.lg - consistent button spacing
1229
+ height: 14,
1230
+ borderRadius: 6,
1231
+ backgroundColor: "#E5E5E5"
1232
+ }
1233
+ });
1234
+ var SkeletonItem_default = SkeletonItem;
1235
+
1236
+ // src/components/Mode.tsx
1237
+ var import_react11 = __toESM(require("react"));
1238
+ var import_react_native7 = require("react-native");
1239
+ var Mode = () => {
1240
+ const { clientInfo } = useKryptosConnect();
1241
+ const theme = useTheme();
1242
+ if (!clientInfo) return null;
1243
+ if (clientInfo?.project_stage === "production") return null;
1244
+ return /* @__PURE__ */ import_react11.default.createElement(import_react_native7.View, { style: [styles7.container, { backgroundColor: theme.colors.warning }] }, /* @__PURE__ */ import_react11.default.createElement(import_react_native7.Text, { style: [styles7.text, { color: theme.colors.warningText }] }, "Sandbox Mode"));
1245
+ };
1246
+ var styles7 = import_react_native7.StyleSheet.create({
1247
+ container: {
1248
+ paddingVertical: 4,
1249
+ paddingHorizontal: 8,
1250
+ borderRadius: 8,
1251
+ alignItems: "center",
1252
+ justifyContent: "center"
1253
1253
  },
1254
- footer: {
1254
+ text: {
1255
1255
  fontSize: 12,
1256
- // theme.fontSize.sm
1257
- textAlign: "center",
1258
- marginTop: 16
1259
- // theme.spacing.lg
1256
+ fontWeight: "600"
1260
1257
  }
1261
1258
  });
1262
1259
 
1263
- // src/components/Input.tsx
1260
+ // src/components/Footer.tsx
1264
1261
  var import_react13 = __toESM(require("react"));
1265
- var import_react_native6 = require("react-native");
1266
- var Input = ({
1267
- label,
1268
- error,
1269
- helperText,
1270
- status = "default",
1271
- containerStyle,
1272
- inputStyle,
1273
- labelStyle,
1274
- ...props
1275
- }) => {
1262
+ var import_react_native9 = require("react-native");
1263
+
1264
+ // src/components/PoweredByKryptos.tsx
1265
+ var import_react12 = __toESM(require("react"));
1266
+ var import_react_native8 = require("react-native");
1267
+ var PoweredByKryptos = () => {
1276
1268
  const theme = useTheme();
1277
- const inputStatus = error ? "error" : status;
1278
- const getBorderColor = () => {
1279
- switch (inputStatus) {
1280
- case "error":
1281
- return theme.colors.error;
1282
- case "success":
1283
- return theme.colors.success;
1284
- default:
1285
- return theme.colors.border;
1269
+ const handlePress = () => {
1270
+ import_react_native8.Linking.openURL("https://kryptos.io");
1271
+ };
1272
+ return /* @__PURE__ */ import_react12.default.createElement(import_react_native8.View, { style: styles8.container }, /* @__PURE__ */ import_react12.default.createElement(import_react_native8.Text, { style: [styles8.text, { color: theme.colors.textSecondary }] }, "Powered by", " "), /* @__PURE__ */ import_react12.default.createElement(import_react_native8.TouchableOpacity, { onPress: handlePress, activeOpacity: 0.7 }, /* @__PURE__ */ import_react12.default.createElement(LogoIcon, { size: 16 })));
1273
+ };
1274
+ var styles8 = import_react_native8.StyleSheet.create({
1275
+ container: {
1276
+ flexDirection: "row",
1277
+ alignItems: "center"
1278
+ },
1279
+ text: {
1280
+ fontSize: 12,
1281
+ fontWeight: "400"
1282
+ }
1283
+ });
1284
+
1285
+ // src/components/Footer.tsx
1286
+ var Footer = () => {
1287
+ const { clientInfo } = useKryptosConnect();
1288
+ const isSandbox = clientInfo?.project_stage === "sandbox";
1289
+ return /* @__PURE__ */ import_react13.default.createElement(
1290
+ import_react_native9.View,
1291
+ {
1292
+ style: [
1293
+ styles9.container,
1294
+ { justifyContent: isSandbox ? "space-between" : "center" }
1295
+ ]
1296
+ },
1297
+ /* @__PURE__ */ import_react13.default.createElement(PoweredByKryptos, null),
1298
+ /* @__PURE__ */ import_react13.default.createElement(Mode, null)
1299
+ );
1300
+ };
1301
+ var styles9 = import_react_native9.StyleSheet.create({
1302
+ container: {
1303
+ width: "100%",
1304
+ paddingVertical: 8,
1305
+ alignItems: "center",
1306
+ flexDirection: "row"
1307
+ }
1308
+ });
1309
+
1310
+ // src/molecules/Auth.tsx
1311
+ var import_react19 = __toESM(require("react"));
1312
+ var import_react_native11 = require("react-native");
1313
+
1314
+ // src/assets/LinkIcon.tsx
1315
+ var import_react14 = __toESM(require("react"));
1316
+ var import_react_native_svg3 = __toESM(require("react-native-svg"));
1317
+ var LinkIcon = ({
1318
+ size = 20,
1319
+ color = "#00C693"
1320
+ }) => {
1321
+ return /* @__PURE__ */ import_react14.default.createElement(import_react_native_svg3.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react14.default.createElement(
1322
+ import_react_native_svg3.Path,
1323
+ {
1324
+ d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",
1325
+ stroke: color,
1326
+ strokeWidth: 2,
1327
+ strokeLinecap: "round",
1328
+ strokeLinejoin: "round"
1329
+ }
1330
+ ), /* @__PURE__ */ import_react14.default.createElement(
1331
+ import_react_native_svg3.Path,
1332
+ {
1333
+ d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71",
1334
+ stroke: color,
1335
+ strokeWidth: 2,
1336
+ strokeLinecap: "round",
1337
+ strokeLinejoin: "round"
1338
+ }
1339
+ ));
1340
+ };
1341
+
1342
+ // src/assets/ShieldIcon.tsx
1343
+ var import_react15 = __toESM(require("react"));
1344
+ var import_react_native_svg4 = __toESM(require("react-native-svg"));
1345
+ var ShieldIcon = ({
1346
+ size = 20,
1347
+ color = "#00C693"
1348
+ }) => {
1349
+ return /* @__PURE__ */ import_react15.default.createElement(import_react_native_svg4.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react15.default.createElement(
1350
+ import_react_native_svg4.Path,
1351
+ {
1352
+ d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",
1353
+ stroke: color,
1354
+ strokeWidth: 2,
1355
+ strokeLinecap: "round",
1356
+ strokeLinejoin: "round"
1357
+ }
1358
+ ), /* @__PURE__ */ import_react15.default.createElement(
1359
+ import_react_native_svg4.Path,
1360
+ {
1361
+ d: "m9 12 2 2 4-4",
1362
+ stroke: color,
1363
+ strokeWidth: 2,
1364
+ strokeLinecap: "round",
1365
+ strokeLinejoin: "round"
1366
+ }
1367
+ ));
1368
+ };
1369
+
1370
+ // src/assets/eye.tsx
1371
+ var import_react16 = __toESM(require("react"));
1372
+ var import_react_native_svg5 = __toESM(require("react-native-svg"));
1373
+ var EyeIcon = ({
1374
+ size = 20,
1375
+ color = "#00C693"
1376
+ }) => {
1377
+ return /* @__PURE__ */ import_react16.default.createElement(import_react_native_svg5.default, { fill: color, width: size, height: size, viewBox: "0 0 0.72 0.72" }, /* @__PURE__ */ import_react16.default.createElement(import_react_native_svg5.Path, { d: "M0.658 0.348C0.597 0.207 0.483 0.12 0.36 0.12s-0.237 0.087 -0.298 0.228a0.03 0.03 0 0 0 0 0.024C0.123 0.513 0.237 0.6 0.36 0.6s0.237 -0.087 0.298 -0.228a0.03 0.03 0 0 0 0 -0.024M0.36 0.54c-0.095 0 -0.185 -0.069 -0.237 -0.18C0.175 0.249 0.265 0.18 0.36 0.18s0.185 0.069 0.237 0.18c-0.052 0.111 -0.142 0.18 -0.237 0.18m0 -0.3a0.12 0.12 0 1 0 0.12 0.12 0.12 0.12 0 0 0 -0.12 -0.12m0 0.18a0.06 0.06 0 1 1 0.06 -0.06 0.06 0.06 0 0 1 -0.06 0.06" }));
1378
+ };
1379
+
1380
+ // src/molecules/ConnectLogo.tsx
1381
+ var import_react18 = __toESM(require("react"));
1382
+ var import_react_native10 = require("react-native");
1383
+
1384
+ // src/assets/UnplugIcon.tsx
1385
+ var import_react17 = __toESM(require("react"));
1386
+ var import_react_native_svg6 = __toESM(require("react-native-svg"));
1387
+ var UnplugIcon = ({
1388
+ size = 24,
1389
+ color = "#6B7280"
1390
+ }) => {
1391
+ return /* @__PURE__ */ import_react17.default.createElement(import_react_native_svg6.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react17.default.createElement(
1392
+ import_react_native_svg6.Path,
1393
+ {
1394
+ d: "m19 5 3-3",
1395
+ stroke: color,
1396
+ strokeWidth: 2,
1397
+ strokeLinecap: "round",
1398
+ strokeLinejoin: "round"
1286
1399
  }
1287
- };
1288
- return /* @__PURE__ */ import_react13.default.createElement(import_react_native6.View, { style: [styles6.wrapper, containerStyle] }, label && /* @__PURE__ */ import_react13.default.createElement(
1289
- import_react_native6.Text,
1400
+ ), /* @__PURE__ */ import_react17.default.createElement(
1401
+ import_react_native_svg6.Path,
1290
1402
  {
1291
- style: [
1292
- styles6.label,
1293
- { color: theme.colors.text, fontSize: theme.fontSize.sm },
1294
- labelStyle
1295
- ]
1296
- },
1297
- label
1298
- ), /* @__PURE__ */ import_react13.default.createElement(
1299
- import_react_native6.TextInput,
1403
+ d: "m2 22 3-3",
1404
+ stroke: color,
1405
+ strokeWidth: 2,
1406
+ strokeLinecap: "round",
1407
+ strokeLinejoin: "round"
1408
+ }
1409
+ ), /* @__PURE__ */ import_react17.default.createElement(
1410
+ import_react_native_svg6.Path,
1300
1411
  {
1301
- placeholderTextColor: theme.colors.textTertiary,
1302
- style: [
1303
- styles6.input,
1304
- {
1305
- backgroundColor: theme.colors.surface,
1306
- borderColor: getBorderColor(),
1307
- color: theme.colors.text,
1308
- fontSize: theme.fontSize.md,
1309
- borderRadius: theme.borderRadius.md,
1310
- paddingHorizontal: theme.spacing.lg,
1311
- paddingVertical: theme.spacing.md
1312
- },
1313
- inputStyle
1314
- ],
1315
- ...props
1412
+ d: "M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z",
1413
+ stroke: color,
1414
+ strokeWidth: 2,
1415
+ strokeLinecap: "round",
1416
+ strokeLinejoin: "round"
1316
1417
  }
1317
- ), error && /* @__PURE__ */ import_react13.default.createElement(
1318
- import_react_native6.Text,
1418
+ ), /* @__PURE__ */ import_react17.default.createElement(
1419
+ import_react_native_svg6.Path,
1319
1420
  {
1320
- style: [
1321
- styles6.error,
1322
- { color: theme.colors.error, fontSize: theme.fontSize.sm }
1323
- ]
1324
- },
1325
- error
1326
- ), helperText && !error && /* @__PURE__ */ import_react13.default.createElement(
1327
- import_react_native6.Text,
1421
+ d: "m18 12-6-6 2.3-2.3a2.4 2.4 0 0 1 3.4 0l2.6 2.6a2.4 2.4 0 0 1 0 3.4Z",
1422
+ stroke: color,
1423
+ strokeWidth: 2,
1424
+ strokeLinecap: "round",
1425
+ strokeLinejoin: "round"
1426
+ }
1427
+ ), /* @__PURE__ */ import_react17.default.createElement(
1428
+ import_react_native_svg6.Line,
1328
1429
  {
1329
- style: [
1330
- styles6.helper,
1430
+ x1: 7.5,
1431
+ y1: 13.5,
1432
+ x2: 10.5,
1433
+ y2: 10.5,
1434
+ stroke: color,
1435
+ strokeWidth: 2,
1436
+ strokeLinecap: "round"
1437
+ }
1438
+ ));
1439
+ };
1440
+
1441
+ // src/molecules/ConnectLogo.tsx
1442
+ var KryptosLogo = () => {
1443
+ const theme = useTheme();
1444
+ return /* @__PURE__ */ import_react18.default.createElement(
1445
+ import_react_native10.View,
1446
+ {
1447
+ style: [styles10.logoContainer, { backgroundColor: theme.colors.surface }]
1448
+ },
1449
+ /* @__PURE__ */ import_react18.default.createElement(LogoIcon, { size: 36 })
1450
+ );
1451
+ };
1452
+ var ConnectLogo = () => {
1453
+ const { appName, appLogo } = useKryptosConnect();
1454
+ const theme = useTheme();
1455
+ const isValidUrl = (str) => {
1456
+ try {
1457
+ new URL(str);
1458
+ return true;
1459
+ } catch {
1460
+ return false;
1461
+ }
1462
+ };
1463
+ const renderLogo = () => {
1464
+ if ((0, import_react18.isValidElement)(appLogo)) {
1465
+ return appLogo;
1466
+ } else if (typeof appLogo === "string" && isValidUrl(appLogo)) {
1467
+ return /* @__PURE__ */ import_react18.default.createElement(
1468
+ import_react_native10.Image,
1331
1469
  {
1332
- color: theme.colors.textSecondary,
1333
- fontSize: theme.fontSize.sm
1470
+ source: { uri: appLogo },
1471
+ style: styles10.appLogoImage,
1472
+ resizeMode: "contain"
1473
+ }
1474
+ );
1475
+ } else if (typeof appLogo === "number" || typeof appLogo === "object" && appLogo !== null) {
1476
+ return /* @__PURE__ */ import_react18.default.createElement(
1477
+ import_react_native10.Image,
1478
+ {
1479
+ source: appLogo,
1480
+ style: styles10.appLogoImage,
1481
+ resizeMode: "contain"
1334
1482
  }
1483
+ );
1484
+ } else if (appName) {
1485
+ return /* @__PURE__ */ import_react18.default.createElement(import_react_native10.Text, { style: [styles10.appLogoText, { color: theme.colors.text }] }, appName.charAt(0).toUpperCase());
1486
+ }
1487
+ return /* @__PURE__ */ import_react18.default.createElement(import_react_native10.Text, { style: [styles10.appLogoText, { color: theme.colors.text }] }, "?");
1488
+ };
1489
+ return /* @__PURE__ */ import_react18.default.createElement(import_react_native10.View, { style: styles10.container }, /* @__PURE__ */ import_react18.default.createElement(KryptosLogo, null), /* @__PURE__ */ import_react18.default.createElement(import_react_native10.View, { style: styles10.iconContainer }, /* @__PURE__ */ import_react18.default.createElement(UnplugIcon, { size: 24, color: theme.colors.textSecondary })), /* @__PURE__ */ import_react18.default.createElement(
1490
+ import_react_native10.View,
1491
+ {
1492
+ style: [
1493
+ styles10.logoContainer,
1494
+ { backgroundColor: theme.colors.surface }
1335
1495
  ]
1336
1496
  },
1337
- helperText
1497
+ renderLogo()
1338
1498
  ));
1339
1499
  };
1340
- var styles6 = import_react_native6.StyleSheet.create({
1341
- wrapper: {
1342
- marginBottom: 16
1343
- // theme.spacing.lg - consistent form spacing
1500
+ var styles10 = import_react_native10.StyleSheet.create({
1501
+ container: {
1502
+ flexDirection: "row",
1503
+ alignItems: "center",
1504
+ justifyContent: "center",
1505
+ gap: 12
1506
+ // theme.spacing.md
1344
1507
  },
1345
- label: {
1346
- fontWeight: "500",
1347
- marginBottom: 8
1348
- // theme.spacing.sm
1508
+ logoContainer: {
1509
+ width: 56,
1510
+ height: 56,
1511
+ borderRadius: 12,
1512
+ // theme.borderRadius.md
1513
+ alignItems: "center",
1514
+ justifyContent: "center",
1515
+ overflow: "hidden"
1349
1516
  },
1350
- input: {
1351
- borderWidth: 1,
1352
- minHeight: 48
1517
+ iconContainer: {
1518
+ paddingHorizontal: 8
1519
+ // theme.spacing.sm
1353
1520
  },
1354
- error: {
1355
- marginTop: 4
1356
- // theme.spacing.xs
1521
+ appLogoImage: {
1522
+ width: 32,
1523
+ height: 32
1357
1524
  },
1358
- helper: {
1359
- marginTop: 4
1360
- // theme.spacing.xs
1525
+ appLogoText: {
1526
+ fontSize: 24,
1527
+ // theme.fontSize.xxxl
1528
+ fontWeight: "700"
1361
1529
  }
1362
1530
  });
1363
1531
 
1364
- // src/components/OTP.tsx
1365
- var import_react14 = __toESM(require("react"));
1366
- var import_react_native7 = require("react-native");
1367
- var OTP = ({
1368
- length = 6,
1369
- value = "",
1370
- onChange,
1371
- onComplete,
1372
- error,
1373
- label,
1374
- disabled = false,
1375
- containerStyle,
1376
- inputStyle,
1377
- setErrorMessage
1532
+ // src/molecules/Auth.tsx
1533
+ var Auth = ({
1534
+ open,
1535
+ onEmailSuccess,
1536
+ onGuestSuccess,
1537
+ onClose
1378
1538
  }) => {
1539
+ const { appName, linkToken, clientId, setUser, setEmail } = useKryptosConnect();
1379
1540
  const theme = useTheme();
1380
- const AUTO_SUBMIT_DELAY = 500;
1381
- const [otp, setOtp] = import_react14.default.useState(
1382
- value.split("").concat(Array(length).fill("")).slice(0, length)
1383
- );
1384
- const inputRefs = import_react14.default.useRef([]);
1385
- import_react14.default.useEffect(() => {
1386
- const isComplete = otp.every((digit) => digit !== "");
1387
- let timer;
1388
- if (isComplete && onComplete) {
1389
- timer = setTimeout(() => {
1390
- onComplete(otp.join(""));
1391
- }, AUTO_SUBMIT_DELAY);
1541
+ const [isLoading, setIsLoading] = import_react19.default.useState(false);
1542
+ const [errorMessage, setErrorMessage] = import_react19.default.useState("");
1543
+ const [emailValue, setEmailValue] = import_react19.default.useState("");
1544
+ const [emailError, setEmailError] = import_react19.default.useState("");
1545
+ const [loadingType, setLoadingType] = import_react19.default.useState(null);
1546
+ const validateEmail = (email) => {
1547
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1548
+ if (!email) {
1549
+ setEmailError("Email is required");
1550
+ return false;
1551
+ }
1552
+ if (!emailRegex.test(email)) {
1553
+ setEmailError("Invalid email address");
1554
+ return false;
1555
+ }
1556
+ setEmailError("");
1557
+ return true;
1558
+ };
1559
+ const handleClose = () => {
1560
+ onClose();
1561
+ setEmailValue("");
1562
+ setEmailError("");
1563
+ setErrorMessage("");
1564
+ };
1565
+ const handleEmailSubmit = async () => {
1566
+ if (!validateEmail(emailValue)) return;
1567
+ try {
1568
+ setIsLoading(true);
1569
+ setLoadingType("email");
1570
+ setErrorMessage("");
1571
+ await sendEmailOtp(linkToken, emailValue, clientId);
1572
+ setEmail(emailValue);
1573
+ setEmailError("");
1574
+ onEmailSuccess();
1575
+ } catch (error) {
1576
+ const err = error;
1577
+ setErrorMessage(
1578
+ err?.response?.data?.message || "Failed to send email OTP"
1579
+ );
1580
+ } finally {
1581
+ setIsLoading(false);
1582
+ setLoadingType(null);
1583
+ }
1584
+ };
1585
+ const handleContinueAsGuest = async () => {
1586
+ try {
1587
+ setIsLoading(true);
1588
+ setLoadingType("guest");
1589
+ setErrorMessage("");
1590
+ const res = await createAnonymousUser(linkToken, clientId);
1591
+ setUser(res);
1592
+ setEmailError("");
1593
+ onGuestSuccess();
1594
+ } catch (error) {
1595
+ const err = error;
1596
+ console.error(error);
1597
+ setErrorMessage(
1598
+ err?.response?.data?.message || "Failed to continue as guest"
1599
+ );
1600
+ } finally {
1601
+ setIsLoading(false);
1602
+ setLoadingType(null);
1392
1603
  }
1393
- return () => {
1394
- if (timer) clearTimeout(timer);
1395
- };
1396
- }, [otp, onComplete]);
1397
- import_react14.default.useEffect(() => {
1398
- setTimeout(() => {
1399
- inputRefs.current[0]?.focus();
1400
- }, 100);
1401
- }, []);
1402
- const handleChange = import_react14.default.useCallback(
1403
- (index, val) => {
1404
- if (disabled) return;
1405
- setErrorMessage("");
1406
- const numericValue = val.replace(/[^0-9]/g, "");
1407
- const newValue = numericValue.slice(-1);
1408
- if (val && !numericValue) {
1409
- return;
1410
- }
1411
- const newOtp = [...otp];
1412
- newOtp[index] = newValue;
1413
- setOtp(newOtp);
1414
- const otpString = newOtp.join("");
1415
- onChange?.(otpString);
1416
- if (newValue && index < length - 1) {
1417
- inputRefs.current[index + 1]?.focus();
1418
- }
1419
- if (otpString.length === length && !otpString.includes("")) {
1420
- onComplete?.(otpString);
1421
- }
1422
- },
1423
- [otp, length, onChange, onComplete, disabled]
1424
- );
1425
- const handleKeyPress = import_react14.default.useCallback(
1426
- (index, e) => {
1427
- if (disabled) return;
1428
- if (e.nativeEvent.key === "Backspace") {
1429
- if (!otp[index] && index > 0) {
1430
- inputRefs.current[index - 1]?.focus();
1431
- } else {
1432
- const newOtp = [...otp];
1433
- newOtp[index] = "";
1434
- setOtp(newOtp);
1435
- onChange?.(newOtp.join(""));
1436
- }
1437
- }
1438
- },
1439
- [otp, onChange, disabled]
1440
- );
1441
- const getBorderColor = (index) => {
1442
- if (error) return theme.colors.error;
1443
- if (otp[index]) return theme.colors.success;
1444
- return theme.colors.border;
1445
1604
  };
1446
- return /* @__PURE__ */ import_react14.default.createElement(import_react_native7.View, { style: [styles7.wrapper, containerStyle] }, label && /* @__PURE__ */ import_react14.default.createElement(
1447
- import_react_native7.Text,
1605
+ const infoSections = [
1448
1606
  {
1449
- style: [
1450
- styles7.label,
1451
- { color: theme.colors.text, fontSize: theme.fontSize.sm }
1452
- ]
1607
+ icon: /* @__PURE__ */ import_react19.default.createElement(LinkIcon, { size: 20, color: theme.colors.primary }),
1608
+ title: "Simple and secure",
1609
+ text: "Link your accounts in just a few clicks"
1453
1610
  },
1454
- label
1455
- ), /* @__PURE__ */ import_react14.default.createElement(import_react_native7.View, { style: styles7.container }, Array.from({ length }, (_, index) => /* @__PURE__ */ import_react14.default.createElement(
1456
- import_react_native7.TextInput,
1457
1611
  {
1458
- key: index,
1459
- ref: (el) => inputRefs.current[index] = el,
1460
- style: [
1461
- styles7.input,
1462
- {
1463
- backgroundColor: theme.colors.surface,
1464
- borderColor: getBorderColor(index),
1465
- color: theme.colors.text,
1466
- fontSize: theme.fontSize.xxl,
1467
- borderRadius: theme.borderRadius.md
1468
- },
1469
- inputStyle
1470
- ],
1471
- keyboardType: "numeric",
1472
- maxLength: 1,
1473
- value: otp[index] || "",
1474
- onChangeText: (val) => handleChange(index, val),
1475
- onKeyPress: (e) => handleKeyPress(index, e),
1476
- editable: !disabled,
1477
- selectTextOnFocus: true,
1478
- caretHidden: true
1612
+ icon: /* @__PURE__ */ import_react19.default.createElement(ShieldIcon, { size: 20, color: theme.colors.primary }),
1613
+ title: "Control what you share",
1614
+ text: "We never share your data without your permission"
1615
+ },
1616
+ {
1617
+ icon: /* @__PURE__ */ import_react19.default.createElement(EyeIcon, { size: 20, color: theme.colors.primary }),
1618
+ title: "View Only Access",
1619
+ text: "Kryptos retrieves view-only data and cannot perform any transactions on your behalf."
1479
1620
  }
1480
- ))), error && /* @__PURE__ */ import_react14.default.createElement(
1481
- import_react_native7.Text,
1621
+ ];
1622
+ return /* @__PURE__ */ import_react19.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react19.default.createElement(ModalHeader, { onClose: handleClose }, ""), /* @__PURE__ */ import_react19.default.createElement(ModalBody, null, /* @__PURE__ */ import_react19.default.createElement(import_react_native11.View, { style: styles11.container }, /* @__PURE__ */ import_react19.default.createElement(import_react_native11.View, { style: styles11.header }, /* @__PURE__ */ import_react19.default.createElement(import_react_native11.Text, { style: [styles11.title, { color: theme.colors.text }] }, "Link your accounts to", " ", /* @__PURE__ */ import_react19.default.createElement(import_react_native11.Text, { style: { fontWeight: "700" } }, appName), " using Kryptos"), /* @__PURE__ */ import_react19.default.createElement(ConnectLogo, null), infoSections.map((section, index) => /* @__PURE__ */ import_react19.default.createElement(import_react_native11.View, { key: `info-${index}`, style: styles11.infoSection }, /* @__PURE__ */ import_react19.default.createElement(import_react_native11.View, { style: styles11.infoIcon }, section.icon), /* @__PURE__ */ import_react19.default.createElement(import_react_native11.View, { style: styles11.infoContent }, /* @__PURE__ */ import_react19.default.createElement(
1623
+ import_react_native11.Text,
1624
+ {
1625
+ style: [styles11.infoTitle, { color: theme.colors.text }]
1626
+ },
1627
+ section.title
1628
+ ), /* @__PURE__ */ import_react19.default.createElement(
1629
+ import_react_native11.Text,
1482
1630
  {
1483
1631
  style: [
1484
- styles7.error,
1485
- { color: theme.colors.error, fontSize: theme.fontSize.sm }
1632
+ styles11.infoDescription,
1633
+ { color: theme.colors.textSecondary }
1486
1634
  ]
1487
1635
  },
1488
- error
1489
- ));
1636
+ section.text
1637
+ )))), errorMessage ? /* @__PURE__ */ import_react19.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react19.default.createElement(AlertDescription, null, errorMessage)) : null), /* @__PURE__ */ import_react19.default.createElement(import_react_native11.View, { style: styles11.footer }, /* @__PURE__ */ import_react19.default.createElement(
1638
+ Button,
1639
+ {
1640
+ variant: "outline",
1641
+ size: "lg",
1642
+ onPress: handleContinueAsGuest,
1643
+ loading: loadingType === "guest",
1644
+ disabled: isLoading,
1645
+ style: styles11.button
1646
+ },
1647
+ "Continue"
1648
+ ), /* @__PURE__ */ import_react19.default.createElement(
1649
+ import_react_native11.Text,
1650
+ {
1651
+ style: [styles11.footerText, { color: theme.colors.textSecondary }]
1652
+ },
1653
+ "By continuing, you agree to Kryptos",
1654
+ " ",
1655
+ /* @__PURE__ */ import_react19.default.createElement(
1656
+ import_react_native11.Text,
1657
+ {
1658
+ style: {
1659
+ color: theme.colors.primary,
1660
+ textDecorationLine: "underline"
1661
+ },
1662
+ onPress: () => import_react_native11.Linking.openURL("https://kryptos.io/privacy-policy")
1663
+ },
1664
+ "Privacy Policy"
1665
+ ),
1666
+ " ",
1667
+ "and",
1668
+ " ",
1669
+ /* @__PURE__ */ import_react19.default.createElement(
1670
+ import_react_native11.Text,
1671
+ {
1672
+ style: {
1673
+ color: theme.colors.primary,
1674
+ textDecorationLine: "underline"
1675
+ },
1676
+ onPress: () => import_react_native11.Linking.openURL("https://kryptos.io/terms-of-services")
1677
+ },
1678
+ "Terms of Service"
1679
+ )
1680
+ )))), /* @__PURE__ */ import_react19.default.createElement(ModalFooter, { style: { paddingVertical: 0 } }, /* @__PURE__ */ import_react19.default.createElement(Footer, null)));
1490
1681
  };
1491
- var styles7 = import_react_native7.StyleSheet.create({
1492
- wrapper: {
1493
- marginBottom: 16
1494
- // theme.spacing.lg
1682
+ var styles11 = import_react_native11.StyleSheet.create({
1683
+ container: {
1684
+ flex: 1,
1685
+ flexDirection: "column",
1686
+ justifyContent: "space-between"
1495
1687
  },
1496
- label: {
1688
+ header: {
1689
+ flex: 1,
1690
+ gap: 8
1691
+ },
1692
+ footer: {
1693
+ flex: 1,
1694
+ justifyContent: "flex-end",
1695
+ gap: 8
1696
+ },
1697
+ title: {
1698
+ fontSize: 18,
1699
+ // theme.fontSize.xl
1497
1700
  fontWeight: "500",
1498
- marginBottom: 12,
1499
- // theme.spacing.md - consistent label spacing
1500
1701
  textAlign: "center"
1501
1702
  },
1502
- container: {
1703
+ infoSection: {
1503
1704
  flexDirection: "row",
1504
- justifyContent: "center",
1505
- gap: 8
1506
- // theme.spacing.sm
1705
+ alignItems: "flex-start",
1706
+ padding: 8,
1707
+ gap: 12
1507
1708
  },
1508
- input: {
1509
- width: 48,
1510
- height: 56,
1511
- borderWidth: 1,
1512
- textAlign: "center",
1709
+ infoIcon: {
1710
+ width: 32,
1711
+ // theme.spacing.xxxl
1712
+ height: 32,
1713
+ // theme.spacing.xxxl
1714
+ borderRadius: 16,
1715
+ // theme.borderRadius.lg
1716
+ alignItems: "center",
1717
+ justifyContent: "center"
1718
+ },
1719
+ infoContent: {
1720
+ flex: 1,
1721
+ gap: 4
1722
+ },
1723
+ infoTitle: {
1724
+ fontSize: 14,
1725
+ // theme.fontSize.md
1513
1726
  fontWeight: "600"
1514
1727
  },
1515
- error: {
1516
- marginTop: 12,
1517
- // theme.spacing.md - consistent error spacing
1518
- textAlign: "center"
1728
+ infoDescription: {
1729
+ fontSize: 13,
1730
+ // theme.fontSize.sm + 1
1731
+ lineHeight: 18
1732
+ },
1733
+ button: {
1734
+ width: "100%"
1735
+ },
1736
+ footerText: {
1737
+ fontSize: 12,
1738
+ // theme.fontSize.sm
1739
+ textAlign: "center",
1740
+ padding: 8,
1741
+ maxWidth: "80%",
1742
+ alignSelf: "center"
1519
1743
  }
1520
1744
  });
1521
1745
 
1522
1746
  // src/molecules/Init.tsx
1523
- var import_react15 = __toESM(require("react"));
1524
- var import_react_native8 = require("react-native");
1747
+ var import_react20 = __toESM(require("react"));
1748
+ var import_react_native12 = require("react-native");
1525
1749
  var Init = ({
1526
1750
  open,
1527
1751
  onSuccess,
1528
1752
  onClose,
1529
1753
  generateLinkToken
1530
1754
  }) => {
1531
- const { setIsInitialized, isInitialized, setLinkToken } = useKryptosConnect();
1755
+ const {
1756
+ setIsInitialized,
1757
+ isInitialized,
1758
+ setLinkToken,
1759
+ setIsAuthorized,
1760
+ setUser
1761
+ } = useKryptosConnect();
1532
1762
  const theme = useTheme();
1533
- const [isFetching, setIsFetching] = import_react15.default.useState(false);
1534
- const [error, setError] = import_react15.default.useState(null);
1535
- const fetchLinkToken = import_react15.default.useCallback(async () => {
1763
+ const [isFetching, setIsFetching] = import_react20.default.useState(false);
1764
+ const [error, setError] = import_react20.default.useState(null);
1765
+ const fetchLinkToken = import_react20.default.useCallback(async () => {
1536
1766
  if (!open) return;
1537
1767
  setIsFetching(true);
1538
1768
  setError(null);
@@ -1545,6 +1775,11 @@ var Init = ({
1545
1775
  }
1546
1776
  setLinkToken(linkToken.link_token);
1547
1777
  setIsInitialized(true);
1778
+ setIsAuthorized(linkToken.isAuthorized || false);
1779
+ if (linkToken.isAuthorized) {
1780
+ const userInfo = await getUserInfo(linkToken.link_token);
1781
+ setUser(userInfo);
1782
+ }
1548
1783
  onSuccess(linkToken.isAuthorized ? { isAuthorized: true } : null);
1549
1784
  } catch (err) {
1550
1785
  console.error("Failed to fetch link token:", err);
@@ -1553,29 +1788,29 @@ var Init = ({
1553
1788
  } finally {
1554
1789
  setIsFetching(false);
1555
1790
  }
1556
- }, [generateLinkToken, open, setIsInitialized, setLinkToken, onSuccess]);
1557
- import_react15.default.useEffect(() => {
1791
+ }, []);
1792
+ import_react20.default.useEffect(() => {
1558
1793
  fetchLinkToken();
1559
1794
  }, [fetchLinkToken]);
1560
- return /* @__PURE__ */ import_react15.default.createElement(Modal, { isOpen: open, onClose, size: "xs" }, /* @__PURE__ */ import_react15.default.createElement(ModalHeader, { onClose }, "Kryptos Connect"), /* @__PURE__ */ import_react15.default.createElement(ModalBody, null, /* @__PURE__ */ import_react15.default.createElement(import_react_native8.View, { style: styles8.container }, isFetching && /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, /* @__PURE__ */ import_react15.default.createElement(
1561
- import_react_native8.ActivityIndicator,
1795
+ return /* @__PURE__ */ import_react20.default.createElement(Modal, { isOpen: open, onClose, size: "xs" }, /* @__PURE__ */ import_react20.default.createElement(ModalHeader, { onClose }, "Kryptos Connect"), /* @__PURE__ */ import_react20.default.createElement(ModalBody, null, /* @__PURE__ */ import_react20.default.createElement(import_react_native12.View, { style: styles12.container }, isFetching && /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(
1796
+ import_react_native12.ActivityIndicator,
1562
1797
  {
1563
1798
  size: "large",
1564
1799
  color: theme.colors.primary,
1565
- style: styles8.spinner
1800
+ style: styles12.spinner
1566
1801
  }
1567
- ), /* @__PURE__ */ import_react15.default.createElement(import_react_native8.Text, { style: [styles8.message, { color: theme.colors.text }] }, isInitialized ? "Fetching link token..." : "Initializing...")), !isFetching && error && /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, /* @__PURE__ */ import_react15.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react15.default.createElement(AlertDescription, null, error)), /* @__PURE__ */ import_react15.default.createElement(
1802
+ ), /* @__PURE__ */ import_react20.default.createElement(import_react_native12.Text, { style: [styles12.message, { color: theme.colors.text }] }, isInitialized ? "Fetching link token..." : "Initializing...")), !isFetching && error && /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react20.default.createElement(AlertDescription, null, error)), /* @__PURE__ */ import_react20.default.createElement(
1568
1803
  Button,
1569
1804
  {
1570
1805
  variant: "primary",
1571
1806
  size: "lg",
1572
1807
  onPress: fetchLinkToken,
1573
- style: styles8.retryButton
1808
+ style: styles12.retryButton
1574
1809
  },
1575
1810
  "Retry"
1576
- )))));
1811
+ )))), /* @__PURE__ */ import_react20.default.createElement(ModalFooter, { style: { paddingVertical: 0 } }, /* @__PURE__ */ import_react20.default.createElement(Footer, null)));
1577
1812
  };
1578
- var styles8 = import_react_native8.StyleSheet.create({
1813
+ var styles12 = import_react_native12.StyleSheet.create({
1579
1814
  container: {
1580
1815
  flex: 1,
1581
1816
  alignItems: "center",
@@ -1602,18 +1837,18 @@ var styles8 = import_react_native8.StyleSheet.create({
1602
1837
  });
1603
1838
 
1604
1839
  // src/molecules/Integration.tsx
1605
- var import_react27 = __toESM(require("react"));
1606
- var import_react_native13 = require("react-native");
1840
+ var import_react31 = __toESM(require("react"));
1841
+ var import_react_native16 = require("react-native");
1607
1842
 
1608
1843
  // src/assets/ArrowLeftIcon.tsx
1609
- var import_react16 = __toESM(require("react"));
1610
- var import_react_native_svg6 = __toESM(require("react-native-svg"));
1844
+ var import_react21 = __toESM(require("react"));
1845
+ var import_react_native_svg7 = __toESM(require("react-native-svg"));
1611
1846
  var ArrowLeftIcon = ({
1612
1847
  size = 20,
1613
1848
  color = "#000"
1614
1849
  }) => {
1615
- return /* @__PURE__ */ import_react16.default.createElement(import_react_native_svg6.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react16.default.createElement(
1616
- import_react_native_svg6.Path,
1850
+ return /* @__PURE__ */ import_react21.default.createElement(import_react_native_svg7.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react21.default.createElement(
1851
+ import_react_native_svg7.Path,
1617
1852
  {
1618
1853
  d: "M19 12H5M12 19l-7-7 7-7",
1619
1854
  stroke: color,
@@ -1625,14 +1860,14 @@ var ArrowLeftIcon = ({
1625
1860
  };
1626
1861
 
1627
1862
  // src/assets/CheckCircleIcon.tsx
1628
- var import_react17 = __toESM(require("react"));
1629
- var import_react_native_svg7 = __toESM(require("react-native-svg"));
1863
+ var import_react22 = __toESM(require("react"));
1864
+ var import_react_native_svg8 = __toESM(require("react-native-svg"));
1630
1865
  var CheckCircleIcon = ({
1631
1866
  size = 20,
1632
1867
  color = "#10B981"
1633
1868
  }) => {
1634
- return /* @__PURE__ */ import_react17.default.createElement(import_react_native_svg7.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react17.default.createElement(
1635
- import_react_native_svg7.Circle,
1869
+ return /* @__PURE__ */ import_react22.default.createElement(import_react_native_svg8.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ import_react22.default.createElement(
1870
+ import_react_native_svg8.Circle,
1636
1871
  {
1637
1872
  cx: 12,
1638
1873
  cy: 12,
@@ -1640,8 +1875,8 @@ var CheckCircleIcon = ({
1640
1875
  stroke: color,
1641
1876
  strokeWidth: 2
1642
1877
  }
1643
- ), /* @__PURE__ */ import_react17.default.createElement(
1644
- import_react_native_svg7.Path,
1878
+ ), /* @__PURE__ */ import_react22.default.createElement(
1879
+ import_react_native_svg8.Path,
1645
1880
  {
1646
1881
  d: "m9 12 2 2 4-4",
1647
1882
  stroke: color,
@@ -1653,21 +1888,21 @@ var CheckCircleIcon = ({
1653
1888
  };
1654
1889
 
1655
1890
  // src/assets/LoaderIcon.tsx
1656
- var import_react18 = __toESM(require("react"));
1657
- var import_react_native9 = require("react-native");
1658
- var import_react_native_svg8 = __toESM(require("react-native-svg"));
1659
- var AnimatedSvg = import_react_native9.Animated.createAnimatedComponent(import_react_native_svg8.default);
1891
+ var import_react23 = __toESM(require("react"));
1892
+ var import_react_native13 = require("react-native");
1893
+ var import_react_native_svg9 = __toESM(require("react-native-svg"));
1894
+ var AnimatedSvg = import_react_native13.Animated.createAnimatedComponent(import_react_native_svg9.default);
1660
1895
  var LoaderIcon = ({
1661
1896
  size = 20,
1662
1897
  color = "#00C693"
1663
1898
  }) => {
1664
- const rotateAnim = import_react18.default.useRef(new import_react_native9.Animated.Value(0)).current;
1665
- import_react18.default.useEffect(() => {
1666
- import_react_native9.Animated.loop(
1667
- import_react_native9.Animated.timing(rotateAnim, {
1899
+ const rotateAnim = import_react23.default.useRef(new import_react_native13.Animated.Value(0)).current;
1900
+ import_react23.default.useEffect(() => {
1901
+ import_react_native13.Animated.loop(
1902
+ import_react_native13.Animated.timing(rotateAnim, {
1668
1903
  toValue: 1,
1669
1904
  duration: 1e3,
1670
- easing: import_react_native9.Easing.linear,
1905
+ easing: import_react_native13.Easing.linear,
1671
1906
  useNativeDriver: true
1672
1907
  })
1673
1908
  ).start();
@@ -1676,7 +1911,7 @@ var LoaderIcon = ({
1676
1911
  inputRange: [0, 1],
1677
1912
  outputRange: ["0deg", "360deg"]
1678
1913
  });
1679
- return /* @__PURE__ */ import_react18.default.createElement(
1914
+ return /* @__PURE__ */ import_react23.default.createElement(
1680
1915
  AnimatedSvg,
1681
1916
  {
1682
1917
  width: size,
@@ -1685,8 +1920,8 @@ var LoaderIcon = ({
1685
1920
  fill: "none",
1686
1921
  style: { transform: [{ rotate: spin }] }
1687
1922
  },
1688
- /* @__PURE__ */ import_react18.default.createElement(
1689
- import_react_native_svg8.Path,
1923
+ /* @__PURE__ */ import_react23.default.createElement(
1924
+ import_react_native_svg9.Path,
1690
1925
  {
1691
1926
  d: "M21 12a9 9 0 1 1-6.219-8.56",
1692
1927
  stroke: color,
@@ -1699,11 +1934,11 @@ var LoaderIcon = ({
1699
1934
  };
1700
1935
 
1701
1936
  // src/assets/SuccessIcon.tsx
1702
- var import_react19 = __toESM(require("react"));
1703
- var import_react_native_svg9 = __toESM(require("react-native-svg"));
1937
+ var import_react24 = __toESM(require("react"));
1938
+ var import_react_native_svg10 = __toESM(require("react-native-svg"));
1704
1939
  var SuccessIcon = ({ size = 64 }) => {
1705
- return /* @__PURE__ */ import_react19.default.createElement(import_react_native_svg9.default, { width: size, height: size, viewBox: "0 0 64 64", fill: "none" }, /* @__PURE__ */ import_react19.default.createElement(
1706
- import_react_native_svg9.Circle,
1940
+ return /* @__PURE__ */ import_react24.default.createElement(import_react_native_svg10.default, { width: size, height: size, viewBox: "0 0 64 64", fill: "none" }, /* @__PURE__ */ import_react24.default.createElement(
1941
+ import_react_native_svg10.Circle,
1707
1942
  {
1708
1943
  cx: 32,
1709
1944
  cy: 32,
@@ -1711,16 +1946,16 @@ var SuccessIcon = ({ size = 64 }) => {
1711
1946
  fill: "#00C693",
1712
1947
  opacity: 0.1
1713
1948
  }
1714
- ), /* @__PURE__ */ import_react19.default.createElement(
1715
- import_react_native_svg9.Circle,
1949
+ ), /* @__PURE__ */ import_react24.default.createElement(
1950
+ import_react_native_svg10.Circle,
1716
1951
  {
1717
1952
  cx: 32,
1718
1953
  cy: 32,
1719
1954
  r: 24,
1720
1955
  fill: "#00C693"
1721
1956
  }
1722
- ), /* @__PURE__ */ import_react19.default.createElement(
1723
- import_react_native_svg9.Path,
1957
+ ), /* @__PURE__ */ import_react24.default.createElement(
1958
+ import_react_native_svg10.Path,
1724
1959
  {
1725
1960
  d: "M24 32l6 6 12-12",
1726
1961
  stroke: "white",
@@ -1732,11 +1967,11 @@ var SuccessIcon = ({ size = 64 }) => {
1732
1967
  };
1733
1968
 
1734
1969
  // src/assets/ErrorIcon.tsx
1735
- var import_react20 = __toESM(require("react"));
1736
- var import_react_native_svg10 = __toESM(require("react-native-svg"));
1970
+ var import_react25 = __toESM(require("react"));
1971
+ var import_react_native_svg11 = __toESM(require("react-native-svg"));
1737
1972
  var ErrorIcon = ({ size = 64 }) => {
1738
- return /* @__PURE__ */ import_react20.default.createElement(import_react_native_svg10.default, { width: size, height: size, viewBox: "0 0 64 64", fill: "none" }, /* @__PURE__ */ import_react20.default.createElement(
1739
- import_react_native_svg10.Circle,
1973
+ return /* @__PURE__ */ import_react25.default.createElement(import_react_native_svg11.default, { width: size, height: size, viewBox: "0 0 64 64", fill: "none" }, /* @__PURE__ */ import_react25.default.createElement(
1974
+ import_react_native_svg11.Circle,
1740
1975
  {
1741
1976
  cx: 32,
1742
1977
  cy: 32,
@@ -1744,16 +1979,16 @@ var ErrorIcon = ({ size = 64 }) => {
1744
1979
  fill: "#EF4444",
1745
1980
  opacity: 0.1
1746
1981
  }
1747
- ), /* @__PURE__ */ import_react20.default.createElement(
1748
- import_react_native_svg10.Circle,
1982
+ ), /* @__PURE__ */ import_react25.default.createElement(
1983
+ import_react_native_svg11.Circle,
1749
1984
  {
1750
1985
  cx: 32,
1751
1986
  cy: 32,
1752
1987
  r: 24,
1753
1988
  fill: "#EF4444"
1754
1989
  }
1755
- ), /* @__PURE__ */ import_react20.default.createElement(
1756
- import_react_native_svg10.Path,
1990
+ ), /* @__PURE__ */ import_react25.default.createElement(
1991
+ import_react_native_svg11.Path,
1757
1992
  {
1758
1993
  d: "M24 24l16 16M40 24l-16 16",
1759
1994
  stroke: "white",
@@ -1765,18 +2000,18 @@ var ErrorIcon = ({ size = 64 }) => {
1765
2000
  };
1766
2001
 
1767
2002
  // src/assets/SearchIcon.tsx
1768
- var import_react21 = __toESM(require("react"));
1769
- var import_react_native_svg11 = __toESM(require("react-native-svg"));
2003
+ var import_react26 = __toESM(require("react"));
2004
+ var import_react_native_svg12 = __toESM(require("react-native-svg"));
1770
2005
 
1771
2006
  // src/assets/PlusIcon.tsx
1772
- var import_react22 = __toESM(require("react"));
1773
- var import_react_native_svg12 = __toESM(require("react-native-svg"));
2007
+ var import_react27 = __toESM(require("react"));
2008
+ var import_react_native_svg13 = __toESM(require("react-native-svg"));
1774
2009
  var PlusIcon = ({
1775
2010
  size = 14,
1776
2011
  color = "#6B7280"
1777
2012
  }) => {
1778
- return /* @__PURE__ */ import_react22.default.createElement(import_react_native_svg12.default, { width: size, height: size, viewBox: "0 0 14 14", fill: "none" }, /* @__PURE__ */ import_react22.default.createElement(
1779
- import_react_native_svg12.Path,
2013
+ return /* @__PURE__ */ import_react27.default.createElement(import_react_native_svg13.default, { width: size, height: size, viewBox: "0 0 14 14", fill: "none" }, /* @__PURE__ */ import_react27.default.createElement(
2014
+ import_react_native_svg13.Path,
1780
2015
  {
1781
2016
  d: "M7 3.5v7M3.5 7h7",
1782
2017
  stroke: color,
@@ -1788,8 +2023,8 @@ var PlusIcon = ({
1788
2023
 
1789
2024
  // src/wallet-connect/index.tsx
1790
2025
  var import_appkit_react_native3 = require("@reown/appkit-react-native");
1791
- var import_react24 = __toESM(require("react"));
1792
- var import_react_native10 = require("react-native");
2026
+ var import_react29 = __toESM(require("react"));
2027
+ var import_react_native14 = require("react-native");
1793
2028
 
1794
2029
  // src/utils/uuid.ts
1795
2030
  function generateUUID() {
@@ -1801,7 +2036,7 @@ function generateUUID() {
1801
2036
  }
1802
2037
 
1803
2038
  // src/wallet-connect/wallet-connect.tsx
1804
- var import_react23 = __toESM(require("react"));
2039
+ var import_react28 = __toESM(require("react"));
1805
2040
  var import_appkit_react_native2 = require("@reown/appkit-react-native");
1806
2041
 
1807
2042
  // src/wallet-connect/AppKitConfig.ts
@@ -1900,7 +2135,7 @@ var createAppKitInstance = (projectId) => {
1900
2135
  // src/wallet-connect/wallet-connect.tsx
1901
2136
  var WalletConnectWrapper = ({ children }) => {
1902
2137
  const { walletConnectProjectId } = useKryptosConnect();
1903
- const appKit = import_react23.default.useMemo(() => {
2138
+ const appKit = import_react28.default.useMemo(() => {
1904
2139
  if (!walletConnectProjectId) {
1905
2140
  console.warn(
1906
2141
  "walletConnectProjectId is missing in KryptosConnectProvider config"
@@ -1910,9 +2145,9 @@ var WalletConnectWrapper = ({ children }) => {
1910
2145
  return createAppKitInstance(walletConnectProjectId);
1911
2146
  }, [walletConnectProjectId]);
1912
2147
  if (!appKit) {
1913
- return /* @__PURE__ */ import_react23.default.createElement(import_react23.default.Fragment, null, children);
2148
+ return /* @__PURE__ */ import_react28.default.createElement(import_react28.default.Fragment, null, children);
1914
2149
  }
1915
- return /* @__PURE__ */ import_react23.default.createElement(import_appkit_react_native2.AppKitProvider, { instance: appKit }, /* @__PURE__ */ import_react23.default.createElement(import_appkit_react_native2.AppKit, null), children);
2150
+ return /* @__PURE__ */ import_react28.default.createElement(import_appkit_react_native2.AppKitProvider, { instance: appKit }, /* @__PURE__ */ import_react28.default.createElement(import_appkit_react_native2.AppKit, null), children);
1916
2151
  };
1917
2152
  var wallet_connect_default = WalletConnectWrapper;
1918
2153
 
@@ -1923,47 +2158,48 @@ var WalletConnectComponent = ({
1923
2158
  onAddHandle,
1924
2159
  handleClose,
1925
2160
  modalOpen,
1926
- setAddIntegrationMode
2161
+ setAddIntegrationMode,
2162
+ providersList
1927
2163
  }) => {
1928
2164
  const { walletConnectProjectId } = useKryptosConnect();
1929
2165
  const theme = useTheme();
1930
2166
  if (!walletConnectProjectId) {
1931
- return /* @__PURE__ */ import_react24.default.createElement(Modal, { isOpen: modalOpen, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react24.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react24.default.createElement(import_react_native10.View, { style: styles9.headerContent }, /* @__PURE__ */ import_react24.default.createElement(
1932
- import_react_native10.TouchableOpacity,
2167
+ return /* @__PURE__ */ import_react29.default.createElement(Modal, { isOpen: modalOpen, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react29.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, { style: styles13.headerContent }, /* @__PURE__ */ import_react29.default.createElement(
2168
+ import_react_native14.TouchableOpacity,
1933
2169
  {
1934
2170
  onPress: () => {
1935
2171
  setAddIntegrationMode(null);
1936
2172
  },
1937
- style: styles9.backButton
2173
+ style: styles13.backButton
1938
2174
  },
1939
- /* @__PURE__ */ import_react24.default.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
1940
- ), /* @__PURE__ */ import_react24.default.createElement(import_react_native10.Text, { style: [styles9.headerTitle, { color: theme.colors.text }] }, "Integration"))), /* @__PURE__ */ import_react24.default.createElement(ModalBody, { scrollable: false, style: styles9.contentContainer }, /* @__PURE__ */ import_react24.default.createElement(import_react_native10.View, { style: styles9.emptyState }, /* @__PURE__ */ import_react24.default.createElement(
1941
- import_react_native10.Text,
2175
+ /* @__PURE__ */ import_react29.default.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
2176
+ ), /* @__PURE__ */ import_react29.default.createElement(import_react_native14.Text, { style: [styles13.headerTitle, { color: theme.colors.text }] }, "Integration"))), /* @__PURE__ */ import_react29.default.createElement(ModalBody, { scrollable: false, style: styles13.contentContainer }, /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, { style: styles13.emptyState }, /* @__PURE__ */ import_react29.default.createElement(
2177
+ import_react_native14.Text,
1942
2178
  {
1943
- style: [styles9.emptyStateTitle, { color: theme.colors.text }]
2179
+ style: [styles13.emptyStateTitle, { color: theme.colors.text }]
1944
2180
  },
1945
2181
  "WalletConnect is not configured"
1946
- ), /* @__PURE__ */ import_react24.default.createElement(
1947
- import_react_native10.Text,
2182
+ ), /* @__PURE__ */ import_react29.default.createElement(
2183
+ import_react_native14.Text,
1948
2184
  {
1949
2185
  style: [
1950
- styles9.infoText,
2186
+ styles13.infoText,
1951
2187
  { color: theme.colors.textSecondary, textAlign: "center" }
1952
2188
  ]
1953
2189
  },
1954
2190
  "Please add a walletConnectProjectId to KryptosConnectProvider to enable wallet connections."
1955
- ), /* @__PURE__ */ import_react24.default.createElement(
2191
+ ), /* @__PURE__ */ import_react29.default.createElement(
1956
2192
  Button,
1957
2193
  {
1958
2194
  variant: "outline",
1959
2195
  size: "sm",
1960
2196
  onPress: () => setAddIntegrationMode(null),
1961
- style: styles9.emptyStateButton
2197
+ style: styles13.emptyStateButton
1962
2198
  },
1963
2199
  "Go back"
1964
2200
  ))));
1965
2201
  }
1966
- return /* @__PURE__ */ import_react24.default.createElement(wallet_connect_default, null, /* @__PURE__ */ import_react24.default.createElement(
2202
+ return /* @__PURE__ */ import_react29.default.createElement(wallet_connect_default, null, /* @__PURE__ */ import_react29.default.createElement(
1967
2203
  ConnectButton,
1968
2204
  {
1969
2205
  integration,
@@ -1971,7 +2207,8 @@ var WalletConnectComponent = ({
1971
2207
  onClose,
1972
2208
  handleClose,
1973
2209
  modalOpen,
1974
- setAddIntegrationMode
2210
+ setAddIntegrationMode,
2211
+ providersList
1975
2212
  }
1976
2213
  ));
1977
2214
  };
@@ -1980,17 +2217,85 @@ function ConnectButton({
1980
2217
  onAddHandle,
1981
2218
  handleClose,
1982
2219
  modalOpen,
1983
- setAddIntegrationMode
2220
+ setAddIntegrationMode,
2221
+ providersList
1984
2222
  }) {
1985
2223
  const theme = useTheme();
1986
2224
  const { open, disconnect } = (0, import_appkit_react_native3.useAppKit)();
1987
- const { address, isConnected, chainId } = (0, import_appkit_react_native3.useAccount)();
2225
+ const { address, isConnected } = (0, import_appkit_react_native3.useAccount)();
1988
2226
  const { linkToken, user, clientId } = useKryptosConnect();
1989
- const [selectedChains, setSelectedChains] = (0, import_react24.useState)(/* @__PURE__ */ new Set());
1990
- const [errorMessage, setErrorMessage] = (0, import_react24.useState)("");
1991
- const [chainErrors, setChainErrors] = (0, import_react24.useState)({});
1992
- const [isLoading, setIsLoading] = (0, import_react24.useState)(false);
1993
- const userUsedChains = integration?.walletSupportedChains || [];
2227
+ const [selectedChains, setSelectedChains] = (0, import_react29.useState)(/* @__PURE__ */ new Set());
2228
+ const [errorMessage, setErrorMessage] = (0, import_react29.useState)("");
2229
+ const [chainErrors, setChainErrors] = (0, import_react29.useState)({});
2230
+ const [isLoading, setIsLoading] = (0, import_react29.useState)(false);
2231
+ const [userUsedChains, setUserUsedChains] = (0, import_react29.useState)([]);
2232
+ const [isFetchingChains, setIsFetchingChains] = (0, import_react29.useState)(false);
2233
+ const availableChains = (0, import_react29.useMemo)(() => {
2234
+ if (userUsedChains.length > 0) {
2235
+ return userUsedChains;
2236
+ }
2237
+ if (integration.walletSupportedChains && integration.walletSupportedChains.length > 0) {
2238
+ return integration.walletSupportedChains;
2239
+ }
2240
+ return [];
2241
+ }, [userUsedChains, integration.walletSupportedChains]);
2242
+ (0, import_react29.useEffect)(() => {
2243
+ if (!isConnected || !address || !address.trim()) {
2244
+ setUserUsedChains([]);
2245
+ setSelectedChains(/* @__PURE__ */ new Set());
2246
+ setIsFetchingChains(false);
2247
+ return;
2248
+ }
2249
+ const debounceTimer = setTimeout(async () => {
2250
+ if (linkToken && address && address.trim() && isConnected) {
2251
+ try {
2252
+ setIsFetchingChains(true);
2253
+ let chains = [];
2254
+ if (integration.isEvmWallet) {
2255
+ const res = await getUserUsedChains(linkToken, address.trim());
2256
+ if (res && Array.isArray(res) && res.length > 0) {
2257
+ chains = res;
2258
+ }
2259
+ }
2260
+ if (chains.length === 0 && integration.walletSupportedChains && integration.walletSupportedChains.length > 0) {
2261
+ chains = integration.walletSupportedChains;
2262
+ }
2263
+ if (chains.length > 0) {
2264
+ setUserUsedChains(chains);
2265
+ setSelectedChains(new Set(chains.map((chain) => chain.id)));
2266
+ } else {
2267
+ setUserUsedChains([]);
2268
+ setSelectedChains(/* @__PURE__ */ new Set());
2269
+ }
2270
+ } catch (error) {
2271
+ console.error("Failed to fetch user chains:", error);
2272
+ if (integration.walletSupportedChains && integration.walletSupportedChains.length > 0) {
2273
+ setUserUsedChains(integration.walletSupportedChains);
2274
+ setSelectedChains(
2275
+ new Set(
2276
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2277
+ integration.walletSupportedChains.map((chain) => chain.id)
2278
+ )
2279
+ );
2280
+ } else {
2281
+ setUserUsedChains([]);
2282
+ setSelectedChains(/* @__PURE__ */ new Set());
2283
+ }
2284
+ } finally {
2285
+ setIsFetchingChains(false);
2286
+ }
2287
+ }
2288
+ }, 500);
2289
+ return () => {
2290
+ clearTimeout(debounceTimer);
2291
+ };
2292
+ }, [
2293
+ linkToken,
2294
+ address,
2295
+ isConnected,
2296
+ integration.isEvmWallet,
2297
+ integration.walletSupportedChains
2298
+ ]);
1994
2299
  const validateForm = () => {
1995
2300
  if (!address) {
1996
2301
  setErrorMessage("Please connect a wallet");
@@ -2008,7 +2313,7 @@ function ConnectButton({
2008
2313
  setIsLoading(true);
2009
2314
  setErrorMessage("");
2010
2315
  setChainErrors({});
2011
- const chainsToProcess = userUsedChains.filter(
2316
+ const chainsToProcess = availableChains.filter(
2012
2317
  (c) => selectedChains.has(c.id)
2013
2318
  );
2014
2319
  const integrationsToAdd = [];
@@ -2016,46 +2321,49 @@ function ConnectButton({
2016
2321
  const walletTestsPayload = chainsToProcess.map((chain) => {
2017
2322
  const walletId = generateUUID();
2018
2323
  const displaySuffix = address ? address?.length > 8 ? `${address.slice(0, 4)}...${address.slice(-4)}` : address : "";
2019
- const alias = `${integration.id} - ${chain.id} (${displaySuffix})`;
2324
+ const alias = `${chain.id} (${displaySuffix})`;
2325
+ const provider = providersList.find((p) => p.id === chain.id);
2020
2326
  return {
2021
2327
  chain,
2022
2328
  walletId,
2023
2329
  alias,
2024
2330
  credential: {
2025
- source: integration.id,
2331
+ source: provider?.id,
2026
2332
  credential: {
2027
2333
  address,
2028
- userId: user?.user?.uid || "0",
2029
- projectId: integration.projectId,
2334
+ userId: user?.user_id || "0",
2335
+ projectId: provider?.projectId,
2030
2336
  apiKey: "0",
2031
2337
  secret: "0",
2032
2338
  privateKey: "0",
2033
2339
  alias,
2034
2340
  walletId,
2035
- exchange: integration.id
2341
+ exchange: provider?.id
2036
2342
  }
2037
2343
  }
2038
2344
  };
2039
2345
  });
2040
2346
  const results = await Promise.allSettled(
2347
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2041
2348
  walletTestsPayload.map(
2042
- (data) => testCredentials(linkToken, data.credential)
2349
+ (testData) => testCredentials(linkToken, { ...testData.credential })
2043
2350
  )
2044
2351
  );
2045
2352
  results.forEach((result, index) => {
2046
2353
  const { chain, walletId, alias } = walletTestsPayload[index];
2047
- if (result.status === "fulfilled" && result.value?.valid) {
2354
+ const provider = providersList.find((p) => p.id === chain.id);
2355
+ if (result.status === "fulfilled" && result.value?.valid && provider) {
2048
2356
  const data = {
2049
2357
  alias,
2050
- exchange: integration.id.toLowerCase(),
2051
- id: integration.id,
2052
- public_name: integration.public_name,
2358
+ exchange: provider.id.toLowerCase(),
2359
+ id: provider.id,
2360
+ public_name: provider.public_name,
2053
2361
  sync_time: (/* @__PURE__ */ new Date()).getTime(),
2054
2362
  fetchAll: true,
2055
- logo: integration.logo || null,
2363
+ logo: provider.logo || null,
2056
2364
  startTime: null,
2057
2365
  endTime: null,
2058
- uid: user?.user?.uid || "",
2366
+ uid: user?.user_id || "",
2059
2367
  walletId,
2060
2368
  clientMetadata: {
2061
2369
  clientId,
@@ -2065,18 +2373,27 @@ function ConnectButton({
2065
2373
  environment: "sandbox"
2066
2374
  },
2067
2375
  addedOn: (/* @__PURE__ */ new Date()).getTime(),
2068
- default_chain: chain.name,
2069
- default_chain_logo: chain.logo || null,
2070
- type: integration.type,
2071
- isNftSupported: integration.isEvmWallet || integration.nftSupport || false,
2072
- chainId: chain.chainId || chain.id,
2073
- address
2376
+ default_chain: provider.id,
2377
+ default_chain_logo: null,
2378
+ type: provider.type,
2379
+ isNftSupported: provider.isEvmWallet || provider.nftSupport || false
2074
2380
  };
2075
2381
  integrationsToAdd.push(data);
2076
2382
  } else {
2077
- errors[chain.id] = "Wallet verification failed";
2383
+ if (result.status === "rejected") {
2384
+ errors[chain.id] = result.reason?.response?.data?.message || "Failed to process chain";
2385
+ } else if (result.status === "fulfilled") {
2386
+ errors[chain.id] = result.value?.message || "Failed to verify chain";
2387
+ }
2078
2388
  }
2079
2389
  });
2390
+ setChainErrors(errors);
2391
+ if (Object.keys(errors).length > 0) {
2392
+ setErrorMessage(
2393
+ `Cannot add integrations. ${Object.keys(errors).length} chain${Object.keys(errors).length > 1 ? "s" : ""} failed verification. Please fix the errors and try again.`
2394
+ );
2395
+ return;
2396
+ }
2080
2397
  if (integrationsToAdd.length > 0) {
2081
2398
  onAddHandle(integrationsToAdd);
2082
2399
  setChainErrors({});
@@ -2094,30 +2411,30 @@ function ConnectButton({
2094
2411
  setIsLoading(false);
2095
2412
  }
2096
2413
  };
2097
- const toggleChainSelection = (chainId2) => {
2414
+ const toggleChainSelection = (chainId) => {
2098
2415
  const newSelected = new Set(selectedChains);
2099
- if (newSelected.has(chainId2)) {
2100
- newSelected.delete(chainId2);
2416
+ if (newSelected.has(chainId)) {
2417
+ newSelected.delete(chainId);
2101
2418
  } else {
2102
- newSelected.add(chainId2);
2419
+ newSelected.add(chainId);
2103
2420
  }
2104
2421
  setSelectedChains(newSelected);
2105
- if (chainErrors[chainId2]) {
2422
+ if (chainErrors[chainId]) {
2106
2423
  const newErrors = { ...chainErrors };
2107
- delete newErrors[chainId2];
2424
+ delete newErrors[chainId];
2108
2425
  setChainErrors(newErrors);
2109
2426
  }
2110
2427
  };
2111
- return /* @__PURE__ */ import_react24.default.createElement(Modal, { isOpen: modalOpen, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react24.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react24.default.createElement(import_react_native10.View, { style: styles9.headerContent }, /* @__PURE__ */ import_react24.default.createElement(
2112
- import_react_native10.TouchableOpacity,
2428
+ return /* @__PURE__ */ import_react29.default.createElement(Modal, { isOpen: modalOpen, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react29.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, { style: styles13.headerContent }, /* @__PURE__ */ import_react29.default.createElement(
2429
+ import_react_native14.TouchableOpacity,
2113
2430
  {
2114
2431
  onPress: () => {
2115
2432
  setAddIntegrationMode(null);
2116
2433
  },
2117
- style: styles9.backButton
2434
+ style: styles13.backButton
2118
2435
  },
2119
- /* @__PURE__ */ import_react24.default.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
2120
- ), /* @__PURE__ */ import_react24.default.createElement(import_react_native10.Text, { style: [styles9.headerTitle, { color: theme.colors.text }] }, "Integration"))), /* @__PURE__ */ import_react24.default.createElement(ModalBody, { scrollable: false, style: styles9.contentContainer }, !isConnected ? /* @__PURE__ */ import_react24.default.createElement(import_react_native10.View, null, /* @__PURE__ */ import_react24.default.createElement(import_react_native10.Text, { style: [styles9.infoText, { color: theme.colors.text }] }, "Connect your wallet to continue"), /* @__PURE__ */ import_react24.default.createElement(
2436
+ /* @__PURE__ */ import_react29.default.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
2437
+ ), /* @__PURE__ */ import_react29.default.createElement(import_react_native14.Text, { style: [styles13.headerTitle, { color: theme.colors.text }] }, "Integration"))), /* @__PURE__ */ import_react29.default.createElement(ModalBody, { scrollable: false, style: styles13.contentContainer }, !isConnected ? /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, null, /* @__PURE__ */ import_react29.default.createElement(import_react_native14.Text, { style: [styles13.infoText, { color: theme.colors.text }] }, "Connect your wallet to continue"), /* @__PURE__ */ import_react29.default.createElement(
2121
2438
  Button,
2122
2439
  {
2123
2440
  variant: "primary",
@@ -2125,107 +2442,149 @@ function ConnectButton({
2125
2442
  onPress: () => open({ view: "Connect" })
2126
2443
  },
2127
2444
  "Connect Wallet"
2128
- )) : /* @__PURE__ */ import_react24.default.createElement(import_react_native10.View, null, /* @__PURE__ */ import_react24.default.createElement(import_react_native10.Text, { style: [styles9.connectedTitle, { color: theme.colors.text }] }, "Wallet Connected"), /* @__PURE__ */ import_react24.default.createElement(import_react_native10.Text, { style: [styles9.connectedText, { color: theme.colors.text }] }, "Address: ", address), /* @__PURE__ */ import_react24.default.createElement(import_react_native10.Text, { style: [styles9.connectedText, { color: theme.colors.text }] }, "Chain: ", chainId), /* @__PURE__ */ import_react24.default.createElement(Button, { variant: "ghost", size: "sm", onPress: () => disconnect() }, "Disconnect Wallet"), userUsedChains.length > 0 && address && /* @__PURE__ */ import_react24.default.createElement(import_react_native10.View, { style: styles9.chainSelection }, /* @__PURE__ */ import_react24.default.createElement(import_react_native10.Text, { style: [styles9.chainTitle, { color: theme.colors.text }] }, "Select Chains to Add:"), /* @__PURE__ */ import_react24.default.createElement(import_react_native10.ScrollView, { contentContainerStyle: styles9.scrollViewContent }, /* @__PURE__ */ import_react24.default.createElement(import_react_native10.View, { style: styles9.chainChips }, userUsedChains.map((chain) => {
2129
- const isSelected = selectedChains.has(chain.id);
2130
- const hasError = chainErrors[chain.id];
2131
- return /* @__PURE__ */ import_react24.default.createElement(
2132
- import_react_native10.TouchableOpacity,
2133
- {
2134
- onPress: () => toggleChainSelection(chain.id),
2135
- style: styles9.chainButton,
2136
- key: chain.id
2137
- },
2138
- /* @__PURE__ */ import_react24.default.createElement(
2139
- import_react_native10.View,
2445
+ )) : /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, { style: styles13.connectedContainer }, /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, { style: styles13.connectedHeader }, /* @__PURE__ */ import_react29.default.createElement(
2446
+ import_react_native14.Text,
2447
+ {
2448
+ style: [styles13.connectedTitle, { color: theme.colors.text }]
2449
+ },
2450
+ "Wallet Connected"
2451
+ ), /* @__PURE__ */ import_react29.default.createElement(
2452
+ import_react_native14.Text,
2453
+ {
2454
+ style: [styles13.connectedText, { color: theme.colors.text }]
2455
+ },
2456
+ "Address: ",
2457
+ address
2458
+ ), /* @__PURE__ */ import_react29.default.createElement(Button, { variant: "ghost", size: "sm", onPress: () => disconnect() }, "Disconnect Wallet"), isFetchingChains ? /* @__PURE__ */ import_react29.default.createElement(
2459
+ import_react_native14.Text,
2460
+ {
2461
+ style: [styles13.fetchingText, { color: theme.colors.text }]
2462
+ },
2463
+ "Fetching chains..."
2464
+ ) : null), availableChains.length > 0 && address && /* @__PURE__ */ import_react29.default.createElement(
2465
+ import_react_native14.ScrollView,
2466
+ {
2467
+ style: styles13.scrollView,
2468
+ contentContainerStyle: styles13.scrollViewContent,
2469
+ showsVerticalScrollIndicator: true,
2470
+ nestedScrollEnabled: true
2471
+ },
2472
+ /* @__PURE__ */ import_react29.default.createElement(import_react_native14.Text, { style: [styles13.chainTitle, { color: theme.colors.text }] }, "Select Chains to Add:"),
2473
+ /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, null, /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, { style: styles13.chainChips }, availableChains.map((chain) => {
2474
+ const isSelected = selectedChains.has(chain.id);
2475
+ const hasError = chainErrors[chain.id];
2476
+ return /* @__PURE__ */ import_react29.default.createElement(
2477
+ import_react_native14.TouchableOpacity,
2140
2478
  {
2141
- style: [
2142
- styles9.chainChip,
2143
- {
2144
- backgroundColor: hasError ? theme.colors.errorLight : isSelected ? theme.colors.primary + "20" : theme.colors.surface,
2145
- borderColor: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.border
2146
- }
2147
- ]
2479
+ onPress: () => toggleChainSelection(chain.id),
2480
+ style: styles13.chainButton,
2481
+ key: chain.id
2148
2482
  },
2149
- /* @__PURE__ */ import_react24.default.createElement(
2150
- import_react_native10.Text,
2483
+ /* @__PURE__ */ import_react29.default.createElement(
2484
+ import_react_native14.View,
2151
2485
  {
2152
2486
  style: [
2153
- styles9.chainName,
2487
+ styles13.chainChip,
2154
2488
  {
2155
- color: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.text
2489
+ backgroundColor: hasError ? theme.colors.errorLight : isSelected ? theme.colors.primary + "20" : theme.colors.surface,
2490
+ borderColor: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.border
2156
2491
  }
2157
2492
  ]
2158
2493
  },
2159
- chain.id
2160
- ),
2161
- isSelected ? /* @__PURE__ */ import_react24.default.createElement(
2162
- CloseIcon,
2163
- {
2164
- size: 12,
2165
- color: hasError ? theme.colors.error : theme.colors.primary
2166
- }
2167
- ) : /* @__PURE__ */ import_react24.default.createElement(
2168
- PlusIcon,
2169
- {
2170
- size: 12,
2171
- color: theme.colors.textSecondary
2172
- }
2494
+ /* @__PURE__ */ import_react29.default.createElement(
2495
+ import_react_native14.Text,
2496
+ {
2497
+ style: [
2498
+ styles13.chainName,
2499
+ {
2500
+ color: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.text
2501
+ }
2502
+ ]
2503
+ },
2504
+ chain.id
2505
+ ),
2506
+ isSelected ? /* @__PURE__ */ import_react29.default.createElement(
2507
+ CloseIcon,
2508
+ {
2509
+ size: 12,
2510
+ color: hasError ? theme.colors.error : theme.colors.primary
2511
+ }
2512
+ ) : /* @__PURE__ */ import_react29.default.createElement(
2513
+ PlusIcon,
2514
+ {
2515
+ size: 12,
2516
+ color: theme.colors.textSecondary
2517
+ }
2518
+ )
2173
2519
  )
2174
- )
2175
- );
2176
- }))), Object.keys(chainErrors).length > 0 && /* @__PURE__ */ import_react24.default.createElement(import_react_native10.View, { style: styles9.chainErrorsContainer }, /* @__PURE__ */ import_react24.default.createElement(
2177
- import_react_native10.Text,
2178
- {
2179
- style: [
2180
- styles9.chainErrorsTitle,
2181
- { color: theme.colors.error }
2182
- ]
2183
- },
2184
- "Errors:"
2185
- ), Object.entries(chainErrors).map(([chainId2, error]) => {
2186
- const chain = userUsedChains.find(
2187
- (c) => c.id === chainId2
2188
- );
2189
- return /* @__PURE__ */ import_react24.default.createElement(
2190
- import_react_native10.Text,
2520
+ );
2521
+ })), errorMessage ? /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, { style: styles13.errorMessageContainer }, /* @__PURE__ */ import_react29.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react29.default.createElement(AlertDescription, null, errorMessage))) : null, Object.keys(chainErrors || {}).length > 0 && /* @__PURE__ */ import_react29.default.createElement(import_react_native14.View, { style: styles13.chainErrorsContainer }, /* @__PURE__ */ import_react29.default.createElement(
2522
+ import_react_native14.Text,
2191
2523
  {
2192
- key: chainId2,
2193
2524
  style: [
2194
- styles9.chainErrorItem,
2525
+ styles13.chainErrorsTitle,
2195
2526
  { color: theme.colors.error }
2196
2527
  ]
2197
2528
  },
2198
- "\u2022 ",
2199
- chain?.name,
2200
- ": ",
2201
- error
2202
- );
2203
- }))), errorMessage ? /* @__PURE__ */ import_react24.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react24.default.createElement(AlertDescription, null, errorMessage)) : null)), userUsedChains.length > 0 && address && /* @__PURE__ */ import_react24.default.createElement(ModalFooter, null, /* @__PURE__ */ import_react24.default.createElement(
2529
+ "Errors:"
2530
+ ), Object.entries(chainErrors).map(([chainId, error]) => {
2531
+ const chain = availableChains.find(
2532
+ (c) => c.id === chainId
2533
+ );
2534
+ return /* @__PURE__ */ import_react29.default.createElement(
2535
+ import_react_native14.Text,
2536
+ {
2537
+ key: chainId,
2538
+ style: [
2539
+ styles13.chainErrorItem,
2540
+ { color: theme.colors.error }
2541
+ ]
2542
+ },
2543
+ "\u2022 ",
2544
+ chain?.name ?? chainId,
2545
+ ": ",
2546
+ String(error)
2547
+ );
2548
+ })))
2549
+ ))), availableChains.length > 0 && address && /* @__PURE__ */ import_react29.default.createElement(ModalFooter, { style: { paddingVertical: 8 } }, /* @__PURE__ */ import_react29.default.createElement(
2204
2550
  Button,
2205
2551
  {
2206
2552
  variant: "outline",
2207
2553
  size: "lg",
2208
2554
  onPress: onSubmitWalletConnect,
2209
2555
  loading: isLoading,
2210
- disabled: isLoading || !!address && userUsedChains.length > 0 && selectedChains.size === 0,
2211
- style: styles9.button
2556
+ disabled: isLoading || !!address && availableChains.length > 0 && selectedChains.size === 0,
2557
+ style: styles13.button
2212
2558
  },
2213
2559
  selectedChains.size > 0 ? `Add ${selectedChains.size} Chain${selectedChains.size > 1 ? "s" : ""}` : "Add Integration"
2214
- )));
2560
+ ), /* @__PURE__ */ import_react29.default.createElement(Footer, null)));
2215
2561
  }
2216
- var styles9 = import_react_native10.StyleSheet.create({
2217
- connectedTitle: { fontSize: 18, fontWeight: "600", marginBottom: 4 },
2562
+ var styles13 = import_react_native14.StyleSheet.create({
2563
+ connectedContainer: {
2564
+ flex: 1
2565
+ },
2566
+ connectedHeader: {
2567
+ marginBottom: 8
2568
+ },
2569
+ connectedTitle: { fontSize: 12, fontWeight: "600", marginBottom: 4 },
2218
2570
  connectedText: { fontSize: 14, marginBottom: 4 },
2571
+ fetchingText: { fontSize: 12, marginBottom: 4, textAlign: "center" },
2219
2572
  infoText: {
2220
2573
  fontSize: 16,
2221
2574
  fontWeight: "600",
2222
2575
  marginBottom: 8,
2223
2576
  textAlign: "center"
2224
2577
  },
2578
+ scrollView: {
2579
+ flex: 1
2580
+ },
2225
2581
  scrollViewContent: {
2226
- paddingBottom: 100,
2582
+ paddingBottom: 40,
2227
2583
  flexGrow: 1
2228
2584
  },
2585
+ errorMessageContainer: {
2586
+ marginTop: 16
2587
+ },
2229
2588
  headerContent: {
2230
2589
  flexDirection: "row",
2231
2590
  alignItems: "center"
@@ -2244,17 +2603,13 @@ var styles9 = import_react_native10.StyleSheet.create({
2244
2603
  contentContainer: {
2245
2604
  padding: 20,
2246
2605
  // theme.spacing.xl
2247
- paddingBottom: 40,
2606
+ paddingBottom: 20,
2248
2607
  width: "100%",
2249
2608
  overflow: "hidden",
2250
2609
  alignSelf: "center",
2251
2610
  flexDirection: "column",
2252
2611
  flex: 1
2253
2612
  },
2254
- chainSelection: {
2255
- marginBottom: 16
2256
- // theme.spacing.lg
2257
- },
2258
2613
  chainTitle: {
2259
2614
  fontSize: 14,
2260
2615
  // theme.fontSize.md
@@ -2306,9 +2661,7 @@ var styles9 = import_react_native10.StyleSheet.create({
2306
2661
  // theme.spacing.xs
2307
2662
  },
2308
2663
  button: {
2309
- width: "100%",
2310
- marginTop: 16
2311
- // theme.spacing.lg - consistent button spacing
2664
+ width: "100%"
2312
2665
  },
2313
2666
  emptyState: {
2314
2667
  flex: 1,
@@ -2326,38 +2679,47 @@ var styles9 = import_react_native10.StyleSheet.create({
2326
2679
  });
2327
2680
 
2328
2681
  // src/molecules/IntegrationForm.tsx
2329
- var import_react25 = __toESM(require("react"));
2330
- var import_react_native11 = require("react-native");
2682
+ var import_react30 = __toESM(require("react"));
2683
+ var import_react_native15 = require("react-native");
2331
2684
  var IntegrationForm = ({
2332
2685
  metadata,
2333
2686
  onAddHandle,
2334
2687
  open,
2335
2688
  setAddIntegrationMode,
2336
- handleClose
2689
+ handleClose,
2690
+ providersList
2337
2691
  }) => {
2338
2692
  const { clientId, linkToken, user } = useKryptosConnect();
2339
2693
  const theme = useTheme();
2340
- const [isLoading, setIsLoading] = import_react25.default.useState(false);
2341
- const [userUsedChains, setUserUsedChains] = import_react25.default.useState([]);
2342
- const [selectedChains, setSelectedChains] = import_react25.default.useState(
2694
+ const [isLoading, setIsLoading] = import_react30.default.useState(false);
2695
+ const [isFetchingChains, setIsFetchingChains] = import_react30.default.useState(false);
2696
+ const [userUsedChains, setUserUsedChains] = import_react30.default.useState([]);
2697
+ const [selectedChains, setSelectedChains] = import_react30.default.useState(
2343
2698
  /* @__PURE__ */ new Set()
2344
2699
  );
2345
- const [chainErrors, setChainErrors] = import_react25.default.useState(
2700
+ const [chainErrors, setChainErrors] = import_react30.default.useState(
2346
2701
  {}
2347
2702
  );
2348
- const [errorMessage, setErrorMessage] = import_react25.default.useState("");
2349
- const [formValues, setFormValues] = import_react25.default.useState({
2703
+ const [errorMessage, setErrorMessage] = import_react30.default.useState("");
2704
+ const [formValues, setFormValues] = import_react30.default.useState({
2350
2705
  address: "",
2351
2706
  account_name: "",
2352
2707
  api_key: "",
2353
2708
  secret_key: "",
2354
2709
  password: ""
2355
2710
  });
2356
- const [formErrors, setFormErrors] = import_react25.default.useState({});
2357
- import_react25.default.useEffect(() => {
2358
- const fetchUserUsedChains = async () => {
2359
- if (linkToken && formValues.address && formValues.address.trim()) {
2711
+ const [formErrors, setFormErrors] = import_react30.default.useState({});
2712
+ import_react30.default.useEffect(() => {
2713
+ if (!formValues.address || !formValues.address.trim()) {
2714
+ setUserUsedChains([]);
2715
+ setSelectedChains(/* @__PURE__ */ new Set());
2716
+ setIsFetchingChains(false);
2717
+ return;
2718
+ }
2719
+ const debounceTimer = setTimeout(async () => {
2720
+ if (linkToken && formValues.address && formValues.address.trim() && metadata.isEvmWallet) {
2360
2721
  try {
2722
+ setIsFetchingChains(true);
2361
2723
  const res = await getUserUsedChains(
2362
2724
  linkToken,
2363
2725
  formValues.address.trim()
@@ -2365,18 +2727,22 @@ var IntegrationForm = ({
2365
2727
  if (res && Array.isArray(res)) {
2366
2728
  setUserUsedChains(res);
2367
2729
  setSelectedChains(new Set(res.map((chain) => chain.id)));
2730
+ } else {
2731
+ setUserUsedChains([]);
2732
+ setSelectedChains(/* @__PURE__ */ new Set());
2368
2733
  }
2369
2734
  } catch (error) {
2370
2735
  console.error("Failed to fetch user chains:", error);
2371
2736
  setUserUsedChains([]);
2372
2737
  setSelectedChains(/* @__PURE__ */ new Set());
2738
+ } finally {
2739
+ setIsFetchingChains(false);
2373
2740
  }
2374
- } else {
2375
- setUserUsedChains([]);
2376
- setSelectedChains(/* @__PURE__ */ new Set());
2377
2741
  }
2742
+ }, 500);
2743
+ return () => {
2744
+ clearTimeout(debounceTimer);
2378
2745
  };
2379
- fetchUserUsedChains();
2380
2746
  }, [linkToken, formValues.address]);
2381
2747
  const toggleChainSelection = (chainId) => {
2382
2748
  const newSelected = new Set(selectedChains);
@@ -2435,7 +2801,7 @@ var IntegrationForm = ({
2435
2801
  accountName: formValues.account_name?.trim() || "0",
2436
2802
  address: formValues.address?.trim() || "0",
2437
2803
  password: formValues.password?.trim() || "0",
2438
- userId: user?.user?.uid || "0",
2804
+ userId: user?.user_id || "0",
2439
2805
  projectId: metadata?.projectId || "0",
2440
2806
  privateKey: "0",
2441
2807
  alias,
@@ -2463,7 +2829,7 @@ var IntegrationForm = ({
2463
2829
  logo: metadata.logo || null,
2464
2830
  startTime: null,
2465
2831
  endTime: null,
2466
- uid: user?.user?.uid || "",
2832
+ uid: user?.user_id || "",
2467
2833
  walletId,
2468
2834
  clientMetadata: {
2469
2835
  clientId,
@@ -2477,7 +2843,7 @@ var IntegrationForm = ({
2477
2843
  default_chain_logo: chain.logo || null,
2478
2844
  type: metadata.type,
2479
2845
  isNftSupported: metadata.isEvmWallet || metadata.nftSupport || false,
2480
- chainId: chain.chainId || chain.id,
2846
+ chainId: chain?.community_id || "",
2481
2847
  address: formValues.address
2482
2848
  };
2483
2849
  if (formValues.account_name)
@@ -2514,7 +2880,7 @@ var IntegrationForm = ({
2514
2880
  accountName: formValues.account_name?.trim() || "0",
2515
2881
  address: formValues.address?.trim() || "0",
2516
2882
  password: formValues.password?.trim() || "0",
2517
- userId: user?.user?.uid || "0",
2883
+ userId: user?.user_id || "0",
2518
2884
  projectId: metadata?.projectId || "0",
2519
2885
  privateKey: "0",
2520
2886
  alias,
@@ -2523,7 +2889,7 @@ var IntegrationForm = ({
2523
2889
  }
2524
2890
  };
2525
2891
  const testResult = await testCredentials(linkToken, { ...credential });
2526
- if (!testResult?.value?.valid) {
2892
+ if (!testResult?.valid) {
2527
2893
  setErrorMessage(
2528
2894
  testResult?.value?.message || "Credentials are invalid"
2529
2895
  );
@@ -2539,7 +2905,7 @@ var IntegrationForm = ({
2539
2905
  logo: metadata.logo || null,
2540
2906
  startTime: null,
2541
2907
  endTime: null,
2542
- uid: user?.user?.uid || "",
2908
+ uid: user?.user_id || "",
2543
2909
  walletId,
2544
2910
  clientMetadata: {
2545
2911
  clientId,
@@ -2555,7 +2921,7 @@ var IntegrationForm = ({
2555
2921
  isNftSupported: metadata.isEvmWallet || metadata.nftSupport || false
2556
2922
  };
2557
2923
  if (metadata.community_id) {
2558
- data.chainId = Number(metadata.community_id);
2924
+ data.chainId = metadata.community_id;
2559
2925
  }
2560
2926
  if (formValues.address) data.address = formValues.address;
2561
2927
  if (formValues.account_name) data.accountName = formValues.account_name;
@@ -2590,24 +2956,24 @@ var IntegrationForm = ({
2590
2956
  };
2591
2957
  const hasNoFields = !metadata.password && !metadata.secret_key && !metadata.api_key && !metadata.address && !metadata.account_name;
2592
2958
  const shouldShowFormFields = metadata.password || metadata.secret_key || metadata.api_key || metadata.address || metadata.account_name;
2593
- const renderLogo = () => metadata.logo ? /* @__PURE__ */ import_react25.default.createElement(
2594
- import_react_native11.Image,
2959
+ const renderLogo = () => metadata.logo ? /* @__PURE__ */ import_react30.default.createElement(
2960
+ import_react_native15.Image,
2595
2961
  {
2596
2962
  source: { uri: metadata.logo },
2597
- style: styles10.logo,
2963
+ style: styles14.logo,
2598
2964
  resizeMode: "contain"
2599
2965
  }
2600
- ) : /* @__PURE__ */ import_react25.default.createElement(
2601
- import_react_native11.View,
2966
+ ) : /* @__PURE__ */ import_react30.default.createElement(
2967
+ import_react_native15.View,
2602
2968
  {
2603
2969
  style: [
2604
- styles10.logoPlaceholder,
2970
+ styles14.logoPlaceholder,
2605
2971
  { backgroundColor: theme.colors.surface }
2606
2972
  ]
2607
2973
  },
2608
- /* @__PURE__ */ import_react25.default.createElement(import_react_native11.Text, { style: { color: theme.colors.text } }, metadata.name?.charAt(0) || "?")
2974
+ /* @__PURE__ */ import_react30.default.createElement(import_react_native15.Text, { style: { color: theme.colors.text } }, metadata.name?.charAt(0) || "?")
2609
2975
  );
2610
- const renderInput = (key, props) => /* @__PURE__ */ import_react25.default.createElement(
2976
+ const renderInput = (key, props) => /* @__PURE__ */ import_react30.default.createElement(
2611
2977
  Input,
2612
2978
  {
2613
2979
  placeholder: props.placeholder,
@@ -2619,33 +2985,33 @@ var IntegrationForm = ({
2619
2985
  secureTextEntry: props.secureTextEntry
2620
2986
  }
2621
2987
  );
2622
- const renderErrorAlert = () => errorMessage ? /* @__PURE__ */ import_react25.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react25.default.createElement(AlertDescription, null, errorMessage)) : null;
2623
- const renderChainSelection = () => userUsedChains.length > 0 && formValues.address && /* @__PURE__ */ import_react25.default.createElement(import_react_native11.View, { style: styles10.chainSelection }, /* @__PURE__ */ import_react25.default.createElement(import_react_native11.Text, { style: [styles10.chainTitle, { color: theme.colors.text }] }, "Select Chains to Add:"), /* @__PURE__ */ import_react25.default.createElement(import_react_native11.ScrollView, { contentContainerStyle: styles10.scrollViewContent }, /* @__PURE__ */ import_react25.default.createElement(import_react_native11.View, { style: styles10.chainChips }, userUsedChains.map((chain) => {
2988
+ const renderErrorAlert = () => errorMessage ? /* @__PURE__ */ import_react30.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react30.default.createElement(AlertDescription, null, errorMessage)) : null;
2989
+ const renderChainSelection = () => userUsedChains.length > 0 && formValues.address && /* @__PURE__ */ import_react30.default.createElement(import_react_native15.View, { style: styles14.chainSelection }, /* @__PURE__ */ import_react30.default.createElement(import_react_native15.Text, { style: [styles14.chainTitle, { color: theme.colors.text }] }, "Select Chains to Add:"), /* @__PURE__ */ import_react30.default.createElement(import_react_native15.ScrollView, { contentContainerStyle: styles14.scrollViewContent }, /* @__PURE__ */ import_react30.default.createElement(import_react_native15.View, { style: styles14.chainChips }, userUsedChains.map((chain) => {
2624
2990
  const isSelected = selectedChains.has(chain.id);
2625
2991
  const hasError = chainErrors[chain.id];
2626
- return /* @__PURE__ */ import_react25.default.createElement(
2627
- import_react_native11.TouchableOpacity,
2992
+ return /* @__PURE__ */ import_react30.default.createElement(
2993
+ import_react_native15.TouchableOpacity,
2628
2994
  {
2629
2995
  onPress: () => toggleChainSelection(chain.id),
2630
- style: styles10.chainButton,
2996
+ style: styles14.chainButton,
2631
2997
  key: chain.id
2632
2998
  },
2633
- /* @__PURE__ */ import_react25.default.createElement(
2634
- import_react_native11.View,
2999
+ /* @__PURE__ */ import_react30.default.createElement(
3000
+ import_react_native15.View,
2635
3001
  {
2636
3002
  style: [
2637
- styles10.chainChip,
3003
+ styles14.chainChip,
2638
3004
  {
2639
3005
  backgroundColor: hasError ? theme.colors.errorLight : isSelected ? theme.colors.primary + "20" : theme.colors.surface,
2640
3006
  borderColor: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.border
2641
3007
  }
2642
3008
  ]
2643
3009
  },
2644
- /* @__PURE__ */ import_react25.default.createElement(
2645
- import_react_native11.Text,
3010
+ /* @__PURE__ */ import_react30.default.createElement(
3011
+ import_react_native15.Text,
2646
3012
  {
2647
3013
  style: [
2648
- styles10.chainName,
3014
+ styles14.chainName,
2649
3015
  {
2650
3016
  color: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.text
2651
3017
  }
@@ -2653,28 +3019,28 @@ var IntegrationForm = ({
2653
3019
  },
2654
3020
  chain.name
2655
3021
  ),
2656
- isSelected ? /* @__PURE__ */ import_react25.default.createElement(
3022
+ isSelected ? /* @__PURE__ */ import_react30.default.createElement(
2657
3023
  CloseIcon,
2658
3024
  {
2659
3025
  size: 12,
2660
3026
  color: hasError ? theme.colors.error : theme.colors.primary
2661
3027
  }
2662
- ) : /* @__PURE__ */ import_react25.default.createElement(PlusIcon, { size: 12, color: theme.colors.textSecondary })
3028
+ ) : /* @__PURE__ */ import_react30.default.createElement(PlusIcon, { size: 12, color: theme.colors.textSecondary })
2663
3029
  )
2664
3030
  );
2665
- }))), Object.keys(chainErrors).length > 0 && /* @__PURE__ */ import_react25.default.createElement(import_react_native11.View, { style: styles10.chainErrorsContainer }, /* @__PURE__ */ import_react25.default.createElement(
2666
- import_react_native11.Text,
3031
+ }))), Object.keys(chainErrors).length > 0 && /* @__PURE__ */ import_react30.default.createElement(import_react_native15.View, { style: styles14.chainErrorsContainer }, /* @__PURE__ */ import_react30.default.createElement(
3032
+ import_react_native15.Text,
2667
3033
  {
2668
- style: [styles10.chainErrorsTitle, { color: theme.colors.error }]
3034
+ style: [styles14.chainErrorsTitle, { color: theme.colors.error }]
2669
3035
  },
2670
3036
  "Errors:"
2671
3037
  ), Object.entries(chainErrors).map(([chainId, error]) => {
2672
3038
  const chain = userUsedChains.find((c) => c.id === chainId);
2673
- return /* @__PURE__ */ import_react25.default.createElement(
2674
- import_react_native11.Text,
3039
+ return /* @__PURE__ */ import_react30.default.createElement(
3040
+ import_react_native15.Text,
2675
3041
  {
2676
3042
  key: chainId,
2677
- style: [styles10.chainErrorItem, { color: theme.colors.error }]
3043
+ style: [styles14.chainErrorItem, { color: theme.colors.error }]
2678
3044
  },
2679
3045
  "\u2022 ",
2680
3046
  chain?.name,
@@ -2682,7 +3048,7 @@ var IntegrationForm = ({
2682
3048
  error
2683
3049
  );
2684
3050
  })));
2685
- const renderFormBlock = () => /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement(import_react_native11.View, { style: styles10.header }, renderLogo(), /* @__PURE__ */ import_react25.default.createElement(import_react_native11.Text, { style: [styles10.name, { color: theme.colors.text }] }, metadata.name)), renderErrorAlert(), shouldShowFormFields && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, metadata.address && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, renderInput("address", {
3051
+ const renderFormBlock = () => /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, /* @__PURE__ */ import_react30.default.createElement(import_react_native15.View, { style: styles14.header }, renderLogo(), /* @__PURE__ */ import_react30.default.createElement(import_react_native15.Text, { style: [styles14.name, { color: theme.colors.text }] }, metadata.name)), renderErrorAlert(), shouldShowFormFields && /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, metadata.address && /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, renderInput("address", {
2686
3052
  placeholder: "Enter address",
2687
3053
  autoCapitalize: "none",
2688
3054
  autoCorrect: false
@@ -2698,27 +3064,27 @@ var IntegrationForm = ({
2698
3064
  }), metadata.password && renderInput("password", {
2699
3065
  placeholder: "Enter Password",
2700
3066
  secureTextEntry: true
2701
- })), hasNoFields && !metadata?.isWalletConnectSupported && /* @__PURE__ */ import_react25.default.createElement(Alert, { variant: "default", style: { marginTop: 12 } }, /* @__PURE__ */ import_react25.default.createElement(AlertDescription, null, "This integration is not supported here yet \u2014 try using it through our Kryptos Platform.")));
3067
+ })), hasNoFields && !metadata?.isWalletConnectSupported && /* @__PURE__ */ import_react30.default.createElement(Alert, { variant: "default", style: { marginTop: 12 } }, /* @__PURE__ */ import_react30.default.createElement(AlertDescription, null, "This integration is not supported here yet \u2014 try using it through our Kryptos Platform.")));
2702
3068
  const addIntegrationLabel = formValues.address && userUsedChains.length > 0 && selectedChains.size > 0 ? `Add ${selectedChains.size} Chain${selectedChains.size !== 1 ? "s" : ""}` : "Add Integration";
2703
- return /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, !metadata?.isWalletConnectSupported ? /* @__PURE__ */ import_react25.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react25.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react25.default.createElement(import_react_native11.View, { style: styles10.headerContent }, /* @__PURE__ */ import_react25.default.createElement(
2704
- import_react_native11.TouchableOpacity,
3069
+ return /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, !metadata?.isWalletConnectSupported ? /* @__PURE__ */ import_react30.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react30.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react30.default.createElement(import_react_native15.View, { style: styles14.headerContent }, /* @__PURE__ */ import_react30.default.createElement(
3070
+ import_react_native15.TouchableOpacity,
2705
3071
  {
2706
3072
  onPress: () => setAddIntegrationMode(null),
2707
- style: styles10.backButton
3073
+ style: styles14.backButton
2708
3074
  },
2709
- /* @__PURE__ */ import_react25.default.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
2710
- ), /* @__PURE__ */ import_react25.default.createElement(import_react_native11.Text, { style: [styles10.headerTitle, { color: theme.colors.text }] }, "Integration"))), /* @__PURE__ */ import_react25.default.createElement(ModalBody, { scrollable: false, style: styles10.contentContainer }, renderFormBlock()), !hasNoFields && /* @__PURE__ */ import_react25.default.createElement(ModalFooter, null, /* @__PURE__ */ import_react25.default.createElement(
3075
+ /* @__PURE__ */ import_react30.default.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
3076
+ ), /* @__PURE__ */ import_react30.default.createElement(import_react_native15.Text, { style: [styles14.headerTitle, { color: theme.colors.text }] }, "Integration"))), /* @__PURE__ */ import_react30.default.createElement(ModalBody, { scrollable: false, style: styles14.contentContainer }, renderFormBlock()), !hasNoFields && /* @__PURE__ */ import_react30.default.createElement(ModalFooter, { style: { paddingVertical: 8 } }, /* @__PURE__ */ import_react30.default.createElement(
2711
3077
  Button,
2712
3078
  {
2713
3079
  variant: "outline",
2714
3080
  size: "lg",
2715
3081
  onPress: handleSubmit,
2716
3082
  loading: isLoading,
2717
- disabled: isLoading || !!formValues.address && userUsedChains.length > 0 && selectedChains.size === 0,
2718
- style: styles10.button
3083
+ disabled: isLoading || isFetchingChains || !!formValues.address && userUsedChains.length > 0 && selectedChains.size === 0,
3084
+ style: styles14.button
2719
3085
  },
2720
3086
  addIntegrationLabel
2721
- ))) : /* @__PURE__ */ import_react25.default.createElement(
3087
+ ), /* @__PURE__ */ import_react30.default.createElement(Footer, null))) : /* @__PURE__ */ import_react30.default.createElement(
2722
3088
  WalletConnectComponent,
2723
3089
  {
2724
3090
  integration: metadata,
@@ -2726,11 +3092,12 @@ var IntegrationForm = ({
2726
3092
  onAddHandle,
2727
3093
  modalOpen: open,
2728
3094
  setAddIntegrationMode,
2729
- handleClose
3095
+ handleClose,
3096
+ providersList
2730
3097
  }
2731
3098
  ));
2732
3099
  };
2733
- var styles10 = import_react_native11.StyleSheet.create({
3100
+ var styles14 = import_react_native15.StyleSheet.create({
2734
3101
  scrollViewContent: {
2735
3102
  flexGrow: 1,
2736
3103
  paddingBottom: 100
@@ -2847,66 +3214,9 @@ var styles10 = import_react_native11.StyleSheet.create({
2847
3214
  // theme.spacing.xs
2848
3215
  },
2849
3216
  button: {
2850
- width: "100%",
2851
- marginTop: 16
2852
- // theme.spacing.lg - consistent button spacing
2853
- }
2854
- });
2855
-
2856
- // src/components/SkeletonItem.tsx
2857
- var import_react26 = __toESM(require("react"));
2858
- var import_react_native12 = require("react-native");
2859
- var SkeletonItem = () => {
2860
- const opacity = (0, import_react26.useRef)(new import_react_native12.Animated.Value(0.3)).current;
2861
- (0, import_react26.useEffect)(() => {
2862
- import_react_native12.Animated.loop(
2863
- import_react_native12.Animated.sequence([
2864
- import_react_native12.Animated.timing(opacity, {
2865
- toValue: 1,
2866
- duration: 600,
2867
- useNativeDriver: true
2868
- }),
2869
- import_react_native12.Animated.timing(opacity, {
2870
- toValue: 0.3,
2871
- duration: 600,
2872
- useNativeDriver: true
2873
- })
2874
- ])
2875
- ).start();
2876
- }, []);
2877
- return /* @__PURE__ */ import_react26.default.createElement(import_react_native12.Animated.View, { style: [styles11.row, { opacity }] }, /* @__PURE__ */ import_react26.default.createElement(import_react_native12.View, { style: styles11.iconCircle }), /* @__PURE__ */ import_react26.default.createElement(import_react_native12.View, { style: styles11.textBlock }, /* @__PURE__ */ import_react26.default.createElement(import_react_native12.View, { style: styles11.lineLong }), /* @__PURE__ */ import_react26.default.createElement(import_react_native12.View, { style: styles11.lineShort })));
2878
- };
2879
- var styles11 = import_react_native12.StyleSheet.create({
2880
- row: {
2881
- flexDirection: "row",
2882
- alignItems: "center",
2883
- paddingVertical: 16
2884
- },
2885
- iconCircle: {
2886
- width: 45,
2887
- height: 45,
2888
- borderRadius: 22.5,
2889
- backgroundColor: "#E5E5E5"
2890
- },
2891
- textBlock: {
2892
- marginLeft: 12,
2893
- flex: 1
2894
- },
2895
- lineShort: {
2896
- width: "50%",
2897
- height: 14,
2898
- borderRadius: 6,
2899
- backgroundColor: "#E5E5E5"
2900
- },
2901
- lineLong: {
2902
- marginBottom: 6,
2903
- width: "100%",
2904
- height: 14,
2905
- borderRadius: 6,
2906
- backgroundColor: "#E5E5E5"
3217
+ width: "100%"
2907
3218
  }
2908
3219
  });
2909
- var SkeletonItem_default = SkeletonItem;
2910
3220
 
2911
3221
  // src/molecules/Integration.tsx
2912
3222
  var Integration = ({
@@ -2916,13 +3226,14 @@ var Integration = ({
2916
3226
  }) => {
2917
3227
  const { appName, linkToken } = useKryptosConnect();
2918
3228
  const theme = useTheme();
2919
- const [addIntegrationMode, setAddIntegrationMode] = import_react27.default.useState(null);
2920
- const [query, setQuery] = import_react27.default.useState("");
2921
- const [supportedProviders, setSupportedProviders] = import_react27.default.useState([]);
2922
- const [addedIntegrations, setAddedIntegrations] = import_react27.default.useState([]);
2923
- const [existingIntegrations, setExistingIntegrations] = import_react27.default.useState([]);
2924
- const [isLoading, setIsLoading] = import_react27.default.useState(false);
2925
- const [errorMessage, setErrorMessage] = import_react27.default.useState("");
3229
+ const [addIntegrationMode, setAddIntegrationMode] = import_react31.default.useState(null);
3230
+ const [query, setQuery] = import_react31.default.useState("");
3231
+ const [activeTab, setActiveTab] = import_react31.default.useState("all");
3232
+ const [supportedProviders, setSupportedProviders] = import_react31.default.useState([]);
3233
+ const [addedIntegrations, setAddedIntegrations] = import_react31.default.useState([]);
3234
+ const [existingIntegrations, setExistingIntegrations] = import_react31.default.useState([]);
3235
+ const [isLoading, setIsLoading] = import_react31.default.useState(false);
3236
+ const [errorMessage, setErrorMessage] = import_react31.default.useState("");
2926
3237
  const handleClose = () => {
2927
3238
  onClose();
2928
3239
  };
@@ -2953,13 +3264,13 @@ var Integration = ({
2953
3264
  setIsLoading(false);
2954
3265
  }
2955
3266
  };
2956
- import_react27.default.useEffect(() => {
3267
+ import_react31.default.useEffect(() => {
2957
3268
  if (linkToken) {
2958
3269
  fetchSupportedProviders();
2959
3270
  fetchExistingIntegrations();
2960
3271
  }
2961
3272
  }, [linkToken]);
2962
- const isIntegrationAdded = import_react27.default.useCallback(
3273
+ const isIntegrationAdded = import_react31.default.useCallback(
2963
3274
  (publicName) => {
2964
3275
  const integrations = [...addedIntegrations, ...existingIntegrations];
2965
3276
  return integrations.some(
@@ -2968,7 +3279,7 @@ var Integration = ({
2968
3279
  },
2969
3280
  [addedIntegrations, existingIntegrations]
2970
3281
  );
2971
- const getIntegrationCount = import_react27.default.useCallback(
3282
+ const getIntegrationCount = import_react31.default.useCallback(
2972
3283
  (publicName) => {
2973
3284
  const integrations = [...addedIntegrations, ...existingIntegrations];
2974
3285
  return integrations.filter(
@@ -2977,22 +3288,24 @@ var Integration = ({
2977
3288
  },
2978
3289
  [addedIntegrations, existingIntegrations]
2979
3290
  );
2980
- const filteredResults = import_react27.default.useMemo(() => {
2981
- if (query) {
2982
- const lowerQuery = query.toLowerCase();
2983
- return supportedProviders.filter(
2984
- (provider) => provider.name?.toLowerCase().includes(lowerQuery) || provider.public_name?.toLowerCase().includes(lowerQuery) || provider.id?.toLowerCase().includes(lowerQuery)
2985
- );
3291
+ const filteredResults = import_react31.default.useMemo(() => {
3292
+ let filtered = supportedProviders;
3293
+ if (activeTab !== "all") {
3294
+ filtered = filtered.filter((provider) => provider.type === activeTab);
2986
3295
  }
2987
- return [...supportedProviders].sort((a, b) => {
3296
+ if (query?.trim()) {
3297
+ const lowerQuery = query.trim().toLowerCase();
3298
+ filtered = filtered.filter((provider) => {
3299
+ return provider.name?.toLowerCase().includes(lowerQuery) || provider.public_name?.toLowerCase().includes(lowerQuery) || provider.id?.toLowerCase().includes(lowerQuery);
3300
+ });
3301
+ }
3302
+ return [...filtered].sort((a, b) => {
2988
3303
  const countA = getIntegrationCount(a.public_name);
2989
3304
  const countB = getIntegrationCount(b.public_name);
2990
- if (countB !== countA) {
2991
- return countB - countA;
2992
- }
2993
- return a.name.localeCompare(b.name);
3305
+ if (countB !== countA) return countB - countA;
3306
+ return (a.name ?? "").localeCompare(b.name ?? "");
2994
3307
  });
2995
- }, [query, supportedProviders, getIntegrationCount]);
3308
+ }, [query, supportedProviders, getIntegrationCount, activeTab]);
2996
3309
  const handleAddIntegration = async () => {
2997
3310
  try {
2998
3311
  setIsLoading(true);
@@ -3015,11 +3328,11 @@ var Integration = ({
3015
3328
  setIsLoading(false);
3016
3329
  }
3017
3330
  };
3018
- const renderProviderItem = ({ item }) => /* @__PURE__ */ import_react27.default.createElement(
3019
- import_react_native13.TouchableOpacity,
3331
+ const renderProviderItem = ({ item }) => /* @__PURE__ */ import_react31.default.createElement(
3332
+ import_react_native16.TouchableOpacity,
3020
3333
  {
3021
3334
  style: [
3022
- styles12.providerItem,
3335
+ styles15.providerItem,
3023
3336
  {
3024
3337
  backgroundColor: theme.colors.surface,
3025
3338
  borderColor: theme.colors.border
@@ -3028,44 +3341,44 @@ var Integration = ({
3028
3341
  onPress: () => setAddIntegrationMode(item),
3029
3342
  activeOpacity: 0.7
3030
3343
  },
3031
- /* @__PURE__ */ import_react27.default.createElement(import_react_native13.View, { style: styles12.providerInfo }, item?.logo ? /* @__PURE__ */ import_react27.default.createElement(
3032
- import_react_native13.Image,
3344
+ /* @__PURE__ */ import_react31.default.createElement(import_react_native16.View, { style: styles15.providerInfo }, item?.logo ? /* @__PURE__ */ import_react31.default.createElement(
3345
+ import_react_native16.Image,
3033
3346
  {
3034
3347
  source: { uri: item?.logo },
3035
- style: styles12.providerLogo,
3348
+ style: styles15.providerLogo,
3036
3349
  resizeMode: "contain"
3037
3350
  }
3038
- ) : /* @__PURE__ */ import_react27.default.createElement(
3039
- import_react_native13.View,
3351
+ ) : /* @__PURE__ */ import_react31.default.createElement(
3352
+ import_react_native16.View,
3040
3353
  {
3041
3354
  style: [
3042
- styles12.providerLogoPlaceholder,
3355
+ styles15.providerLogoPlaceholder,
3043
3356
  { backgroundColor: theme.colors.surfaceSecondary }
3044
3357
  ]
3045
3358
  },
3046
- /* @__PURE__ */ import_react27.default.createElement(import_react_native13.Text, { style: { color: theme.colors.text } }, item?.name?.charAt(0) || "?")
3047
- ), /* @__PURE__ */ import_react27.default.createElement(import_react_native13.Text, { style: [styles12.providerName, { color: theme.colors.text }] }, item?.name + "\u200B")),
3048
- isIntegrationAdded(item?.public_name) && /* @__PURE__ */ import_react27.default.createElement(import_react_native13.View, { style: styles12.providerStatus }, /* @__PURE__ */ import_react27.default.createElement(CheckCircleIcon, { size: 18, color: theme.colors.success }), /* @__PURE__ */ import_react27.default.createElement(
3049
- import_react_native13.Text,
3359
+ /* @__PURE__ */ import_react31.default.createElement(import_react_native16.Text, { style: { color: theme.colors.text } }, item?.name?.charAt(0) || "?")
3360
+ ), /* @__PURE__ */ import_react31.default.createElement(import_react_native16.Text, { style: [styles15.providerName, { color: theme.colors.text }] }, item?.name + "\u200B")),
3361
+ isIntegrationAdded(item?.public_name) && /* @__PURE__ */ import_react31.default.createElement(import_react_native16.View, { style: styles15.providerStatus }, /* @__PURE__ */ import_react31.default.createElement(CheckCircleIcon, { size: 18, color: theme.colors.success }), /* @__PURE__ */ import_react31.default.createElement(
3362
+ import_react_native16.Text,
3050
3363
  {
3051
3364
  style: [
3052
- styles12.providerCount,
3365
+ styles15.providerCount,
3053
3366
  { color: theme.colors.textSecondary }
3054
3367
  ]
3055
3368
  },
3056
3369
  getIntegrationCount(item?.public_name)
3057
3370
  ))
3058
3371
  );
3059
- const renderSkeletonItem = () => /* @__PURE__ */ import_react27.default.createElement(SkeletonItem_default, null);
3060
- return /* @__PURE__ */ import_react27.default.createElement(import_react27.default.Fragment, null, !addIntegrationMode ? /* @__PURE__ */ import_react27.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react27.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react27.default.createElement(import_react_native13.View, { style: styles12.headerContent }, addIntegrationMode && /* @__PURE__ */ import_react27.default.createElement(
3061
- import_react_native13.TouchableOpacity,
3372
+ const renderSkeletonItem = () => /* @__PURE__ */ import_react31.default.createElement(SkeletonItem_default, null);
3373
+ return /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, !addIntegrationMode ? /* @__PURE__ */ import_react31.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "full" }, /* @__PURE__ */ import_react31.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react31.default.createElement(import_react_native16.View, { style: styles15.headerContent }, addIntegrationMode && /* @__PURE__ */ import_react31.default.createElement(
3374
+ import_react_native16.TouchableOpacity,
3062
3375
  {
3063
3376
  onPress: () => setAddIntegrationMode(null),
3064
- style: styles12.backButton
3377
+ style: styles15.backButton
3065
3378
  },
3066
- /* @__PURE__ */ import_react27.default.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
3067
- ), /* @__PURE__ */ import_react27.default.createElement(import_react_native13.Text, { style: [styles12.headerTitle, { color: theme.colors.text }] }, "Integration"))), /* @__PURE__ */ import_react27.default.createElement(ModalBody, { scrollable: false, style: styles12.noPadding }, /* @__PURE__ */ import_react27.default.createElement(import_react_native13.View, { style: styles12.container }, /* @__PURE__ */ import_react27.default.createElement(import_react_native13.View, { style: styles12.headerSection }, /* @__PURE__ */ import_react27.default.createElement(ConnectLogo, null), /* @__PURE__ */ import_react27.default.createElement(import_react_native13.Text, { style: [styles12.title, { color: theme.colors.text }] }, "Connect ", appName, " to your Kryptos account")), /* @__PURE__ */ import_react27.default.createElement(
3068
- import_react_native13.FlatList,
3379
+ /* @__PURE__ */ import_react31.default.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
3380
+ ), /* @__PURE__ */ import_react31.default.createElement(import_react_native16.Text, { style: [styles15.headerTitle, { color: theme.colors.text }] }, "Integration"))), /* @__PURE__ */ import_react31.default.createElement(ModalBody, { scrollable: false, style: styles15.noPadding }, /* @__PURE__ */ import_react31.default.createElement(import_react_native16.View, { style: styles15.container }, /* @__PURE__ */ import_react31.default.createElement(import_react_native16.View, { style: styles15.headerSection }, /* @__PURE__ */ import_react31.default.createElement(ConnectLogo, null), /* @__PURE__ */ import_react31.default.createElement(import_react_native16.Text, { style: [styles15.title, { color: theme.colors.text }] }, "Select an account to link to ", appName)), /* @__PURE__ */ import_react31.default.createElement(
3381
+ import_react_native16.FlatList,
3069
3382
  {
3070
3383
  data: isLoading ? Array.from({ length: 8 }, (_, i) => ({
3071
3384
  id: `skeleton-${i}`,
@@ -3075,14 +3388,14 @@ var Integration = ({
3075
3388
  })) : filteredResults,
3076
3389
  keyExtractor: (item, index) => isLoading ? item.id : `provider-${item.id}-${index}`,
3077
3390
  renderItem: isLoading ? renderSkeletonItem : renderProviderItem,
3078
- style: styles12.list,
3391
+ style: styles15.list,
3079
3392
  contentContainerStyle: [
3080
- styles12.listContent,
3393
+ styles15.listContent,
3081
3394
  { paddingHorizontal: theme.spacing.xl }
3082
3395
  ],
3083
3396
  showsVerticalScrollIndicator: false,
3084
- ListHeaderComponent: /* @__PURE__ */ import_react27.default.createElement(
3085
- import_react_native13.View,
3397
+ ListHeaderComponent: /* @__PURE__ */ import_react31.default.createElement(
3398
+ import_react_native16.View,
3086
3399
  {
3087
3400
  style: {
3088
3401
  paddingVertical: theme.spacing.sm + 2,
@@ -3090,29 +3403,63 @@ var Integration = ({
3090
3403
  zIndex: 10
3091
3404
  }
3092
3405
  },
3093
- /* @__PURE__ */ import_react27.default.createElement(
3406
+ /* @__PURE__ */ import_react31.default.createElement(
3094
3407
  Input,
3095
3408
  {
3096
3409
  value: query,
3097
3410
  onChangeText: setQuery,
3098
3411
  placeholder: "Search Integrations...",
3099
- containerStyle: styles12.searchInput
3412
+ containerStyle: styles15.searchInput
3100
3413
  }
3101
- )
3414
+ ),
3415
+ /* @__PURE__ */ import_react31.default.createElement(import_react_native16.View, { style: styles15.tabsContainer }, [
3416
+ { label: "All", value: "all" },
3417
+ { label: "Exchanges", value: "exchange" },
3418
+ { label: "Blockchains", value: "blockchain" },
3419
+ { label: "Wallets", value: "wallet" }
3420
+ ].map((tab) => /* @__PURE__ */ import_react31.default.createElement(
3421
+ import_react_native16.TouchableOpacity,
3422
+ {
3423
+ key: tab.value,
3424
+ style: [
3425
+ styles15.tab,
3426
+ {
3427
+ backgroundColor: activeTab === tab.value ? theme.colors.primary : theme.colors.surface,
3428
+ borderColor: theme.colors.border
3429
+ }
3430
+ ],
3431
+ onPress: () => setActiveTab(
3432
+ tab.value
3433
+ ),
3434
+ activeOpacity: 0.7
3435
+ },
3436
+ /* @__PURE__ */ import_react31.default.createElement(
3437
+ import_react_native16.Text,
3438
+ {
3439
+ style: [
3440
+ styles15.tabText,
3441
+ {
3442
+ color: activeTab === tab.value ? theme.colors.white : theme.colors.text
3443
+ }
3444
+ ]
3445
+ },
3446
+ tab.label
3447
+ )
3448
+ )))
3102
3449
  ),
3103
3450
  stickyHeaderIndices: [0],
3104
- ListEmptyComponent: /* @__PURE__ */ import_react27.default.createElement(import_react_native13.View, { style: styles12.emptyContainer }, !isLoading && /* @__PURE__ */ import_react27.default.createElement(
3105
- import_react_native13.Text,
3451
+ ListEmptyComponent: /* @__PURE__ */ import_react31.default.createElement(import_react_native16.View, { style: styles15.emptyContainer }, !isLoading && /* @__PURE__ */ import_react31.default.createElement(
3452
+ import_react_native16.Text,
3106
3453
  {
3107
3454
  style: [
3108
- styles12.emptyText,
3455
+ styles15.emptyText,
3109
3456
  { color: theme.colors.textSecondary }
3110
3457
  ]
3111
3458
  },
3112
3459
  query ? "No search results found" : "No supported integrations found"
3113
3460
  ))
3114
3461
  }
3115
- ), errorMessage && /* @__PURE__ */ import_react27.default.createElement(import_react_native13.View, { style: styles12.errorContainer }, /* @__PURE__ */ import_react27.default.createElement(Alert, { variant: "destructive", style: styles12.errorAlert }, /* @__PURE__ */ import_react27.default.createElement(AlertDescription, null, errorMessage))))), /* @__PURE__ */ import_react27.default.createElement(ModalFooter, null, /* @__PURE__ */ import_react27.default.createElement(
3462
+ ), errorMessage && /* @__PURE__ */ import_react31.default.createElement(import_react_native16.View, { style: styles15.errorContainer }, /* @__PURE__ */ import_react31.default.createElement(Alert, { variant: "destructive", style: styles15.errorAlert }, /* @__PURE__ */ import_react31.default.createElement(AlertDescription, null, errorMessage))))), /* @__PURE__ */ import_react31.default.createElement(ModalFooter, { style: { paddingVertical: 8 } }, /* @__PURE__ */ import_react31.default.createElement(
3116
3463
  Button,
3117
3464
  {
3118
3465
  variant: "outline",
@@ -3120,10 +3467,10 @@ var Integration = ({
3120
3467
  onPress: handleAddIntegration,
3121
3468
  loading: isLoading,
3122
3469
  disabled: isLoading,
3123
- style: styles12.continueButton
3470
+ style: styles15.continueButton
3124
3471
  },
3125
3472
  "Continue"
3126
- ))) : /* @__PURE__ */ import_react27.default.createElement(
3473
+ ), /* @__PURE__ */ import_react31.default.createElement(Footer, null))) : /* @__PURE__ */ import_react31.default.createElement(
3127
3474
  IntegrationForm,
3128
3475
  {
3129
3476
  metadata: addIntegrationMode,
@@ -3133,11 +3480,12 @@ var Integration = ({
3133
3480
  },
3134
3481
  open: !!addIntegrationMode,
3135
3482
  setAddIntegrationMode,
3136
- handleClose
3483
+ handleClose,
3484
+ providersList: supportedProviders
3137
3485
  }
3138
3486
  ));
3139
3487
  };
3140
- var styles12 = import_react_native13.StyleSheet.create({
3488
+ var styles15 = import_react_native16.StyleSheet.create({
3141
3489
  headerContent: {
3142
3490
  flexDirection: "row",
3143
3491
  alignItems: "center"
@@ -3252,25 +3600,47 @@ var styles12 = import_react_native13.StyleSheet.create({
3252
3600
  errorAlert: {
3253
3601
  marginTop: 16
3254
3602
  // theme.spacing.lg - consistent alert spacing
3603
+ },
3604
+ tabsContainer: {
3605
+ flexDirection: "row",
3606
+ gap: 4,
3607
+ // theme.spacing.sm
3608
+ flexWrap: "wrap"
3609
+ },
3610
+ tab: {
3611
+ paddingVertical: 8,
3612
+ // theme.spacing.sm
3613
+ paddingHorizontal: 16,
3614
+ // theme.spacing.lg
3615
+ borderRadius: 20,
3616
+ // theme.borderRadius.full / 2
3617
+ borderWidth: 1,
3618
+ alignItems: "center",
3619
+ justifyContent: "center"
3620
+ },
3621
+ tabText: {
3622
+ fontSize: 13,
3623
+ // theme.fontSize.sm
3624
+ fontWeight: "600"
3255
3625
  }
3256
3626
  });
3257
3627
 
3258
3628
  // src/molecules/OTPVerify.tsx
3259
- var import_react28 = __toESM(require("react"));
3260
- var import_react_native14 = require("react-native");
3629
+ var import_react32 = __toESM(require("react"));
3630
+ var import_react_native17 = require("react-native");
3261
3631
  var OTPVerify = ({
3262
3632
  open,
3263
3633
  onSuccess,
3264
3634
  onClose
3265
3635
  }) => {
3266
3636
  const theme = useTheme();
3267
- const [otp, setOtp] = import_react28.default.useState("");
3637
+ const [otp, setOtp] = import_react32.default.useState("");
3268
3638
  const { linkToken, clientId, email, setUser } = useKryptosConnect();
3269
- const [isLoading, setIsLoading] = import_react28.default.useState(false);
3270
- const [isResending, setIsResending] = import_react28.default.useState(false);
3271
- const [resendCooldown, setResendCooldown] = import_react28.default.useState(0);
3272
- const [errorMessage, setErrorMessage] = import_react28.default.useState("");
3273
- const [successMessage, setSuccessMessage] = import_react28.default.useState("");
3639
+ const [isLoading, setIsLoading] = import_react32.default.useState(false);
3640
+ const [isResending, setIsResending] = import_react32.default.useState(false);
3641
+ const [resendCooldown, setResendCooldown] = import_react32.default.useState(0);
3642
+ const [errorMessage, setErrorMessage] = import_react32.default.useState("");
3643
+ const [successMessage, setSuccessMessage] = import_react32.default.useState("");
3274
3644
  const handleSubmit = async () => {
3275
3645
  if (otp.length !== 6) return;
3276
3646
  setIsLoading(true);
@@ -3321,7 +3691,7 @@ var OTPVerify = ({
3321
3691
  setSuccessMessage("");
3322
3692
  setOtp("");
3323
3693
  };
3324
- import_react28.default.useEffect(() => {
3694
+ import_react32.default.useEffect(() => {
3325
3695
  if (resendCooldown > 0) {
3326
3696
  const timer = setTimeout(() => {
3327
3697
  setResendCooldown(resendCooldown - 1);
@@ -3330,13 +3700,20 @@ var OTPVerify = ({
3330
3700
  }
3331
3701
  return void 0;
3332
3702
  }, [resendCooldown]);
3333
- return /* @__PURE__ */ import_react28.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "lg" }, /* @__PURE__ */ import_react28.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react28.default.createElement(import_react_native14.View, { style: styles13.headerContent }, /* @__PURE__ */ import_react28.default.createElement(import_react_native14.Text, { style: [styles13.headerTitle, { color: theme.colors.text }] }, "OTP Verification"))), /* @__PURE__ */ import_react28.default.createElement(ModalBody, null, /* @__PURE__ */ import_react28.default.createElement(import_react_native14.View, { style: styles13.container }, /* @__PURE__ */ import_react28.default.createElement(ConnectLogo, null), /* @__PURE__ */ import_react28.default.createElement(import_react_native14.View, { style: styles13.emailInfo }, /* @__PURE__ */ import_react28.default.createElement(
3334
- import_react_native14.Text,
3703
+ return /* @__PURE__ */ import_react32.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "lg" }, /* @__PURE__ */ import_react32.default.createElement(ModalHeader, { onClose: handleClose }, /* @__PURE__ */ import_react32.default.createElement(import_react_native17.View, { style: styles16.headerContent }, /* @__PURE__ */ import_react32.default.createElement(import_react_native17.Text, { style: [styles16.headerTitle, { color: theme.colors.text }] }, "OTP Verification"))), /* @__PURE__ */ import_react32.default.createElement(ModalBody, null, /* @__PURE__ */ import_react32.default.createElement(import_react_native17.View, { style: styles16.container }, /* @__PURE__ */ import_react32.default.createElement(ConnectLogo, null), /* @__PURE__ */ import_react32.default.createElement(import_react_native17.View, { style: styles16.emailInfo }, /* @__PURE__ */ import_react32.default.createElement(
3704
+ import_react_native17.Text,
3335
3705
  {
3336
- style: [styles13.infoText, { color: theme.colors.textSecondary }]
3706
+ style: [styles16.infoText, { color: theme.colors.textSecondary }]
3337
3707
  },
3338
3708
  "We have sent a verification code to"
3339
- ), /* @__PURE__ */ import_react28.default.createElement(import_react_native14.Text, { style: [styles13.emailText, { color: theme.colors.text }] }, email)), /* @__PURE__ */ import_react28.default.createElement(OTP, { onComplete: handleOtpComplete, length: 6, setErrorMessage }), errorMessage ? /* @__PURE__ */ import_react28.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react28.default.createElement(AlertDescription, null, errorMessage)) : null, successMessage ? /* @__PURE__ */ import_react28.default.createElement(Alert, { variant: "default" }, /* @__PURE__ */ import_react28.default.createElement(AlertDescription, null, successMessage)) : null, /* @__PURE__ */ import_react28.default.createElement(
3709
+ ), /* @__PURE__ */ import_react32.default.createElement(import_react_native17.Text, { style: [styles16.emailText, { color: theme.colors.text }] }, email)), /* @__PURE__ */ import_react32.default.createElement(
3710
+ OTP,
3711
+ {
3712
+ onComplete: handleOtpComplete,
3713
+ length: 6,
3714
+ setErrorMessage
3715
+ }
3716
+ ), errorMessage ? /* @__PURE__ */ import_react32.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react32.default.createElement(AlertDescription, null, errorMessage)) : null, successMessage ? /* @__PURE__ */ import_react32.default.createElement(Alert, { variant: "default" }, /* @__PURE__ */ import_react32.default.createElement(AlertDescription, null, successMessage)) : null, /* @__PURE__ */ import_react32.default.createElement(
3340
3717
  Button,
3341
3718
  {
3342
3719
  variant: "outline",
@@ -3344,44 +3721,44 @@ var OTPVerify = ({
3344
3721
  onPress: handleSubmit,
3345
3722
  loading: isLoading,
3346
3723
  disabled: otp.length !== 6 || isLoading,
3347
- style: styles13.button
3724
+ style: styles16.button
3348
3725
  },
3349
3726
  "Continue"
3350
- ), /* @__PURE__ */ import_react28.default.createElement(
3351
- import_react_native14.TouchableOpacity,
3727
+ ), /* @__PURE__ */ import_react32.default.createElement(
3728
+ import_react_native17.TouchableOpacity,
3352
3729
  {
3353
3730
  onPress: handleResendOtp,
3354
3731
  disabled: resendCooldown > 0 || isResending,
3355
- style: styles13.resendContainer
3732
+ style: styles16.resendContainer
3356
3733
  },
3357
- isResending ? /* @__PURE__ */ import_react28.default.createElement(import_react_native14.View, { style: styles13.resendLoading }, /* @__PURE__ */ import_react28.default.createElement(LoaderIcon, { size: 16, color: theme.colors.primary }), /* @__PURE__ */ import_react28.default.createElement(
3358
- import_react_native14.Text,
3734
+ isResending ? /* @__PURE__ */ import_react32.default.createElement(import_react_native17.View, { style: styles16.resendLoading }, /* @__PURE__ */ import_react32.default.createElement(LoaderIcon, { size: 16, color: theme.colors.primary }), /* @__PURE__ */ import_react32.default.createElement(
3735
+ import_react_native17.Text,
3359
3736
  {
3360
- style: [styles13.resendText, { color: theme.colors.primary }]
3737
+ style: [styles16.resendText, { color: theme.colors.primary }]
3361
3738
  },
3362
3739
  " ",
3363
3740
  "Sending..."
3364
- )) : resendCooldown > 0 ? /* @__PURE__ */ import_react28.default.createElement(
3365
- import_react_native14.Text,
3741
+ )) : resendCooldown > 0 ? /* @__PURE__ */ import_react32.default.createElement(
3742
+ import_react_native17.Text,
3366
3743
  {
3367
3744
  style: [
3368
- styles13.resendText,
3745
+ styles16.resendText,
3369
3746
  { color: theme.colors.textSecondary }
3370
3747
  ]
3371
3748
  },
3372
3749
  "Resend OTP in ",
3373
3750
  resendCooldown,
3374
3751
  "s"
3375
- ) : /* @__PURE__ */ import_react28.default.createElement(
3376
- import_react_native14.Text,
3752
+ ) : /* @__PURE__ */ import_react32.default.createElement(
3753
+ import_react_native17.Text,
3377
3754
  {
3378
- style: [styles13.resendText, { color: theme.colors.primary }]
3755
+ style: [styles16.resendText, { color: theme.colors.primary }]
3379
3756
  },
3380
3757
  "Resend OTP"
3381
3758
  )
3382
- ))));
3759
+ ))), /* @__PURE__ */ import_react32.default.createElement(ModalFooter, { style: { paddingVertical: 0 } }, /* @__PURE__ */ import_react32.default.createElement(Footer, null)));
3383
3760
  };
3384
- var styles13 = import_react_native14.StyleSheet.create({
3761
+ var styles16 = import_react_native17.StyleSheet.create({
3385
3762
  headerContent: {
3386
3763
  flexDirection: "row",
3387
3764
  alignItems: "center"
@@ -3440,8 +3817,8 @@ var styles13 = import_react_native14.StyleSheet.create({
3440
3817
  });
3441
3818
 
3442
3819
  // src/molecules/Permissions.tsx
3443
- var import_react29 = __toESM(require("react"));
3444
- var import_react_native15 = require("react-native");
3820
+ var import_react33 = __toESM(require("react"));
3821
+ var import_react_native18 = require("react-native");
3445
3822
  var Permissions = ({
3446
3823
  open,
3447
3824
  onClose,
@@ -3449,8 +3826,8 @@ var Permissions = ({
3449
3826
  }) => {
3450
3827
  const { appName, linkToken, setUserConsent } = useKryptosConnect();
3451
3828
  const theme = useTheme();
3452
- const [isLoading, setIsLoading] = import_react29.default.useState(false);
3453
- const [errorMessage, setErrorMessage] = import_react29.default.useState("");
3829
+ const [isLoading, setIsLoading] = import_react33.default.useState(false);
3830
+ const [errorMessage, setErrorMessage] = import_react33.default.useState("");
3454
3831
  const handleConsentClick = async () => {
3455
3832
  try {
3456
3833
  setIsLoading(true);
@@ -3473,42 +3850,42 @@ var Permissions = ({
3473
3850
  "Access your transaction history and trading activity",
3474
3851
  "Keep this data updated and accessible when you're offline"
3475
3852
  ];
3476
- return /* @__PURE__ */ import_react29.default.createElement(Modal, { isOpen: open, onClose, size: "xl" }, /* @__PURE__ */ import_react29.default.createElement(ModalHeader, { onClose }, "Permissions"), /* @__PURE__ */ import_react29.default.createElement(ModalBody, null, /* @__PURE__ */ import_react29.default.createElement(import_react_native15.View, { style: styles14.container }, /* @__PURE__ */ import_react29.default.createElement(ConnectLogo, null), errorMessage ? /* @__PURE__ */ import_react29.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react29.default.createElement(AlertDescription, null, errorMessage)) : null, /* @__PURE__ */ import_react29.default.createElement(import_react_native15.View, { style: styles14.permissionsList }, /* @__PURE__ */ import_react29.default.createElement(
3477
- import_react_native15.Text,
3853
+ return /* @__PURE__ */ import_react33.default.createElement(Modal, { isOpen: open, onClose, size: "xl" }, /* @__PURE__ */ import_react33.default.createElement(ModalHeader, { onClose }, "Permissions"), /* @__PURE__ */ import_react33.default.createElement(ModalBody, null, /* @__PURE__ */ import_react33.default.createElement(import_react_native18.View, { style: styles17.container }, /* @__PURE__ */ import_react33.default.createElement(ConnectLogo, null), errorMessage ? /* @__PURE__ */ import_react33.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ import_react33.default.createElement(AlertDescription, null, errorMessage)) : null, /* @__PURE__ */ import_react33.default.createElement(import_react_native18.View, { style: styles17.permissionsList }, /* @__PURE__ */ import_react33.default.createElement(
3854
+ import_react_native18.Text,
3478
3855
  {
3479
- style: [styles14.subtitle, { color: theme.colors.textSecondary }]
3856
+ style: [styles17.subtitle, { color: theme.colors.textSecondary }]
3480
3857
  },
3481
3858
  "Allow ",
3482
3859
  appName,
3483
3860
  " to:"
3484
- ), permissionItems.map((item, index) => /* @__PURE__ */ import_react29.default.createElement(import_react_native15.View, { key: `permission-${index}`, style: styles14.permissionItem }, /* @__PURE__ */ import_react29.default.createElement(import_react_native15.Text, { style: [styles14.bullet, { color: theme.colors.primary }] }, index + 1, "."), /* @__PURE__ */ import_react29.default.createElement(
3485
- import_react_native15.Text,
3861
+ ), permissionItems.map((item, index) => /* @__PURE__ */ import_react33.default.createElement(import_react_native18.View, { key: `permission-${index}`, style: styles17.permissionItem }, /* @__PURE__ */ import_react33.default.createElement(import_react_native18.Text, { style: [styles17.bullet, { color: theme.colors.primary }] }, index + 1, "."), /* @__PURE__ */ import_react33.default.createElement(
3862
+ import_react_native18.Text,
3486
3863
  {
3487
- style: [styles14.permissionText, { color: theme.colors.text }]
3864
+ style: [styles17.permissionText, { color: theme.colors.text }]
3488
3865
  },
3489
3866
  item
3490
- )))), /* @__PURE__ */ import_react29.default.createElement(
3491
- import_react_native15.View,
3867
+ )))), /* @__PURE__ */ import_react33.default.createElement(
3868
+ import_react_native18.View,
3492
3869
  {
3493
3870
  style: [
3494
- styles14.infoBox,
3871
+ styles17.infoBox,
3495
3872
  {
3496
3873
  backgroundColor: theme.colors.surface,
3497
3874
  borderColor: theme.colors.border
3498
3875
  }
3499
3876
  ]
3500
3877
  },
3501
- /* @__PURE__ */ import_react29.default.createElement(
3502
- import_react_native15.Text,
3878
+ /* @__PURE__ */ import_react33.default.createElement(
3879
+ import_react_native18.Text,
3503
3880
  {
3504
- style: [styles14.infoText, { color: theme.colors.textSecondary }]
3881
+ style: [styles17.infoText, { color: theme.colors.textSecondary }]
3505
3882
  },
3506
3883
  "By selecting",
3507
3884
  " ",
3508
- /* @__PURE__ */ import_react29.default.createElement(import_react_native15.Text, { style: { fontWeight: "600", color: theme.colors.text } }, "'Allow'"),
3885
+ /* @__PURE__ */ import_react33.default.createElement(import_react_native18.Text, { style: { fontWeight: "600", color: theme.colors.text } }, "'Allow'"),
3509
3886
  ", you agree to share this information and keep it updated."
3510
3887
  )
3511
- ))), /* @__PURE__ */ import_react29.default.createElement(ModalFooter, null, /* @__PURE__ */ import_react29.default.createElement(
3888
+ ))), /* @__PURE__ */ import_react33.default.createElement(ModalFooter, { style: { paddingVertical: 8 } }, /* @__PURE__ */ import_react33.default.createElement(
3512
3889
  Button,
3513
3890
  {
3514
3891
  variant: "outline",
@@ -3516,12 +3893,12 @@ var Permissions = ({
3516
3893
  onPress: handleConsentClick,
3517
3894
  loading: isLoading,
3518
3895
  disabled: isLoading,
3519
- style: styles14.button
3896
+ style: styles17.button
3520
3897
  },
3521
3898
  "Allow"
3522
- )));
3899
+ ), /* @__PURE__ */ import_react33.default.createElement(Footer, null)));
3523
3900
  };
3524
- var styles14 = import_react_native15.StyleSheet.create({
3901
+ var styles17 = import_react_native18.StyleSheet.create({
3525
3902
  container: {
3526
3903
  flex: 1
3527
3904
  },
@@ -3579,8 +3956,8 @@ var styles14 = import_react_native15.StyleSheet.create({
3579
3956
  });
3580
3957
 
3581
3958
  // src/molecules/StatusModal.tsx
3582
- var import_react30 = __toESM(require("react"));
3583
- var import_react_native16 = require("react-native");
3959
+ var import_react34 = __toESM(require("react"));
3960
+ var import_react_native19 = require("react-native");
3584
3961
  var StatusModal = ({
3585
3962
  open,
3586
3963
  onClose,
@@ -3597,18 +3974,18 @@ var StatusModal = ({
3597
3974
  }
3598
3975
  onClose();
3599
3976
  };
3600
- return /* @__PURE__ */ import_react30.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "xs" }, /* @__PURE__ */ import_react30.default.createElement(ModalBody, null, /* @__PURE__ */ import_react30.default.createElement(import_react_native16.View, { style: styles15.container }, /* @__PURE__ */ import_react30.default.createElement(import_react_native16.View, { style: styles15.iconContainer }, status === "success" ? /* @__PURE__ */ import_react30.default.createElement(SuccessIcon, { size: 80 }) : /* @__PURE__ */ import_react30.default.createElement(ErrorIcon, { size: 80 })), /* @__PURE__ */ import_react30.default.createElement(import_react_native16.Text, { style: [styles15.message, { color: theme.colors.text }] }, status === "success" ? "Connection successful" : "Connection failed"), /* @__PURE__ */ import_react30.default.createElement(
3977
+ return /* @__PURE__ */ import_react34.default.createElement(Modal, { isOpen: open, onClose: handleClose, size: "sm" }, /* @__PURE__ */ import_react34.default.createElement(ModalHeader, { showCloseButton: false, onClose: handleClose }, ""), /* @__PURE__ */ import_react34.default.createElement(ModalBody, null, /* @__PURE__ */ import_react34.default.createElement(import_react_native19.View, { style: styles18.container }, /* @__PURE__ */ import_react34.default.createElement(import_react_native19.View, { style: styles18.iconContainer }, status === "success" ? /* @__PURE__ */ import_react34.default.createElement(SuccessIcon, { size: 80 }) : /* @__PURE__ */ import_react34.default.createElement(ErrorIcon, { size: 80 })), /* @__PURE__ */ import_react34.default.createElement(import_react_native19.Text, { style: [styles18.message, { color: theme.colors.text }] }, status === "success" ? "Connection successful" : "Connection failed"))), /* @__PURE__ */ import_react34.default.createElement(ModalFooter, { style: { paddingVertical: 8 } }, /* @__PURE__ */ import_react34.default.createElement(
3601
3978
  Button,
3602
3979
  {
3603
3980
  variant: "outline",
3604
3981
  size: "lg",
3605
3982
  onPress: status === "success" ? onSuccess : onError,
3606
- style: styles15.button
3983
+ style: styles18.button
3607
3984
  },
3608
3985
  status === "success" ? "Continue" : "Try again later"
3609
- ))));
3986
+ ), /* @__PURE__ */ import_react34.default.createElement(Footer, null)));
3610
3987
  };
3611
- var styles15 = import_react_native16.StyleSheet.create({
3988
+ var styles18 = import_react_native19.StyleSheet.create({
3612
3989
  container: {
3613
3990
  flex: 1,
3614
3991
  alignItems: "center",
@@ -3632,6 +4009,64 @@ var styles15 = import_react_native16.StyleSheet.create({
3632
4009
  }
3633
4010
  });
3634
4011
 
4012
+ // src/molecules/EndModal.tsx
4013
+ var import_react35 = __toESM(require("react"));
4014
+ var import_react_native20 = require("react-native");
4015
+ var EndModal = ({ open, onClose }) => {
4016
+ const theme = useTheme();
4017
+ (0, import_react35.useEffect)(() => {
4018
+ if (!open) return;
4019
+ const timer = setTimeout(() => {
4020
+ onClose();
4021
+ }, 5e3);
4022
+ return () => clearTimeout(timer);
4023
+ }, []);
4024
+ return /* @__PURE__ */ import_react35.default.createElement(Modal, { isOpen: open, onClose, size: "md" }, /* @__PURE__ */ import_react35.default.createElement(ModalHeader, { onClose }, ""), /* @__PURE__ */ import_react35.default.createElement(ModalBody, null, /* @__PURE__ */ import_react35.default.createElement(import_react_native20.View, { style: styles19.container }, /* @__PURE__ */ import_react35.default.createElement(
4025
+ import_react_native20.View,
4026
+ {
4027
+ style: [
4028
+ styles19.iconContainer,
4029
+ { backgroundColor: theme.colors.successLight }
4030
+ ]
4031
+ },
4032
+ /* @__PURE__ */ import_react35.default.createElement(SuccessIcon, { size: 80 })
4033
+ ), /* @__PURE__ */ import_react35.default.createElement(import_react_native20.Text, { style: [styles19.message, { color: theme.colors.text }] }, `All set! We're redirecting you back to the app. If it takes longer
4034
+ than expected, tap the button below to continue.`))), /* @__PURE__ */ import_react35.default.createElement(ModalFooter, { style: { paddingVertical: 8 } }, /* @__PURE__ */ import_react35.default.createElement(
4035
+ Button,
4036
+ {
4037
+ variant: "primary",
4038
+ size: "lg",
4039
+ onPress: onClose,
4040
+ style: styles19.button
4041
+ },
4042
+ "Continue to App"
4043
+ ), /* @__PURE__ */ import_react35.default.createElement(Footer, null)));
4044
+ };
4045
+ var styles19 = import_react_native20.StyleSheet.create({
4046
+ container: {
4047
+ alignItems: "center",
4048
+ paddingVertical: 20
4049
+ },
4050
+ iconContainer: {
4051
+ width: 80,
4052
+ height: 80,
4053
+ borderRadius: 40,
4054
+ alignItems: "center",
4055
+ justifyContent: "center",
4056
+ marginBottom: 20
4057
+ },
4058
+ message: {
4059
+ fontSize: 14,
4060
+ textAlign: "center",
4061
+ lineHeight: 20,
4062
+ marginBottom: 24,
4063
+ paddingHorizontal: 20
4064
+ },
4065
+ button: {
4066
+ width: "100%"
4067
+ }
4068
+ });
4069
+
3635
4070
  // src/KryptosConnectButton.tsx
3636
4071
  var KryptosConnectButton = ({
3637
4072
  children,
@@ -3642,14 +4077,14 @@ var KryptosConnectButton = ({
3642
4077
  textStyle
3643
4078
  }) => {
3644
4079
  const { theme: themeName } = useKryptosConnect();
3645
- const [open, setOpen] = import_react31.default.useState(false);
4080
+ const [open, setOpen] = import_react36.default.useState(false);
3646
4081
  const theme = useTheme();
3647
- return /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, children ? /* @__PURE__ */ import_react31.default.createElement(import_react_native17.TouchableOpacity, { onPress: () => setOpen(true), style }, children) : /* @__PURE__ */ import_react31.default.createElement(
3648
- import_react_native17.TouchableOpacity,
4082
+ return /* @__PURE__ */ import_react36.default.createElement(import_react36.default.Fragment, null, children ? /* @__PURE__ */ import_react36.default.createElement(import_react_native21.TouchableOpacity, { onPress: () => setOpen(true), style }, children) : /* @__PURE__ */ import_react36.default.createElement(
4083
+ import_react_native21.TouchableOpacity,
3649
4084
  {
3650
4085
  onPress: () => setOpen(true),
3651
4086
  style: [
3652
- styles16.defaultButton,
4087
+ styles20.defaultButton,
3653
4088
  themeName === "light" ? {
3654
4089
  backgroundColor: theme.colors.white,
3655
4090
  borderRadius: theme.borderRadius.md,
@@ -3663,11 +4098,11 @@ var KryptosConnectButton = ({
3663
4098
  ],
3664
4099
  activeOpacity: 0.8
3665
4100
  },
3666
- /* @__PURE__ */ import_react31.default.createElement(
3667
- import_react_native17.Text,
4101
+ /* @__PURE__ */ import_react36.default.createElement(
4102
+ import_react_native21.Text,
3668
4103
  {
3669
4104
  style: [
3670
- styles16.buttonText,
4105
+ styles20.buttonText,
3671
4106
  {
3672
4107
  color: themeName === "light" ? theme.colors.primary : theme.colors.white,
3673
4108
  fontSize: theme.fontSize.lg
@@ -3678,8 +4113,8 @@ var KryptosConnectButton = ({
3678
4113
  "Connect with",
3679
4114
  " "
3680
4115
  ),
3681
- /* @__PURE__ */ import_react31.default.createElement(LogoIcon, { size: 24 })
3682
- ), /* @__PURE__ */ import_react31.default.createElement(
4116
+ /* @__PURE__ */ import_react36.default.createElement(LogoIcon, { size: 24 })
4117
+ ), /* @__PURE__ */ import_react36.default.createElement(
3683
4118
  KryptosConnectModal,
3684
4119
  {
3685
4120
  open,
@@ -3703,9 +4138,11 @@ var KryptosConnectModal = ({
3703
4138
  setUserConsent,
3704
4139
  setUser,
3705
4140
  setEmail,
3706
- setLinkToken
4141
+ setLinkToken,
4142
+ isAuthorized,
4143
+ linkToken
3707
4144
  } = useKryptosConnect();
3708
- const [step, setStep] = import_react31.default.useState("INIT" /* INIT */);
4145
+ const [step, setStep] = import_react36.default.useState("INIT" /* INIT */);
3709
4146
  const handleClose = () => {
3710
4147
  setOpen(false);
3711
4148
  setIsInitialized(false);
@@ -3723,12 +4160,25 @@ var KryptosConnectModal = ({
3723
4160
  onError?.(userConsent);
3724
4161
  handleClose();
3725
4162
  };
4163
+ const handleConsentClick = async () => {
4164
+ try {
4165
+ if (isAuthorized) {
4166
+ setStep("END" /* END */);
4167
+ return;
4168
+ }
4169
+ const res = await giveUserConsent(linkToken);
4170
+ setUserConsent(res);
4171
+ setStep("STATUS" /* STATUS */);
4172
+ } catch (error) {
4173
+ console.error(error);
4174
+ }
4175
+ };
3726
4176
  const handleAbort = () => {
3727
4177
  onError?.(new Error("User closed the modal"));
3728
4178
  handleClose();
3729
4179
  };
3730
4180
  if (!open) return null;
3731
- return /* @__PURE__ */ import_react31.default.createElement(import_react_native17.View, { style: styles16.container }, step === "INIT" /* INIT */ && /* @__PURE__ */ import_react31.default.createElement(
4181
+ return /* @__PURE__ */ import_react36.default.createElement(import_react_native21.View, { style: styles20.container }, step === "INIT" /* INIT */ && /* @__PURE__ */ import_react36.default.createElement(
3732
4182
  Init,
3733
4183
  {
3734
4184
  open,
@@ -3742,7 +4192,7 @@ var KryptosConnectModal = ({
3742
4192
  },
3743
4193
  onClose: handleAbort
3744
4194
  }
3745
- ), step === "AUTH" /* AUTH */ && /* @__PURE__ */ import_react31.default.createElement(
4195
+ ), step === "AUTH" /* AUTH */ && /* @__PURE__ */ import_react36.default.createElement(
3746
4196
  Auth,
3747
4197
  {
3748
4198
  open,
@@ -3750,28 +4200,28 @@ var KryptosConnectModal = ({
3750
4200
  onGuestSuccess: () => setStep("INTEGRATION" /* INTEGRATION */),
3751
4201
  onClose: handleAbort
3752
4202
  }
3753
- ), step === "OTP" /* OTP */ && /* @__PURE__ */ import_react31.default.createElement(
4203
+ ), step === "OTP" /* OTP */ && /* @__PURE__ */ import_react36.default.createElement(
3754
4204
  OTPVerify,
3755
4205
  {
3756
4206
  open,
3757
4207
  onSuccess: () => setStep("INTEGRATION" /* INTEGRATION */),
3758
4208
  onClose: handleAbort
3759
4209
  }
3760
- ), step === "INTEGRATION" /* INTEGRATION */ && /* @__PURE__ */ import_react31.default.createElement(
4210
+ ), step === "INTEGRATION" /* INTEGRATION */ && /* @__PURE__ */ import_react36.default.createElement(
3761
4211
  Integration,
3762
4212
  {
3763
4213
  open,
3764
- onSuccess: () => setStep("PERMISSIONS" /* PERMISSIONS */),
4214
+ onSuccess: handleConsentClick,
3765
4215
  onClose: handleAbort
3766
4216
  }
3767
- ), step === "PERMISSIONS" /* PERMISSIONS */ && /* @__PURE__ */ import_react31.default.createElement(
4217
+ ), step === "PERMISSIONS" /* PERMISSIONS */ && /* @__PURE__ */ import_react36.default.createElement(
3768
4218
  Permissions,
3769
4219
  {
3770
4220
  open,
3771
4221
  onClose: handleAbort,
3772
4222
  onSuccess: () => setStep("STATUS" /* STATUS */)
3773
4223
  }
3774
- ), step === "STATUS" /* STATUS */ && /* @__PURE__ */ import_react31.default.createElement(
4224
+ ), step === "STATUS" /* STATUS */ && /* @__PURE__ */ import_react36.default.createElement(
3775
4225
  StatusModal,
3776
4226
  {
3777
4227
  open,
@@ -3780,9 +4230,19 @@ var KryptosConnectModal = ({
3780
4230
  onError: handleError,
3781
4231
  status: userConsent?.public_token ? "success" : "error"
3782
4232
  }
4233
+ ), step === "END" /* END */ && /* @__PURE__ */ import_react36.default.createElement(
4234
+ EndModal,
4235
+ {
4236
+ open,
4237
+ onClose: () => {
4238
+ onSuccess?.(userConsent);
4239
+ setStep("INIT" /* INIT */);
4240
+ setOpen(false);
4241
+ }
4242
+ }
3783
4243
  ));
3784
4244
  };
3785
- var styles16 = import_react_native17.StyleSheet.create({
4245
+ var styles20 = import_react_native21.StyleSheet.create({
3786
4246
  defaultButton: {
3787
4247
  flexDirection: "row",
3788
4248
  alignItems: "center",