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