@kryptos_connect/mobile-sdk 1.0.0 → 1.0.2

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
  },
@@ -795,145 +1006,386 @@ var styles3 = StyleSheet3.create({
795
1006
  }
796
1007
  });
797
1008
 
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
- }
1009
+ // src/components/OTP.tsx
1010
+ import React9 from "react";
1011
+ import {
1012
+ View as View5,
1013
+ TextInput as TextInput2,
1014
+ Text as Text5,
1015
+ StyleSheet as StyleSheet5
1016
+ } from "react-native";
1017
+ var OTP = ({
1018
+ length = 6,
1019
+ value = "",
1020
+ onChange,
1021
+ onComplete,
1022
+ error,
1023
+ label,
1024
+ disabled = false,
1025
+ containerStyle,
1026
+ inputStyle,
1027
+ setErrorMessage
1028
+ }) => {
1029
+ const theme = useTheme();
1030
+ const AUTO_SUBMIT_DELAY = 500;
1031
+ const [otp, setOtp] = React9.useState(
1032
+ value.split("").concat(Array(length).fill("")).slice(0, length)
825
1033
  );
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
- }
1034
+ const inputRefs = React9.useRef([]);
1035
+ React9.useEffect(() => {
1036
+ const isComplete = otp.every((digit) => digit !== "");
1037
+ let timer;
1038
+ if (isComplete && onComplete) {
1039
+ timer = setTimeout(() => {
1040
+ onComplete(otp.join(""));
1041
+ }, AUTO_SUBMIT_DELAY);
841
1042
  }
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
1043
+ return () => {
1044
+ if (timer) clearTimeout(timer);
1045
+ };
1046
+ }, [otp, onComplete]);
1047
+ React9.useEffect(() => {
1048
+ setTimeout(() => {
1049
+ inputRefs.current[0]?.focus();
1050
+ }, 100);
1051
+ }, []);
1052
+ const handleChange = React9.useCallback(
1053
+ (index, val) => {
1054
+ if (disabled) return;
1055
+ setErrorMessage("");
1056
+ const numericValue = val.replace(/[^0-9]/g, "");
1057
+ const newValue = numericValue.slice(-1);
1058
+ if (val && !numericValue) {
1059
+ return;
852
1060
  }
853
- }
1061
+ const newOtp = [...otp];
1062
+ newOtp[index] = newValue;
1063
+ setOtp(newOtp);
1064
+ const otpString = newOtp.join("");
1065
+ onChange?.(otpString);
1066
+ if (newValue && index < length - 1) {
1067
+ inputRefs.current[index + 1]?.focus();
1068
+ }
1069
+ if (otpString.length === length && !otpString.includes("")) {
1070
+ onComplete?.(otpString);
1071
+ }
1072
+ },
1073
+ [otp, length, onChange, onComplete, disabled]
854
1074
  );
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
1075
+ const handleKeyPress = React9.useCallback(
1076
+ (index, e) => {
1077
+ if (disabled) return;
1078
+ if (e.nativeEvent.key === "Backspace") {
1079
+ if (!otp[index] && index > 0) {
1080
+ inputRefs.current[index - 1]?.focus();
1081
+ } else {
1082
+ const newOtp = [...otp];
1083
+ newOtp[index] = "";
1084
+ setOtp(newOtp);
1085
+ onChange?.(newOtp.join(""));
1086
+ }
864
1087
  }
865
- }
1088
+ },
1089
+ [otp, onChange, disabled]
866
1090
  );
867
- return res.data?.data;
868
- }
869
- async function giveUserConsent(linkToken) {
870
- const res = await api.post(
871
- "/consent",
1091
+ const getBorderColor = (index) => {
1092
+ if (error) return theme.colors.error;
1093
+ if (otp[index]) return theme.colors.success;
1094
+ return theme.colors.border;
1095
+ };
1096
+ return /* @__PURE__ */ React9.createElement(View5, { style: [styles5.wrapper, containerStyle] }, label && /* @__PURE__ */ React9.createElement(
1097
+ Text5,
872
1098
  {
873
- granted_scopes: SCOPES
1099
+ style: [
1100
+ styles5.label,
1101
+ { color: theme.colors.text, fontSize: theme.fontSize.sm }
1102
+ ]
874
1103
  },
1104
+ label
1105
+ ), /* @__PURE__ */ React9.createElement(View5, { style: styles5.container }, Array.from({ length }, (_, index) => /* @__PURE__ */ React9.createElement(
1106
+ TextInput2,
875
1107
  {
876
- headers: {
877
- "X-LINK-TOKEN": linkToken
878
- }
1108
+ key: index,
1109
+ ref: (el) => inputRefs.current[index] = el,
1110
+ style: [
1111
+ styles5.input,
1112
+ {
1113
+ backgroundColor: theme.colors.surface,
1114
+ borderColor: getBorderColor(index),
1115
+ color: theme.colors.text,
1116
+ fontSize: theme.fontSize.xxl,
1117
+ borderRadius: theme.borderRadius.md
1118
+ },
1119
+ inputStyle
1120
+ ],
1121
+ keyboardType: "numeric",
1122
+ maxLength: 1,
1123
+ value: otp[index] || "",
1124
+ onChangeText: (val) => handleChange(index, val),
1125
+ onKeyPress: (e) => handleKeyPress(index, e),
1126
+ editable: !disabled,
1127
+ selectTextOnFocus: true,
1128
+ caretHidden: true
879
1129
  }
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
1130
+ ))), error && /* @__PURE__ */ React9.createElement(
1131
+ Text5,
1132
+ {
1133
+ style: [
1134
+ styles5.error,
1135
+ { color: theme.colors.error, fontSize: theme.fontSize.sm }
1136
+ ]
1137
+ },
1138
+ error
1139
+ ));
1140
+ };
1141
+ var styles5 = StyleSheet5.create({
1142
+ wrapper: {
1143
+ marginBottom: 16
1144
+ // theme.spacing.lg
1145
+ },
1146
+ label: {
1147
+ fontWeight: "500",
1148
+ marginBottom: 12,
1149
+ // theme.spacing.md - consistent label spacing
1150
+ textAlign: "center"
1151
+ },
1152
+ container: {
1153
+ flexDirection: "row",
1154
+ justifyContent: "center",
1155
+ gap: 8
1156
+ // theme.spacing.sm
1157
+ },
1158
+ input: {
1159
+ width: 48,
1160
+ height: 56,
1161
+ borderWidth: 1,
1162
+ textAlign: "center",
1163
+ fontWeight: "600"
1164
+ },
1165
+ error: {
1166
+ marginTop: 12,
1167
+ // theme.spacing.md - consistent error spacing
1168
+ textAlign: "center"
1169
+ }
1170
+ });
1171
+
1172
+ // src/components/SkeletonItem.tsx
1173
+ import React10, { useEffect, useRef } from "react";
1174
+ import { Animated, View as View6, StyleSheet as StyleSheet6 } from "react-native";
1175
+ var SkeletonItem = () => {
1176
+ const opacity = useRef(new Animated.Value(0.3)).current;
1177
+ useEffect(() => {
1178
+ Animated.loop(
1179
+ Animated.sequence([
1180
+ Animated.timing(opacity, {
1181
+ toValue: 1,
1182
+ duration: 600,
1183
+ useNativeDriver: true
1184
+ }),
1185
+ Animated.timing(opacity, {
1186
+ toValue: 0.3,
1187
+ duration: 600,
1188
+ useNativeDriver: true
1189
+ })
1190
+ ])
1191
+ ).start();
1192
+ }, []);
1193
+ 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 })));
1194
+ };
1195
+ var styles6 = StyleSheet6.create({
1196
+ row: {
1197
+ flexDirection: "row",
1198
+ alignItems: "center",
1199
+ paddingVertical: 16
1200
+ },
1201
+ iconCircle: {
1202
+ width: 45,
1203
+ height: 45,
1204
+ borderRadius: 22.5,
1205
+ backgroundColor: "#E5E5E5"
1206
+ },
1207
+ textBlock: {
1208
+ marginLeft: 12,
1209
+ flex: 1
1210
+ },
1211
+ lineShort: {
1212
+ width: "50%",
1213
+ height: 14,
1214
+ borderRadius: 6,
1215
+ backgroundColor: "#E5E5E5"
1216
+ },
1217
+ lineLong: {
1218
+ marginBottom: 6,
1219
+ width: "100%",
1220
+ height: 14,
1221
+ borderRadius: 6,
1222
+ backgroundColor: "#E5E5E5"
1223
+ }
1224
+ });
1225
+ var SkeletonItem_default = SkeletonItem;
1226
+
1227
+ // src/components/Mode.tsx
1228
+ import React11 from "react";
1229
+ import { View as View7, Text as Text6, StyleSheet as StyleSheet7 } from "react-native";
1230
+ var Mode = () => {
1231
+ const { clientInfo } = useKryptosConnect();
1232
+ const theme = useTheme();
1233
+ if (!clientInfo) return null;
1234
+ if (clientInfo?.project_stage === "production") return null;
1235
+ 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"));
1236
+ };
1237
+ var styles7 = StyleSheet7.create({
1238
+ container: {
1239
+ paddingVertical: 4,
1240
+ paddingHorizontal: 8,
1241
+ borderRadius: 8,
1242
+ alignItems: "center",
1243
+ justifyContent: "center"
1244
+ },
1245
+ text: {
1246
+ fontSize: 12,
1247
+ fontWeight: "600"
1248
+ }
1249
+ });
1250
+
1251
+ // src/components/Footer.tsx
1252
+ import React13 from "react";
1253
+ import { View as View9, StyleSheet as StyleSheet9 } from "react-native";
1254
+
1255
+ // src/components/PoweredByKryptos.tsx
1256
+ import React12 from "react";
1257
+ import {
1258
+ Linking,
1259
+ StyleSheet as StyleSheet8,
1260
+ Text as Text7,
1261
+ TouchableOpacity as TouchableOpacity3,
1262
+ View as View8
1263
+ } from "react-native";
1264
+ var PoweredByKryptos = () => {
1265
+ const theme = useTheme();
1266
+ const handlePress = () => {
1267
+ Linking.openURL("https://kryptos.io");
1268
+ };
1269
+ 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 })));
1270
+ };
1271
+ var styles8 = StyleSheet8.create({
1272
+ container: {
1273
+ flexDirection: "row",
1274
+ alignItems: "center"
1275
+ },
1276
+ text: {
1277
+ fontSize: 12,
1278
+ fontWeight: "400"
1279
+ }
1280
+ });
1281
+
1282
+ // src/components/Footer.tsx
1283
+ var Footer = () => {
1284
+ return /* @__PURE__ */ React13.createElement(View9, { style: styles9.container }, /* @__PURE__ */ React13.createElement(PoweredByKryptos, null), /* @__PURE__ */ React13.createElement(View9, { style: styles9.modeWrapper }, /* @__PURE__ */ React13.createElement(Mode, null)));
1285
+ };
1286
+ var styles9 = StyleSheet9.create({
1287
+ container: {
1288
+ width: "100%",
1289
+ paddingVertical: 8,
1290
+ alignItems: "center",
1291
+ justifyContent: "center"
1292
+ },
1293
+ // Anchor Mode to the right side
1294
+ modeWrapper: {
1295
+ position: "absolute",
1296
+ right: 8,
1297
+ top: 4
1298
+ }
1299
+ });
1300
+
1301
+ // src/molecules/Auth.tsx
1302
+ import React19 from "react";
1303
+ import { Linking as Linking2, StyleSheet as StyleSheet11, Text as Text9, View as View11 } from "react-native";
1304
+
1305
+ // src/assets/LinkIcon.tsx
1306
+ import React14 from "react";
1307
+ import Svg3, { Path as Path3 } from "react-native-svg";
1308
+ var LinkIcon = ({
1309
+ size = 20,
1310
+ color = "#00C693"
1311
+ }) => {
1312
+ return /* @__PURE__ */ React14.createElement(Svg3, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React14.createElement(
1313
+ Path3,
1314
+ {
1315
+ d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",
1316
+ stroke: color,
1317
+ strokeWidth: 2,
1318
+ strokeLinecap: "round",
1319
+ strokeLinejoin: "round"
887
1320
  }
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
1321
+ ), /* @__PURE__ */ React14.createElement(
1322
+ Path3,
1323
+ {
1324
+ d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71",
1325
+ stroke: color,
1326
+ strokeWidth: 2,
1327
+ strokeLinecap: "round",
1328
+ strokeLinejoin: "round"
895
1329
  }
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
1330
+ ));
1331
+ };
1332
+
1333
+ // src/assets/ShieldIcon.tsx
1334
+ import React15 from "react";
1335
+ import Svg4, { Path as Path4 } from "react-native-svg";
1336
+ var ShieldIcon = ({
1337
+ size = 20,
1338
+ color = "#00C693"
1339
+ }) => {
1340
+ return /* @__PURE__ */ React15.createElement(Svg4, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React15.createElement(
1341
+ Path4,
1342
+ {
1343
+ d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",
1344
+ stroke: color,
1345
+ strokeWidth: 2,
1346
+ strokeLinecap: "round",
1347
+ strokeLinejoin: "round"
903
1348
  }
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
- },
912
- params: {
913
- id: address
1349
+ ), /* @__PURE__ */ React15.createElement(
1350
+ Path4,
1351
+ {
1352
+ d: "m9 12 2 2 4-4",
1353
+ stroke: color,
1354
+ strokeWidth: 2,
1355
+ strokeLinecap: "round",
1356
+ strokeLinejoin: "round"
914
1357
  }
915
- });
916
- return res.data?.data?.chains || [];
917
- }
1358
+ ));
1359
+ };
1360
+
1361
+ // src/assets/eye.tsx
1362
+ import React16 from "react";
1363
+ import Svg5, { Path as Path5 } from "react-native-svg";
1364
+ var EyeIcon = ({
1365
+ size = 20,
1366
+ color = "#00C693"
1367
+ }) => {
1368
+ 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" }));
1369
+ };
918
1370
 
919
1371
  // src/molecules/ConnectLogo.tsx
920
- import React11, { isValidElement } from "react";
1372
+ import React18, { isValidElement } from "react";
921
1373
  import {
922
1374
  Image,
923
- StyleSheet as StyleSheet4,
924
- Text as Text4,
925
- View as View4
1375
+ StyleSheet as StyleSheet10,
1376
+ Text as Text8,
1377
+ View as View10
926
1378
  } from "react-native";
927
1379
 
928
1380
  // src/assets/UnplugIcon.tsx
929
- import React10 from "react";
930
- import Svg5, { Path as Path5, Line } from "react-native-svg";
1381
+ import React17 from "react";
1382
+ import Svg6, { Path as Path6, Line } from "react-native-svg";
931
1383
  var UnplugIcon = ({
932
1384
  size = 24,
933
1385
  color = "#6B7280"
934
1386
  }) => {
935
- return /* @__PURE__ */ React10.createElement(Svg5, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React10.createElement(
936
- Path5,
1387
+ return /* @__PURE__ */ React17.createElement(Svg6, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React17.createElement(
1388
+ Path6,
937
1389
  {
938
1390
  d: "m19 5 3-3",
939
1391
  stroke: color,
@@ -941,8 +1393,8 @@ var UnplugIcon = ({
941
1393
  strokeLinecap: "round",
942
1394
  strokeLinejoin: "round"
943
1395
  }
944
- ), /* @__PURE__ */ React10.createElement(
945
- Path5,
1396
+ ), /* @__PURE__ */ React17.createElement(
1397
+ Path6,
946
1398
  {
947
1399
  d: "m2 22 3-3",
948
1400
  stroke: color,
@@ -950,8 +1402,8 @@ var UnplugIcon = ({
950
1402
  strokeLinecap: "round",
951
1403
  strokeLinejoin: "round"
952
1404
  }
953
- ), /* @__PURE__ */ React10.createElement(
954
- Path5,
1405
+ ), /* @__PURE__ */ React17.createElement(
1406
+ Path6,
955
1407
  {
956
1408
  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
1409
  stroke: color,
@@ -959,8 +1411,8 @@ var UnplugIcon = ({
959
1411
  strokeLinecap: "round",
960
1412
  strokeLinejoin: "round"
961
1413
  }
962
- ), /* @__PURE__ */ React10.createElement(
963
- Path5,
1414
+ ), /* @__PURE__ */ React17.createElement(
1415
+ Path6,
964
1416
  {
965
1417
  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
1418
  stroke: color,
@@ -968,7 +1420,7 @@ var UnplugIcon = ({
968
1420
  strokeLinecap: "round",
969
1421
  strokeLinejoin: "round"
970
1422
  }
971
- ), /* @__PURE__ */ React10.createElement(
1423
+ ), /* @__PURE__ */ React17.createElement(
972
1424
  Line,
973
1425
  {
974
1426
  x1: 7.5,
@@ -985,12 +1437,12 @@ var UnplugIcon = ({
985
1437
  // src/molecules/ConnectLogo.tsx
986
1438
  var KryptosLogo = () => {
987
1439
  const theme = useTheme();
988
- return /* @__PURE__ */ React11.createElement(
989
- View4,
1440
+ return /* @__PURE__ */ React18.createElement(
1441
+ View10,
990
1442
  {
991
- style: [styles4.logoContainer, { backgroundColor: theme.colors.surface }]
1443
+ style: [styles10.logoContainer, { backgroundColor: theme.colors.surface }]
992
1444
  },
993
- /* @__PURE__ */ React11.createElement(LogoIcon, { size: 36 })
1445
+ /* @__PURE__ */ React18.createElement(LogoIcon, { size: 36 })
994
1446
  );
995
1447
  };
996
1448
  var ConnectLogo = () => {
@@ -1008,46 +1460,44 @@ var ConnectLogo = () => {
1008
1460
  if (isValidElement(appLogo)) {
1009
1461
  return appLogo;
1010
1462
  } else if (typeof appLogo === "string" && isValidUrl(appLogo)) {
1011
- return /* @__PURE__ */ React11.createElement(
1463
+ return /* @__PURE__ */ React18.createElement(
1012
1464
  Image,
1013
1465
  {
1014
1466
  source: { uri: appLogo },
1015
- style: styles4.appLogoImage,
1467
+ style: styles10.appLogoImage,
1016
1468
  resizeMode: "contain"
1017
1469
  }
1018
1470
  );
1019
1471
  } else if (typeof appLogo === "number" || typeof appLogo === "object" && appLogo !== null) {
1020
- return /* @__PURE__ */ React11.createElement(
1472
+ return /* @__PURE__ */ React18.createElement(
1021
1473
  Image,
1022
1474
  {
1023
1475
  source: appLogo,
1024
- style: styles4.appLogoImage,
1476
+ style: styles10.appLogoImage,
1025
1477
  resizeMode: "contain"
1026
1478
  }
1027
1479
  );
1028
1480
  } else if (appName) {
1029
- return /* @__PURE__ */ React11.createElement(Text4, { style: [styles4.appLogoText, { color: theme.colors.text }] }, appName.charAt(0).toUpperCase());
1481
+ return /* @__PURE__ */ React18.createElement(Text8, { style: [styles10.appLogoText, { color: theme.colors.text }] }, appName.charAt(0).toUpperCase());
1030
1482
  }
1031
- return /* @__PURE__ */ React11.createElement(Text4, { style: [styles4.appLogoText, { color: theme.colors.text }] }, "?");
1483
+ return /* @__PURE__ */ React18.createElement(Text8, { style: [styles10.appLogoText, { color: theme.colors.text }] }, "?");
1032
1484
  };
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,
1485
+ 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(
1486
+ View10,
1035
1487
  {
1036
1488
  style: [
1037
- styles4.logoContainer,
1489
+ styles10.logoContainer,
1038
1490
  { backgroundColor: theme.colors.surface }
1039
1491
  ]
1040
1492
  },
1041
1493
  renderLogo()
1042
1494
  ));
1043
1495
  };
1044
- var styles4 = StyleSheet4.create({
1496
+ var styles10 = StyleSheet10.create({
1045
1497
  container: {
1046
1498
  flexDirection: "row",
1047
1499
  alignItems: "center",
1048
1500
  justifyContent: "center",
1049
- marginVertical: 24,
1050
- // theme.spacing.xxl
1051
1501
  gap: 12
1052
1502
  // theme.spacing.md
1053
1503
  },
@@ -1060,476 +1510,255 @@ var styles4 = StyleSheet4.create({
1060
1510
  justifyContent: "center",
1061
1511
  overflow: "hidden"
1062
1512
  },
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
- },
1157
- {
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"
1161
- }
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(
1164
- Text5,
1165
- {
1166
- style: [
1167
- styles5.infoDescription,
1168
- { color: theme.colors.textSecondary }
1169
- ]
1170
- },
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
- ))));
1193
- };
1194
- var styles5 = StyleSheet5.create({
1195
- container: {
1196
- flex: 1
1197
- },
1198
- title: {
1199
- fontSize: 18,
1200
- // theme.fontSize.xl
1201
- fontWeight: "600",
1202
- textAlign: "center",
1203
- marginBottom: 16
1204
- // theme.spacing.lg - consistent section spacing
1205
- },
1206
- infoSection: {
1207
- 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
- alignItems: "center",
1218
- justifyContent: "center",
1219
- marginRight: 12
1220
- // theme.spacing.md
1221
- },
1222
- infoContent: {
1223
- flex: 1
1224
- },
1225
- infoTitle: {
1226
- fontSize: 14,
1227
- // theme.fontSize.md
1228
- fontWeight: "600",
1229
- marginBottom: 4
1230
- // theme.spacing.xs
1231
- },
1232
- infoDescription: {
1233
- fontSize: 13,
1234
- lineHeight: 18
1235
- },
1236
- button: {
1237
- width: "100%",
1238
- marginTop: 16
1239
- // theme.spacing.lg - consistent button spacing
1240
- },
1241
- footer: {
1242
- fontSize: 12,
1243
- // theme.fontSize.sm
1244
- textAlign: "center",
1245
- marginTop: 16
1246
- // theme.spacing.lg
1247
- }
1248
- });
1249
-
1250
- // src/components/Input.tsx
1251
- import React13 from "react";
1252
- import {
1253
- View as View6,
1254
- TextInput,
1255
- Text as Text6,
1256
- StyleSheet as StyleSheet6
1257
- } from "react-native";
1258
- var Input = ({
1259
- label,
1260
- error,
1261
- helperText,
1262
- status = "default",
1263
- containerStyle,
1264
- inputStyle,
1265
- labelStyle,
1266
- ...props
1267
- }) => {
1268
- 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;
1278
- }
1279
- };
1280
- return /* @__PURE__ */ React13.createElement(View6, { style: [styles6.wrapper, containerStyle] }, label && /* @__PURE__ */ React13.createElement(
1281
- Text6,
1282
- {
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,
1292
- {
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
1308
- }
1309
- ), error && /* @__PURE__ */ React13.createElement(
1310
- Text6,
1311
- {
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,
1320
- {
1321
- style: [
1322
- styles6.helper,
1323
- {
1324
- color: theme.colors.textSecondary,
1325
- fontSize: theme.fontSize.sm
1326
- }
1327
- ]
1328
- },
1329
- helperText
1330
- ));
1331
- };
1332
- var styles6 = StyleSheet6.create({
1333
- wrapper: {
1334
- marginBottom: 16
1335
- // theme.spacing.lg - consistent form spacing
1336
- },
1337
- label: {
1338
- fontWeight: "500",
1339
- marginBottom: 8
1340
- // theme.spacing.sm
1341
- },
1342
- input: {
1343
- borderWidth: 1,
1344
- minHeight: 48
1513
+ iconContainer: {
1514
+ paddingHorizontal: 8
1515
+ // theme.spacing.sm
1345
1516
  },
1346
- error: {
1347
- marginTop: 4
1348
- // theme.spacing.xs
1517
+ appLogoImage: {
1518
+ width: 32,
1519
+ height: 32
1349
1520
  },
1350
- helper: {
1351
- marginTop: 4
1352
- // theme.spacing.xs
1521
+ appLogoText: {
1522
+ fontSize: 24,
1523
+ // theme.fontSize.xxxl
1524
+ fontWeight: "700"
1353
1525
  }
1354
1526
  });
1355
1527
 
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
1528
+ // src/molecules/Auth.tsx
1529
+ var Auth = ({
1530
+ open,
1531
+ onEmailSuccess,
1532
+ onGuestSuccess,
1533
+ onClose
1375
1534
  }) => {
1535
+ const { appName, linkToken, clientId, setUser, setEmail } = useKryptosConnect();
1376
1536
  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);
1537
+ const [isLoading, setIsLoading] = React19.useState(false);
1538
+ const [errorMessage, setErrorMessage] = React19.useState("");
1539
+ const [emailValue, setEmailValue] = React19.useState("");
1540
+ const [emailError, setEmailError] = React19.useState("");
1541
+ const [loadingType, setLoadingType] = React19.useState(null);
1542
+ const validateEmail = (email) => {
1543
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1544
+ if (!email) {
1545
+ setEmailError("Email is required");
1546
+ return false;
1389
1547
  }
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;
1548
+ if (!emailRegex.test(email)) {
1549
+ setEmailError("Invalid email address");
1550
+ return false;
1551
+ }
1552
+ setEmailError("");
1553
+ return true;
1554
+ };
1555
+ const handleClose = () => {
1556
+ onClose();
1557
+ setEmailValue("");
1558
+ setEmailError("");
1559
+ setErrorMessage("");
1560
+ };
1561
+ const handleEmailSubmit = async () => {
1562
+ if (!validateEmail(emailValue)) return;
1563
+ try {
1564
+ setIsLoading(true);
1565
+ setLoadingType("email");
1402
1566
  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;
1567
+ await sendEmailOtp(linkToken, emailValue, clientId);
1568
+ setEmail(emailValue);
1569
+ setEmailError("");
1570
+ onEmailSuccess();
1571
+ } catch (error) {
1572
+ const err = error;
1573
+ setErrorMessage(
1574
+ err?.response?.data?.message || "Failed to send email OTP"
1575
+ );
1576
+ } finally {
1577
+ setIsLoading(false);
1578
+ setLoadingType(null);
1579
+ }
1580
+ };
1581
+ const handleContinueAsGuest = async () => {
1582
+ try {
1583
+ setIsLoading(true);
1584
+ setLoadingType("guest");
1585
+ setErrorMessage("");
1586
+ const res = await createAnonymousUser(linkToken, clientId);
1587
+ setUser(res);
1588
+ setEmailError("");
1589
+ onGuestSuccess();
1590
+ } catch (error) {
1591
+ const err = error;
1592
+ console.error(error);
1593
+ setErrorMessage(
1594
+ err?.response?.data?.message || "Failed to continue as guest"
1595
+ );
1596
+ } finally {
1597
+ setIsLoading(false);
1598
+ setLoadingType(null);
1599
+ }
1442
1600
  };
1443
- return /* @__PURE__ */ React14.createElement(View7, { style: [styles7.wrapper, containerStyle] }, label && /* @__PURE__ */ React14.createElement(
1444
- Text7,
1601
+ const infoSections = [
1445
1602
  {
1446
- style: [
1447
- styles7.label,
1448
- { color: theme.colors.text, fontSize: theme.fontSize.sm }
1449
- ]
1603
+ icon: /* @__PURE__ */ React19.createElement(LinkIcon, { size: 20, color: theme.colors.primary }),
1604
+ title: "Simple and secure",
1605
+ text: "Link your accounts in just a few clicks"
1450
1606
  },
1451
- label
1452
- ), /* @__PURE__ */ React14.createElement(View7, { style: styles7.container }, Array.from({ length }, (_, index) => /* @__PURE__ */ React14.createElement(
1453
- TextInput2,
1454
1607
  {
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
1608
+ icon: /* @__PURE__ */ React19.createElement(ShieldIcon, { size: 20, color: theme.colors.primary }),
1609
+ title: "Control what you share",
1610
+ text: "We never share your data without your permission"
1611
+ },
1612
+ {
1613
+ icon: /* @__PURE__ */ React19.createElement(EyeIcon, { size: 20, color: theme.colors.primary }),
1614
+ title: "View Only Access",
1615
+ text: "Kryptos retrieves view-only data and cannot perform any transactions on your behalf."
1476
1616
  }
1477
- ))), error && /* @__PURE__ */ React14.createElement(
1478
- Text7,
1617
+ ];
1618
+ 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(
1619
+ Text9,
1620
+ {
1621
+ style: [styles11.infoTitle, { color: theme.colors.text }]
1622
+ },
1623
+ section.title
1624
+ ), /* @__PURE__ */ React19.createElement(
1625
+ Text9,
1479
1626
  {
1480
1627
  style: [
1481
- styles7.error,
1482
- { color: theme.colors.error, fontSize: theme.fontSize.sm }
1628
+ styles11.infoDescription,
1629
+ { color: theme.colors.textSecondary }
1483
1630
  ]
1484
1631
  },
1485
- error
1486
- ));
1632
+ section.text
1633
+ )))), errorMessage ? /* @__PURE__ */ React19.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ React19.createElement(AlertDescription, null, errorMessage)) : null), /* @__PURE__ */ React19.createElement(View11, { style: styles11.footer }, /* @__PURE__ */ React19.createElement(
1634
+ Button,
1635
+ {
1636
+ variant: "outline",
1637
+ size: "lg",
1638
+ onPress: handleContinueAsGuest,
1639
+ loading: loadingType === "guest",
1640
+ disabled: isLoading,
1641
+ style: styles11.button
1642
+ },
1643
+ "Continue"
1644
+ ), /* @__PURE__ */ React19.createElement(
1645
+ Text9,
1646
+ {
1647
+ style: [styles11.footerText, { color: theme.colors.textSecondary }]
1648
+ },
1649
+ "By continuing, you agree to Kryptos",
1650
+ " ",
1651
+ /* @__PURE__ */ React19.createElement(
1652
+ Text9,
1653
+ {
1654
+ style: {
1655
+ color: theme.colors.primary,
1656
+ textDecorationLine: "underline"
1657
+ },
1658
+ onPress: () => Linking2.openURL("https://kryptos.io/privacy-policy")
1659
+ },
1660
+ "Privacy Policy"
1661
+ ),
1662
+ " ",
1663
+ "and",
1664
+ " ",
1665
+ /* @__PURE__ */ React19.createElement(
1666
+ Text9,
1667
+ {
1668
+ style: {
1669
+ color: theme.colors.primary,
1670
+ textDecorationLine: "underline"
1671
+ },
1672
+ onPress: () => Linking2.openURL("https://kryptos.io/terms-of-services")
1673
+ },
1674
+ "Terms of Service"
1675
+ )
1676
+ )))), /* @__PURE__ */ React19.createElement(ModalFooter, { style: { paddingVertical: 0 } }, /* @__PURE__ */ React19.createElement(Footer, null)));
1487
1677
  };
1488
- var styles7 = StyleSheet7.create({
1489
- wrapper: {
1490
- marginBottom: 16
1491
- // theme.spacing.lg
1678
+ var styles11 = StyleSheet11.create({
1679
+ container: {
1680
+ flex: 1,
1681
+ flexDirection: "column",
1682
+ justifyContent: "space-between"
1492
1683
  },
1493
- label: {
1684
+ header: {
1685
+ flex: 1,
1686
+ gap: 8
1687
+ },
1688
+ footer: {
1689
+ flex: 1,
1690
+ justifyContent: "flex-end",
1691
+ gap: 8
1692
+ },
1693
+ title: {
1694
+ fontSize: 18,
1695
+ // theme.fontSize.xl
1494
1696
  fontWeight: "500",
1495
- marginBottom: 12,
1496
- // theme.spacing.md - consistent label spacing
1497
1697
  textAlign: "center"
1498
1698
  },
1499
- container: {
1699
+ infoSection: {
1500
1700
  flexDirection: "row",
1501
- justifyContent: "center",
1502
- gap: 8
1503
- // theme.spacing.sm
1701
+ alignItems: "flex-start",
1702
+ padding: 8,
1703
+ gap: 12
1704
+ },
1705
+ infoIcon: {
1706
+ width: 32,
1707
+ // theme.spacing.xxxl
1708
+ height: 32,
1709
+ // theme.spacing.xxxl
1710
+ borderRadius: 16,
1711
+ // theme.borderRadius.lg
1712
+ alignItems: "center",
1713
+ justifyContent: "center"
1504
1714
  },
1505
- input: {
1506
- width: 48,
1507
- height: 56,
1508
- borderWidth: 1,
1509
- textAlign: "center",
1715
+ infoContent: {
1716
+ flex: 1,
1717
+ gap: 4
1718
+ },
1719
+ infoTitle: {
1720
+ fontSize: 14,
1721
+ // theme.fontSize.md
1510
1722
  fontWeight: "600"
1511
1723
  },
1512
- error: {
1513
- marginTop: 12,
1514
- // theme.spacing.md - consistent error spacing
1515
- textAlign: "center"
1724
+ infoDescription: {
1725
+ fontSize: 13,
1726
+ // theme.fontSize.sm + 1
1727
+ lineHeight: 18
1728
+ },
1729
+ button: {
1730
+ width: "100%"
1731
+ },
1732
+ footerText: {
1733
+ fontSize: 12,
1734
+ // theme.fontSize.sm
1735
+ textAlign: "center",
1736
+ padding: 8,
1737
+ maxWidth: "80%",
1738
+ alignSelf: "center"
1516
1739
  }
1517
1740
  });
1518
1741
 
1519
1742
  // 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";
1743
+ import React20 from "react";
1744
+ import { ActivityIndicator as ActivityIndicator2, StyleSheet as StyleSheet12, Text as Text10, View as View12 } from "react-native";
1522
1745
  var Init = ({
1523
1746
  open,
1524
1747
  onSuccess,
1525
1748
  onClose,
1526
1749
  generateLinkToken
1527
1750
  }) => {
1528
- const { setIsInitialized, isInitialized, setLinkToken } = useKryptosConnect();
1751
+ const {
1752
+ setIsInitialized,
1753
+ isInitialized,
1754
+ setLinkToken,
1755
+ setIsAuthorized,
1756
+ setUser
1757
+ } = useKryptosConnect();
1529
1758
  const theme = useTheme();
1530
- const [isFetching, setIsFetching] = React15.useState(false);
1531
- const [error, setError] = React15.useState(null);
1532
- const fetchLinkToken = React15.useCallback(async () => {
1759
+ const [isFetching, setIsFetching] = React20.useState(false);
1760
+ const [error, setError] = React20.useState(null);
1761
+ const fetchLinkToken = React20.useCallback(async () => {
1533
1762
  if (!open) return;
1534
1763
  setIsFetching(true);
1535
1764
  setError(null);
@@ -1542,6 +1771,11 @@ var Init = ({
1542
1771
  }
1543
1772
  setLinkToken(linkToken.link_token);
1544
1773
  setIsInitialized(true);
1774
+ setIsAuthorized(linkToken.isAuthorized || false);
1775
+ if (linkToken.isAuthorized) {
1776
+ const userInfo = await getUserInfo(linkToken.link_token);
1777
+ setUser(userInfo);
1778
+ }
1545
1779
  onSuccess(linkToken.isAuthorized ? { isAuthorized: true } : null);
1546
1780
  } catch (err) {
1547
1781
  console.error("Failed to fetch link token:", err);
@@ -1550,29 +1784,29 @@ var Init = ({
1550
1784
  } finally {
1551
1785
  setIsFetching(false);
1552
1786
  }
1553
- }, [generateLinkToken, open, setIsInitialized, setLinkToken, onSuccess]);
1554
- React15.useEffect(() => {
1787
+ }, []);
1788
+ React20.useEffect(() => {
1555
1789
  fetchLinkToken();
1556
1790
  }, [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(
1791
+ 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
1792
  ActivityIndicator2,
1559
1793
  {
1560
1794
  size: "large",
1561
1795
  color: theme.colors.primary,
1562
- style: styles8.spinner
1796
+ style: styles12.spinner
1563
1797
  }
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(
1798
+ ), /* @__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
1799
  Button,
1566
1800
  {
1567
1801
  variant: "primary",
1568
1802
  size: "lg",
1569
1803
  onPress: fetchLinkToken,
1570
- style: styles8.retryButton
1804
+ style: styles12.retryButton
1571
1805
  },
1572
1806
  "Retry"
1573
- )))));
1807
+ )))), /* @__PURE__ */ React20.createElement(ModalFooter, { style: { paddingVertical: 0 } }, /* @__PURE__ */ React20.createElement(Footer, null)));
1574
1808
  };
1575
- var styles8 = StyleSheet8.create({
1809
+ var styles12 = StyleSheet12.create({
1576
1810
  container: {
1577
1811
  flex: 1,
1578
1812
  alignItems: "center",
@@ -1599,25 +1833,25 @@ var styles8 = StyleSheet8.create({
1599
1833
  });
1600
1834
 
1601
1835
  // src/molecules/Integration.tsx
1602
- import React27 from "react";
1836
+ import React31 from "react";
1603
1837
  import {
1604
1838
  FlatList,
1605
1839
  Image as Image3,
1606
- StyleSheet as StyleSheet12,
1607
- Text as Text11,
1608
- TouchableOpacity as TouchableOpacity5,
1609
- View as View12
1840
+ StyleSheet as StyleSheet15,
1841
+ Text as Text13,
1842
+ TouchableOpacity as TouchableOpacity6,
1843
+ View as View15
1610
1844
  } from "react-native";
1611
1845
 
1612
1846
  // src/assets/ArrowLeftIcon.tsx
1613
- import React16 from "react";
1614
- import Svg6, { Path as Path6 } from "react-native-svg";
1847
+ import React21 from "react";
1848
+ import Svg7, { Path as Path7 } from "react-native-svg";
1615
1849
  var ArrowLeftIcon = ({
1616
1850
  size = 20,
1617
1851
  color = "#000"
1618
1852
  }) => {
1619
- return /* @__PURE__ */ React16.createElement(Svg6, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React16.createElement(
1620
- Path6,
1853
+ return /* @__PURE__ */ React21.createElement(Svg7, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React21.createElement(
1854
+ Path7,
1621
1855
  {
1622
1856
  d: "M19 12H5M12 19l-7-7 7-7",
1623
1857
  stroke: color,
@@ -1629,13 +1863,13 @@ var ArrowLeftIcon = ({
1629
1863
  };
1630
1864
 
1631
1865
  // src/assets/CheckCircleIcon.tsx
1632
- import React17 from "react";
1633
- import Svg7, { Path as Path7, Circle } from "react-native-svg";
1866
+ import React22 from "react";
1867
+ import Svg8, { Path as Path8, Circle } from "react-native-svg";
1634
1868
  var CheckCircleIcon = ({
1635
1869
  size = 20,
1636
1870
  color = "#10B981"
1637
1871
  }) => {
1638
- return /* @__PURE__ */ React17.createElement(Svg7, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React17.createElement(
1872
+ return /* @__PURE__ */ React22.createElement(Svg8, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React22.createElement(
1639
1873
  Circle,
1640
1874
  {
1641
1875
  cx: 12,
@@ -1644,8 +1878,8 @@ var CheckCircleIcon = ({
1644
1878
  stroke: color,
1645
1879
  strokeWidth: 2
1646
1880
  }
1647
- ), /* @__PURE__ */ React17.createElement(
1648
- Path7,
1881
+ ), /* @__PURE__ */ React22.createElement(
1882
+ Path8,
1649
1883
  {
1650
1884
  d: "m9 12 2 2 4-4",
1651
1885
  stroke: color,
@@ -1657,18 +1891,18 @@ var CheckCircleIcon = ({
1657
1891
  };
1658
1892
 
1659
1893
  // 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);
1894
+ import React23 from "react";
1895
+ import { Animated as Animated2, Easing } from "react-native";
1896
+ import Svg9, { Path as Path9 } from "react-native-svg";
1897
+ var AnimatedSvg = Animated2.createAnimatedComponent(Svg9);
1664
1898
  var LoaderIcon = ({
1665
1899
  size = 20,
1666
1900
  color = "#00C693"
1667
1901
  }) => {
1668
- const rotateAnim = React18.useRef(new Animated.Value(0)).current;
1669
- React18.useEffect(() => {
1670
- Animated.loop(
1671
- Animated.timing(rotateAnim, {
1902
+ const rotateAnim = React23.useRef(new Animated2.Value(0)).current;
1903
+ React23.useEffect(() => {
1904
+ Animated2.loop(
1905
+ Animated2.timing(rotateAnim, {
1672
1906
  toValue: 1,
1673
1907
  duration: 1e3,
1674
1908
  easing: Easing.linear,
@@ -1680,7 +1914,7 @@ var LoaderIcon = ({
1680
1914
  inputRange: [0, 1],
1681
1915
  outputRange: ["0deg", "360deg"]
1682
1916
  });
1683
- return /* @__PURE__ */ React18.createElement(
1917
+ return /* @__PURE__ */ React23.createElement(
1684
1918
  AnimatedSvg,
1685
1919
  {
1686
1920
  width: size,
@@ -1689,8 +1923,8 @@ var LoaderIcon = ({
1689
1923
  fill: "none",
1690
1924
  style: { transform: [{ rotate: spin }] }
1691
1925
  },
1692
- /* @__PURE__ */ React18.createElement(
1693
- Path8,
1926
+ /* @__PURE__ */ React23.createElement(
1927
+ Path9,
1694
1928
  {
1695
1929
  d: "M21 12a9 9 0 1 1-6.219-8.56",
1696
1930
  stroke: color,
@@ -1703,10 +1937,10 @@ var LoaderIcon = ({
1703
1937
  };
1704
1938
 
1705
1939
  // src/assets/SuccessIcon.tsx
1706
- import React19 from "react";
1707
- import Svg9, { Circle as Circle2, Path as Path9 } from "react-native-svg";
1940
+ import React24 from "react";
1941
+ import Svg10, { Circle as Circle2, Path as Path10 } from "react-native-svg";
1708
1942
  var SuccessIcon = ({ size = 64 }) => {
1709
- return /* @__PURE__ */ React19.createElement(Svg9, { width: size, height: size, viewBox: "0 0 64 64", fill: "none" }, /* @__PURE__ */ React19.createElement(
1943
+ return /* @__PURE__ */ React24.createElement(Svg10, { width: size, height: size, viewBox: "0 0 64 64", fill: "none" }, /* @__PURE__ */ React24.createElement(
1710
1944
  Circle2,
1711
1945
  {
1712
1946
  cx: 32,
@@ -1715,7 +1949,7 @@ var SuccessIcon = ({ size = 64 }) => {
1715
1949
  fill: "#00C693",
1716
1950
  opacity: 0.1
1717
1951
  }
1718
- ), /* @__PURE__ */ React19.createElement(
1952
+ ), /* @__PURE__ */ React24.createElement(
1719
1953
  Circle2,
1720
1954
  {
1721
1955
  cx: 32,
@@ -1723,8 +1957,8 @@ var SuccessIcon = ({ size = 64 }) => {
1723
1957
  r: 24,
1724
1958
  fill: "#00C693"
1725
1959
  }
1726
- ), /* @__PURE__ */ React19.createElement(
1727
- Path9,
1960
+ ), /* @__PURE__ */ React24.createElement(
1961
+ Path10,
1728
1962
  {
1729
1963
  d: "M24 32l6 6 12-12",
1730
1964
  stroke: "white",
@@ -1736,10 +1970,10 @@ var SuccessIcon = ({ size = 64 }) => {
1736
1970
  };
1737
1971
 
1738
1972
  // src/assets/ErrorIcon.tsx
1739
- import React20 from "react";
1740
- import Svg10, { Circle as Circle3, Path as Path10 } from "react-native-svg";
1973
+ import React25 from "react";
1974
+ import Svg11, { Circle as Circle3, Path as Path11 } from "react-native-svg";
1741
1975
  var ErrorIcon = ({ size = 64 }) => {
1742
- return /* @__PURE__ */ React20.createElement(Svg10, { width: size, height: size, viewBox: "0 0 64 64", fill: "none" }, /* @__PURE__ */ React20.createElement(
1976
+ return /* @__PURE__ */ React25.createElement(Svg11, { width: size, height: size, viewBox: "0 0 64 64", fill: "none" }, /* @__PURE__ */ React25.createElement(
1743
1977
  Circle3,
1744
1978
  {
1745
1979
  cx: 32,
@@ -1748,7 +1982,7 @@ var ErrorIcon = ({ size = 64 }) => {
1748
1982
  fill: "#EF4444",
1749
1983
  opacity: 0.1
1750
1984
  }
1751
- ), /* @__PURE__ */ React20.createElement(
1985
+ ), /* @__PURE__ */ React25.createElement(
1752
1986
  Circle3,
1753
1987
  {
1754
1988
  cx: 32,
@@ -1756,8 +1990,8 @@ var ErrorIcon = ({ size = 64 }) => {
1756
1990
  r: 24,
1757
1991
  fill: "#EF4444"
1758
1992
  }
1759
- ), /* @__PURE__ */ React20.createElement(
1760
- Path10,
1993
+ ), /* @__PURE__ */ React25.createElement(
1994
+ Path11,
1761
1995
  {
1762
1996
  d: "M24 24l16 16M40 24l-16 16",
1763
1997
  stroke: "white",
@@ -1769,18 +2003,18 @@ var ErrorIcon = ({ size = 64 }) => {
1769
2003
  };
1770
2004
 
1771
2005
  // src/assets/SearchIcon.tsx
1772
- import React21 from "react";
1773
- import Svg11, { Circle as Circle4, Path as Path11 } from "react-native-svg";
2006
+ import React26 from "react";
2007
+ import Svg12, { Circle as Circle4, Path as Path12 } from "react-native-svg";
1774
2008
 
1775
2009
  // src/assets/PlusIcon.tsx
1776
- import React22 from "react";
1777
- import Svg12, { Path as Path12 } from "react-native-svg";
2010
+ import React27 from "react";
2011
+ import Svg13, { Path as Path13 } from "react-native-svg";
1778
2012
  var PlusIcon = ({
1779
2013
  size = 14,
1780
2014
  color = "#6B7280"
1781
2015
  }) => {
1782
- return /* @__PURE__ */ React22.createElement(Svg12, { width: size, height: size, viewBox: "0 0 14 14", fill: "none" }, /* @__PURE__ */ React22.createElement(
1783
- Path12,
2016
+ return /* @__PURE__ */ React27.createElement(Svg13, { width: size, height: size, viewBox: "0 0 14 14", fill: "none" }, /* @__PURE__ */ React27.createElement(
2017
+ Path13,
1784
2018
  {
1785
2019
  d: "M7 3.5v7M3.5 7h7",
1786
2020
  stroke: color,
@@ -1792,13 +2026,13 @@ var PlusIcon = ({
1792
2026
 
1793
2027
  // src/wallet-connect/index.tsx
1794
2028
  import { useAccount, useAppKit } from "@reown/appkit-react-native";
1795
- import React24, { useState } from "react";
2029
+ import React29, { useState } from "react";
1796
2030
  import {
1797
2031
  ScrollView as ScrollView2,
1798
- StyleSheet as StyleSheet9,
1799
- Text as Text9,
1800
- TouchableOpacity as TouchableOpacity3,
1801
- View as View9
2032
+ StyleSheet as StyleSheet13,
2033
+ Text as Text11,
2034
+ TouchableOpacity as TouchableOpacity4,
2035
+ View as View13
1802
2036
  } from "react-native";
1803
2037
 
1804
2038
  // src/utils/uuid.ts
@@ -1811,7 +2045,7 @@ function generateUUID() {
1811
2045
  }
1812
2046
 
1813
2047
  // src/wallet-connect/wallet-connect.tsx
1814
- import React23 from "react";
2048
+ import React28 from "react";
1815
2049
  import { AppKit, AppKitProvider } from "@reown/appkit-react-native";
1816
2050
 
1817
2051
  // src/wallet-connect/AppKitConfig.ts
@@ -1920,7 +2154,7 @@ var createAppKitInstance = (projectId) => {
1920
2154
  // src/wallet-connect/wallet-connect.tsx
1921
2155
  var WalletConnectWrapper = ({ children }) => {
1922
2156
  const { walletConnectProjectId } = useKryptosConnect();
1923
- const appKit = React23.useMemo(() => {
2157
+ const appKit = React28.useMemo(() => {
1924
2158
  if (!walletConnectProjectId) {
1925
2159
  console.warn(
1926
2160
  "walletConnectProjectId is missing in KryptosConnectProvider config"
@@ -1930,9 +2164,9 @@ var WalletConnectWrapper = ({ children }) => {
1930
2164
  return createAppKitInstance(walletConnectProjectId);
1931
2165
  }, [walletConnectProjectId]);
1932
2166
  if (!appKit) {
1933
- return /* @__PURE__ */ React23.createElement(React23.Fragment, null, children);
2167
+ return /* @__PURE__ */ React28.createElement(React28.Fragment, null, children);
1934
2168
  }
1935
- return /* @__PURE__ */ React23.createElement(AppKitProvider, { instance: appKit }, /* @__PURE__ */ React23.createElement(AppKit, null), children);
2169
+ return /* @__PURE__ */ React28.createElement(AppKitProvider, { instance: appKit }, /* @__PURE__ */ React28.createElement(AppKit, null), children);
1936
2170
  };
1937
2171
  var wallet_connect_default = WalletConnectWrapper;
1938
2172
 
@@ -1948,42 +2182,42 @@ var WalletConnectComponent = ({
1948
2182
  const { walletConnectProjectId } = useKryptosConnect();
1949
2183
  const theme = useTheme();
1950
2184
  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,
2185
+ 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(
2186
+ TouchableOpacity4,
1953
2187
  {
1954
2188
  onPress: () => {
1955
2189
  setAddIntegrationMode(null);
1956
2190
  },
1957
- style: styles9.backButton
2191
+ style: styles13.backButton
1958
2192
  },
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,
2193
+ /* @__PURE__ */ React29.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
2194
+ ), /* @__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(
2195
+ Text11,
1962
2196
  {
1963
- style: [styles9.emptyStateTitle, { color: theme.colors.text }]
2197
+ style: [styles13.emptyStateTitle, { color: theme.colors.text }]
1964
2198
  },
1965
2199
  "WalletConnect is not configured"
1966
- ), /* @__PURE__ */ React24.createElement(
1967
- Text9,
2200
+ ), /* @__PURE__ */ React29.createElement(
2201
+ Text11,
1968
2202
  {
1969
2203
  style: [
1970
- styles9.infoText,
2204
+ styles13.infoText,
1971
2205
  { color: theme.colors.textSecondary, textAlign: "center" }
1972
2206
  ]
1973
2207
  },
1974
2208
  "Please add a walletConnectProjectId to KryptosConnectProvider to enable wallet connections."
1975
- ), /* @__PURE__ */ React24.createElement(
2209
+ ), /* @__PURE__ */ React29.createElement(
1976
2210
  Button,
1977
2211
  {
1978
2212
  variant: "outline",
1979
2213
  size: "sm",
1980
2214
  onPress: () => setAddIntegrationMode(null),
1981
- style: styles9.emptyStateButton
2215
+ style: styles13.emptyStateButton
1982
2216
  },
1983
2217
  "Go back"
1984
2218
  ))));
1985
2219
  }
1986
- return /* @__PURE__ */ React24.createElement(wallet_connect_default, null, /* @__PURE__ */ React24.createElement(
2220
+ return /* @__PURE__ */ React29.createElement(wallet_connect_default, null, /* @__PURE__ */ React29.createElement(
1987
2221
  ConnectButton,
1988
2222
  {
1989
2223
  integration,
@@ -2045,7 +2279,7 @@ function ConnectButton({
2045
2279
  source: integration.id,
2046
2280
  credential: {
2047
2281
  address,
2048
- userId: user?.user?.uid || "0",
2282
+ userId: user?.user_id || "0",
2049
2283
  projectId: integration.projectId,
2050
2284
  apiKey: "0",
2051
2285
  secret: "0",
@@ -2075,7 +2309,7 @@ function ConnectButton({
2075
2309
  logo: integration.logo || null,
2076
2310
  startTime: null,
2077
2311
  endTime: null,
2078
- uid: user?.user?.uid || "",
2312
+ uid: user?.user_id || "",
2079
2313
  walletId,
2080
2314
  clientMetadata: {
2081
2315
  clientId,
@@ -2089,7 +2323,7 @@ function ConnectButton({
2089
2323
  default_chain_logo: chain.logo || null,
2090
2324
  type: integration.type,
2091
2325
  isNftSupported: integration.isEvmWallet || integration.nftSupport || false,
2092
- chainId: chain.chainId || chain.id,
2326
+ chainId: chain?.community_id || chain.chainId || chain.id,
2093
2327
  address
2094
2328
  };
2095
2329
  integrationsToAdd.push(data);
@@ -2128,16 +2362,16 @@ function ConnectButton({
2128
2362
  setChainErrors(newErrors);
2129
2363
  }
2130
2364
  };
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,
2365
+ 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(
2366
+ TouchableOpacity4,
2133
2367
  {
2134
2368
  onPress: () => {
2135
2369
  setAddIntegrationMode(null);
2136
2370
  },
2137
- style: styles9.backButton
2371
+ style: styles13.backButton
2138
2372
  },
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(
2373
+ /* @__PURE__ */ React29.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
2374
+ ), /* @__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(
2141
2375
  Button,
2142
2376
  {
2143
2377
  variant: "primary",
@@ -2145,32 +2379,32 @@ function ConnectButton({
2145
2379
  onPress: () => open({ view: "Connect" })
2146
2380
  },
2147
2381
  "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) => {
2382
+ )) : /* @__PURE__ */ React29.createElement(View13, null, /* @__PURE__ */ React29.createElement(Text11, { style: [styles13.connectedTitle, { color: theme.colors.text }] }, "Wallet Connected"), /* @__PURE__ */ React29.createElement(Text11, { style: [styles13.connectedText, { color: theme.colors.text }] }, "Address: ", address), /* @__PURE__ */ React29.createElement(Text11, { style: [styles13.connectedText, { color: theme.colors.text }] }, "Chain: ", chainId), /* @__PURE__ */ React29.createElement(Button, { variant: "ghost", size: "sm", onPress: () => disconnect() }, "Disconnect Wallet"), userUsedChains.length > 0 && address && /* @__PURE__ */ React29.createElement(View13, { style: styles13.chainSelection }, /* @__PURE__ */ React29.createElement(Text11, { style: [styles13.chainTitle, { color: theme.colors.text }] }, "Select Chains to Add:"), /* @__PURE__ */ React29.createElement(ScrollView2, { contentContainerStyle: styles13.scrollViewContent }, /* @__PURE__ */ React29.createElement(View13, { style: styles13.chainChips }, userUsedChains.map((chain) => {
2149
2383
  const isSelected = selectedChains.has(chain.id);
2150
2384
  const hasError = chainErrors[chain.id];
2151
- return /* @__PURE__ */ React24.createElement(
2152
- TouchableOpacity3,
2385
+ return /* @__PURE__ */ React29.createElement(
2386
+ TouchableOpacity4,
2153
2387
  {
2154
2388
  onPress: () => toggleChainSelection(chain.id),
2155
- style: styles9.chainButton,
2389
+ style: styles13.chainButton,
2156
2390
  key: chain.id
2157
2391
  },
2158
- /* @__PURE__ */ React24.createElement(
2159
- View9,
2392
+ /* @__PURE__ */ React29.createElement(
2393
+ View13,
2160
2394
  {
2161
2395
  style: [
2162
- styles9.chainChip,
2396
+ styles13.chainChip,
2163
2397
  {
2164
2398
  backgroundColor: hasError ? theme.colors.errorLight : isSelected ? theme.colors.primary + "20" : theme.colors.surface,
2165
2399
  borderColor: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.border
2166
2400
  }
2167
2401
  ]
2168
2402
  },
2169
- /* @__PURE__ */ React24.createElement(
2170
- Text9,
2403
+ /* @__PURE__ */ React29.createElement(
2404
+ Text11,
2171
2405
  {
2172
2406
  style: [
2173
- styles9.chainName,
2407
+ styles13.chainName,
2174
2408
  {
2175
2409
  color: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.text
2176
2410
  }
@@ -2178,13 +2412,13 @@ function ConnectButton({
2178
2412
  },
2179
2413
  chain.id
2180
2414
  ),
2181
- isSelected ? /* @__PURE__ */ React24.createElement(
2415
+ isSelected ? /* @__PURE__ */ React29.createElement(
2182
2416
  CloseIcon,
2183
2417
  {
2184
2418
  size: 12,
2185
2419
  color: hasError ? theme.colors.error : theme.colors.primary
2186
2420
  }
2187
- ) : /* @__PURE__ */ React24.createElement(
2421
+ ) : /* @__PURE__ */ React29.createElement(
2188
2422
  PlusIcon,
2189
2423
  {
2190
2424
  size: 12,
@@ -2193,11 +2427,11 @@ function ConnectButton({
2193
2427
  )
2194
2428
  )
2195
2429
  );
2196
- }))), Object.keys(chainErrors).length > 0 && /* @__PURE__ */ React24.createElement(View9, { style: styles9.chainErrorsContainer }, /* @__PURE__ */ React24.createElement(
2197
- Text9,
2430
+ }))), Object.keys(chainErrors).length > 0 && /* @__PURE__ */ React29.createElement(View13, { style: styles13.chainErrorsContainer }, /* @__PURE__ */ React29.createElement(
2431
+ Text11,
2198
2432
  {
2199
2433
  style: [
2200
- styles9.chainErrorsTitle,
2434
+ styles13.chainErrorsTitle,
2201
2435
  { color: theme.colors.error }
2202
2436
  ]
2203
2437
  },
@@ -2206,12 +2440,12 @@ function ConnectButton({
2206
2440
  const chain = userUsedChains.find(
2207
2441
  (c) => c.id === chainId2
2208
2442
  );
2209
- return /* @__PURE__ */ React24.createElement(
2210
- Text9,
2443
+ return /* @__PURE__ */ React29.createElement(
2444
+ Text11,
2211
2445
  {
2212
2446
  key: chainId2,
2213
2447
  style: [
2214
- styles9.chainErrorItem,
2448
+ styles13.chainErrorItem,
2215
2449
  { color: theme.colors.error }
2216
2450
  ]
2217
2451
  },
@@ -2220,7 +2454,7 @@ function ConnectButton({
2220
2454
  ": ",
2221
2455
  error
2222
2456
  );
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(
2457
+ }))), errorMessage ? /* @__PURE__ */ React29.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ React29.createElement(AlertDescription, null, errorMessage)) : null)), userUsedChains.length > 0 && address && /* @__PURE__ */ React29.createElement(ModalFooter, { style: { paddingVertical: 8 } }, /* @__PURE__ */ React29.createElement(
2224
2458
  Button,
2225
2459
  {
2226
2460
  variant: "outline",
@@ -2228,12 +2462,12 @@ function ConnectButton({
2228
2462
  onPress: onSubmitWalletConnect,
2229
2463
  loading: isLoading,
2230
2464
  disabled: isLoading || !!address && userUsedChains.length > 0 && selectedChains.size === 0,
2231
- style: styles9.button
2465
+ style: styles13.button
2232
2466
  },
2233
2467
  selectedChains.size > 0 ? `Add ${selectedChains.size} Chain${selectedChains.size > 1 ? "s" : ""}` : "Add Integration"
2234
- )));
2468
+ ), /* @__PURE__ */ React29.createElement(Footer, null)));
2235
2469
  }
2236
- var styles9 = StyleSheet9.create({
2470
+ var styles13 = StyleSheet13.create({
2237
2471
  connectedTitle: { fontSize: 18, fontWeight: "600", marginBottom: 4 },
2238
2472
  connectedText: { fontSize: 14, marginBottom: 4 },
2239
2473
  infoText: {
@@ -2346,14 +2580,14 @@ var styles9 = StyleSheet9.create({
2346
2580
  });
2347
2581
 
2348
2582
  // src/molecules/IntegrationForm.tsx
2349
- import React25 from "react";
2583
+ import React30 from "react";
2350
2584
  import {
2351
2585
  Image as Image2,
2352
2586
  ScrollView as ScrollView3,
2353
- StyleSheet as StyleSheet10,
2354
- Text as Text10,
2355
- TouchableOpacity as TouchableOpacity4,
2356
- View as View10
2587
+ StyleSheet as StyleSheet14,
2588
+ Text as Text12,
2589
+ TouchableOpacity as TouchableOpacity5,
2590
+ View as View14
2357
2591
  } from "react-native";
2358
2592
  var IntegrationForm = ({
2359
2593
  metadata,
@@ -2364,27 +2598,35 @@ var IntegrationForm = ({
2364
2598
  }) => {
2365
2599
  const { clientId, linkToken, user } = useKryptosConnect();
2366
2600
  const theme = useTheme();
2367
- const [isLoading, setIsLoading] = React25.useState(false);
2368
- const [userUsedChains, setUserUsedChains] = React25.useState([]);
2369
- const [selectedChains, setSelectedChains] = React25.useState(
2601
+ const [isLoading, setIsLoading] = React30.useState(false);
2602
+ const [isFetchingChains, setIsFetchingChains] = React30.useState(false);
2603
+ const [userUsedChains, setUserUsedChains] = React30.useState([]);
2604
+ const [selectedChains, setSelectedChains] = React30.useState(
2370
2605
  /* @__PURE__ */ new Set()
2371
2606
  );
2372
- const [chainErrors, setChainErrors] = React25.useState(
2607
+ const [chainErrors, setChainErrors] = React30.useState(
2373
2608
  {}
2374
2609
  );
2375
- const [errorMessage, setErrorMessage] = React25.useState("");
2376
- const [formValues, setFormValues] = React25.useState({
2610
+ const [errorMessage, setErrorMessage] = React30.useState("");
2611
+ const [formValues, setFormValues] = React30.useState({
2377
2612
  address: "",
2378
2613
  account_name: "",
2379
2614
  api_key: "",
2380
2615
  secret_key: "",
2381
2616
  password: ""
2382
2617
  });
2383
- const [formErrors, setFormErrors] = React25.useState({});
2384
- React25.useEffect(() => {
2385
- const fetchUserUsedChains = async () => {
2386
- if (linkToken && formValues.address && formValues.address.trim()) {
2618
+ const [formErrors, setFormErrors] = React30.useState({});
2619
+ React30.useEffect(() => {
2620
+ if (!formValues.address || !formValues.address.trim()) {
2621
+ setUserUsedChains([]);
2622
+ setSelectedChains(/* @__PURE__ */ new Set());
2623
+ setIsFetchingChains(false);
2624
+ return;
2625
+ }
2626
+ const debounceTimer = setTimeout(async () => {
2627
+ if (linkToken && formValues.address && formValues.address.trim() && metadata.isEvmWallet) {
2387
2628
  try {
2629
+ setIsFetchingChains(true);
2388
2630
  const res = await getUserUsedChains(
2389
2631
  linkToken,
2390
2632
  formValues.address.trim()
@@ -2392,18 +2634,22 @@ var IntegrationForm = ({
2392
2634
  if (res && Array.isArray(res)) {
2393
2635
  setUserUsedChains(res);
2394
2636
  setSelectedChains(new Set(res.map((chain) => chain.id)));
2637
+ } else {
2638
+ setUserUsedChains([]);
2639
+ setSelectedChains(/* @__PURE__ */ new Set());
2395
2640
  }
2396
2641
  } catch (error) {
2397
2642
  console.error("Failed to fetch user chains:", error);
2398
2643
  setUserUsedChains([]);
2399
2644
  setSelectedChains(/* @__PURE__ */ new Set());
2645
+ } finally {
2646
+ setIsFetchingChains(false);
2400
2647
  }
2401
- } else {
2402
- setUserUsedChains([]);
2403
- setSelectedChains(/* @__PURE__ */ new Set());
2404
2648
  }
2649
+ }, 500);
2650
+ return () => {
2651
+ clearTimeout(debounceTimer);
2405
2652
  };
2406
- fetchUserUsedChains();
2407
2653
  }, [linkToken, formValues.address]);
2408
2654
  const toggleChainSelection = (chainId) => {
2409
2655
  const newSelected = new Set(selectedChains);
@@ -2462,7 +2708,7 @@ var IntegrationForm = ({
2462
2708
  accountName: formValues.account_name?.trim() || "0",
2463
2709
  address: formValues.address?.trim() || "0",
2464
2710
  password: formValues.password?.trim() || "0",
2465
- userId: user?.user?.uid || "0",
2711
+ userId: user?.user_id || "0",
2466
2712
  projectId: metadata?.projectId || "0",
2467
2713
  privateKey: "0",
2468
2714
  alias,
@@ -2490,7 +2736,7 @@ var IntegrationForm = ({
2490
2736
  logo: metadata.logo || null,
2491
2737
  startTime: null,
2492
2738
  endTime: null,
2493
- uid: user?.user?.uid || "",
2739
+ uid: user?.user_id || "",
2494
2740
  walletId,
2495
2741
  clientMetadata: {
2496
2742
  clientId,
@@ -2504,7 +2750,7 @@ var IntegrationForm = ({
2504
2750
  default_chain_logo: chain.logo || null,
2505
2751
  type: metadata.type,
2506
2752
  isNftSupported: metadata.isEvmWallet || metadata.nftSupport || false,
2507
- chainId: chain.chainId || chain.id,
2753
+ chainId: chain?.community_id || "",
2508
2754
  address: formValues.address
2509
2755
  };
2510
2756
  if (formValues.account_name)
@@ -2541,7 +2787,7 @@ var IntegrationForm = ({
2541
2787
  accountName: formValues.account_name?.trim() || "0",
2542
2788
  address: formValues.address?.trim() || "0",
2543
2789
  password: formValues.password?.trim() || "0",
2544
- userId: user?.user?.uid || "0",
2790
+ userId: user?.user_id || "0",
2545
2791
  projectId: metadata?.projectId || "0",
2546
2792
  privateKey: "0",
2547
2793
  alias,
@@ -2550,7 +2796,7 @@ var IntegrationForm = ({
2550
2796
  }
2551
2797
  };
2552
2798
  const testResult = await testCredentials(linkToken, { ...credential });
2553
- if (!testResult?.value?.valid) {
2799
+ if (!testResult?.valid) {
2554
2800
  setErrorMessage(
2555
2801
  testResult?.value?.message || "Credentials are invalid"
2556
2802
  );
@@ -2566,7 +2812,7 @@ var IntegrationForm = ({
2566
2812
  logo: metadata.logo || null,
2567
2813
  startTime: null,
2568
2814
  endTime: null,
2569
- uid: user?.user?.uid || "",
2815
+ uid: user?.user_id || "",
2570
2816
  walletId,
2571
2817
  clientMetadata: {
2572
2818
  clientId,
@@ -2617,24 +2863,24 @@ var IntegrationForm = ({
2617
2863
  };
2618
2864
  const hasNoFields = !metadata.password && !metadata.secret_key && !metadata.api_key && !metadata.address && !metadata.account_name;
2619
2865
  const shouldShowFormFields = metadata.password || metadata.secret_key || metadata.api_key || metadata.address || metadata.account_name;
2620
- const renderLogo = () => metadata.logo ? /* @__PURE__ */ React25.createElement(
2866
+ const renderLogo = () => metadata.logo ? /* @__PURE__ */ React30.createElement(
2621
2867
  Image2,
2622
2868
  {
2623
2869
  source: { uri: metadata.logo },
2624
- style: styles10.logo,
2870
+ style: styles14.logo,
2625
2871
  resizeMode: "contain"
2626
2872
  }
2627
- ) : /* @__PURE__ */ React25.createElement(
2628
- View10,
2873
+ ) : /* @__PURE__ */ React30.createElement(
2874
+ View14,
2629
2875
  {
2630
2876
  style: [
2631
- styles10.logoPlaceholder,
2877
+ styles14.logoPlaceholder,
2632
2878
  { backgroundColor: theme.colors.surface }
2633
2879
  ]
2634
2880
  },
2635
- /* @__PURE__ */ React25.createElement(Text10, { style: { color: theme.colors.text } }, metadata.name?.charAt(0) || "?")
2881
+ /* @__PURE__ */ React30.createElement(Text12, { style: { color: theme.colors.text } }, metadata.name?.charAt(0) || "?")
2636
2882
  );
2637
- const renderInput = (key, props) => /* @__PURE__ */ React25.createElement(
2883
+ const renderInput = (key, props) => /* @__PURE__ */ React30.createElement(
2638
2884
  Input,
2639
2885
  {
2640
2886
  placeholder: props.placeholder,
@@ -2646,33 +2892,33 @@ var IntegrationForm = ({
2646
2892
  secureTextEntry: props.secureTextEntry
2647
2893
  }
2648
2894
  );
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) => {
2895
+ const renderErrorAlert = () => errorMessage ? /* @__PURE__ */ React30.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ React30.createElement(AlertDescription, null, errorMessage)) : null;
2896
+ 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
2897
  const isSelected = selectedChains.has(chain.id);
2652
2898
  const hasError = chainErrors[chain.id];
2653
- return /* @__PURE__ */ React25.createElement(
2654
- TouchableOpacity4,
2899
+ return /* @__PURE__ */ React30.createElement(
2900
+ TouchableOpacity5,
2655
2901
  {
2656
2902
  onPress: () => toggleChainSelection(chain.id),
2657
- style: styles10.chainButton,
2903
+ style: styles14.chainButton,
2658
2904
  key: chain.id
2659
2905
  },
2660
- /* @__PURE__ */ React25.createElement(
2661
- View10,
2906
+ /* @__PURE__ */ React30.createElement(
2907
+ View14,
2662
2908
  {
2663
2909
  style: [
2664
- styles10.chainChip,
2910
+ styles14.chainChip,
2665
2911
  {
2666
2912
  backgroundColor: hasError ? theme.colors.errorLight : isSelected ? theme.colors.primary + "20" : theme.colors.surface,
2667
2913
  borderColor: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.border
2668
2914
  }
2669
2915
  ]
2670
2916
  },
2671
- /* @__PURE__ */ React25.createElement(
2672
- Text10,
2917
+ /* @__PURE__ */ React30.createElement(
2918
+ Text12,
2673
2919
  {
2674
2920
  style: [
2675
- styles10.chainName,
2921
+ styles14.chainName,
2676
2922
  {
2677
2923
  color: hasError ? theme.colors.error : isSelected ? theme.colors.primary : theme.colors.text
2678
2924
  }
@@ -2680,28 +2926,28 @@ var IntegrationForm = ({
2680
2926
  },
2681
2927
  chain.name
2682
2928
  ),
2683
- isSelected ? /* @__PURE__ */ React25.createElement(
2929
+ isSelected ? /* @__PURE__ */ React30.createElement(
2684
2930
  CloseIcon,
2685
2931
  {
2686
2932
  size: 12,
2687
2933
  color: hasError ? theme.colors.error : theme.colors.primary
2688
2934
  }
2689
- ) : /* @__PURE__ */ React25.createElement(PlusIcon, { size: 12, color: theme.colors.textSecondary })
2935
+ ) : /* @__PURE__ */ React30.createElement(PlusIcon, { size: 12, color: theme.colors.textSecondary })
2690
2936
  )
2691
2937
  );
2692
- }))), Object.keys(chainErrors).length > 0 && /* @__PURE__ */ React25.createElement(View10, { style: styles10.chainErrorsContainer }, /* @__PURE__ */ React25.createElement(
2693
- Text10,
2938
+ }))), Object.keys(chainErrors).length > 0 && /* @__PURE__ */ React30.createElement(View14, { style: styles14.chainErrorsContainer }, /* @__PURE__ */ React30.createElement(
2939
+ Text12,
2694
2940
  {
2695
- style: [styles10.chainErrorsTitle, { color: theme.colors.error }]
2941
+ style: [styles14.chainErrorsTitle, { color: theme.colors.error }]
2696
2942
  },
2697
2943
  "Errors:"
2698
2944
  ), Object.entries(chainErrors).map(([chainId, error]) => {
2699
2945
  const chain = userUsedChains.find((c) => c.id === chainId);
2700
- return /* @__PURE__ */ React25.createElement(
2701
- Text10,
2946
+ return /* @__PURE__ */ React30.createElement(
2947
+ Text12,
2702
2948
  {
2703
2949
  key: chainId,
2704
- style: [styles10.chainErrorItem, { color: theme.colors.error }]
2950
+ style: [styles14.chainErrorItem, { color: theme.colors.error }]
2705
2951
  },
2706
2952
  "\u2022 ",
2707
2953
  chain?.name,
@@ -2709,7 +2955,7 @@ var IntegrationForm = ({
2709
2955
  error
2710
2956
  );
2711
2957
  })));
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", {
2958
+ 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
2959
  placeholder: "Enter address",
2714
2960
  autoCapitalize: "none",
2715
2961
  autoCorrect: false
@@ -2725,27 +2971,27 @@ var IntegrationForm = ({
2725
2971
  }), metadata.password && renderInput("password", {
2726
2972
  placeholder: "Enter Password",
2727
2973
  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.")));
2974
+ })), 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
2975
  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,
2976
+ 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(
2977
+ TouchableOpacity5,
2732
2978
  {
2733
2979
  onPress: () => setAddIntegrationMode(null),
2734
- style: styles10.backButton
2980
+ style: styles14.backButton
2735
2981
  },
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(
2982
+ /* @__PURE__ */ React30.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
2983
+ ), /* @__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
2984
  Button,
2739
2985
  {
2740
2986
  variant: "outline",
2741
2987
  size: "lg",
2742
2988
  onPress: handleSubmit,
2743
2989
  loading: isLoading,
2744
- disabled: isLoading || !!formValues.address && userUsedChains.length > 0 && selectedChains.size === 0,
2745
- style: styles10.button
2990
+ disabled: isLoading || isFetchingChains || !!formValues.address && userUsedChains.length > 0 && selectedChains.size === 0,
2991
+ style: styles14.button
2746
2992
  },
2747
2993
  addIntegrationLabel
2748
- ))) : /* @__PURE__ */ React25.createElement(
2994
+ ), /* @__PURE__ */ React30.createElement(Footer, null))) : /* @__PURE__ */ React30.createElement(
2749
2995
  WalletConnectComponent,
2750
2996
  {
2751
2997
  integration: metadata,
@@ -2757,7 +3003,7 @@ var IntegrationForm = ({
2757
3003
  }
2758
3004
  ));
2759
3005
  };
2760
- var styles10 = StyleSheet10.create({
3006
+ var styles14 = StyleSheet14.create({
2761
3007
  scrollViewContent: {
2762
3008
  flexGrow: 1,
2763
3009
  paddingBottom: 100
@@ -2874,66 +3120,9 @@ var styles10 = StyleSheet10.create({
2874
3120
  // theme.spacing.xs
2875
3121
  },
2876
3122
  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"
3123
+ width: "100%"
2934
3124
  }
2935
3125
  });
2936
- var SkeletonItem_default = SkeletonItem;
2937
3126
 
2938
3127
  // src/molecules/Integration.tsx
2939
3128
  var Integration = ({
@@ -2943,13 +3132,14 @@ var Integration = ({
2943
3132
  }) => {
2944
3133
  const { appName, linkToken } = useKryptosConnect();
2945
3134
  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("");
3135
+ const [addIntegrationMode, setAddIntegrationMode] = React31.useState(null);
3136
+ const [query, setQuery] = React31.useState("");
3137
+ const [activeTab, setActiveTab] = React31.useState("all");
3138
+ const [supportedProviders, setSupportedProviders] = React31.useState([]);
3139
+ const [addedIntegrations, setAddedIntegrations] = React31.useState([]);
3140
+ const [existingIntegrations, setExistingIntegrations] = React31.useState([]);
3141
+ const [isLoading, setIsLoading] = React31.useState(false);
3142
+ const [errorMessage, setErrorMessage] = React31.useState("");
2953
3143
  const handleClose = () => {
2954
3144
  onClose();
2955
3145
  };
@@ -2980,13 +3170,13 @@ var Integration = ({
2980
3170
  setIsLoading(false);
2981
3171
  }
2982
3172
  };
2983
- React27.useEffect(() => {
3173
+ React31.useEffect(() => {
2984
3174
  if (linkToken) {
2985
3175
  fetchSupportedProviders();
2986
3176
  fetchExistingIntegrations();
2987
3177
  }
2988
3178
  }, [linkToken]);
2989
- const isIntegrationAdded = React27.useCallback(
3179
+ const isIntegrationAdded = React31.useCallback(
2990
3180
  (publicName) => {
2991
3181
  const integrations = [...addedIntegrations, ...existingIntegrations];
2992
3182
  return integrations.some(
@@ -2995,7 +3185,7 @@ var Integration = ({
2995
3185
  },
2996
3186
  [addedIntegrations, existingIntegrations]
2997
3187
  );
2998
- const getIntegrationCount = React27.useCallback(
3188
+ const getIntegrationCount = React31.useCallback(
2999
3189
  (publicName) => {
3000
3190
  const integrations = [...addedIntegrations, ...existingIntegrations];
3001
3191
  return integrations.filter(
@@ -3004,22 +3194,24 @@ var Integration = ({
3004
3194
  },
3005
3195
  [addedIntegrations, existingIntegrations]
3006
3196
  );
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
- );
3197
+ const filteredResults = React31.useMemo(() => {
3198
+ let filtered = supportedProviders;
3199
+ if (activeTab !== "all") {
3200
+ filtered = filtered.filter((provider) => provider.type === activeTab);
3013
3201
  }
3014
- return [...supportedProviders].sort((a, b) => {
3202
+ if (query?.trim()) {
3203
+ const lowerQuery = query.trim().toLowerCase();
3204
+ filtered = filtered.filter((provider) => {
3205
+ return provider.name?.toLowerCase().includes(lowerQuery) || provider.public_name?.toLowerCase().includes(lowerQuery) || provider.id?.toLowerCase().includes(lowerQuery);
3206
+ });
3207
+ }
3208
+ return [...filtered].sort((a, b) => {
3015
3209
  const countA = getIntegrationCount(a.public_name);
3016
3210
  const countB = getIntegrationCount(b.public_name);
3017
- if (countB !== countA) {
3018
- return countB - countA;
3019
- }
3020
- return a.name.localeCompare(b.name);
3211
+ if (countB !== countA) return countB - countA;
3212
+ return (a.name ?? "").localeCompare(b.name ?? "");
3021
3213
  });
3022
- }, [query, supportedProviders, getIntegrationCount]);
3214
+ }, [query, supportedProviders, getIntegrationCount, activeTab]);
3023
3215
  const handleAddIntegration = async () => {
3024
3216
  try {
3025
3217
  setIsLoading(true);
@@ -3042,11 +3234,11 @@ var Integration = ({
3042
3234
  setIsLoading(false);
3043
3235
  }
3044
3236
  };
3045
- const renderProviderItem = ({ item }) => /* @__PURE__ */ React27.createElement(
3046
- TouchableOpacity5,
3237
+ const renderProviderItem = ({ item }) => /* @__PURE__ */ React31.createElement(
3238
+ TouchableOpacity6,
3047
3239
  {
3048
3240
  style: [
3049
- styles12.providerItem,
3241
+ styles15.providerItem,
3050
3242
  {
3051
3243
  backgroundColor: theme.colors.surface,
3052
3244
  borderColor: theme.colors.border
@@ -3055,43 +3247,43 @@ var Integration = ({
3055
3247
  onPress: () => setAddIntegrationMode(item),
3056
3248
  activeOpacity: 0.7
3057
3249
  },
3058
- /* @__PURE__ */ React27.createElement(View12, { style: styles12.providerInfo }, item?.logo ? /* @__PURE__ */ React27.createElement(
3250
+ /* @__PURE__ */ React31.createElement(View15, { style: styles15.providerInfo }, item?.logo ? /* @__PURE__ */ React31.createElement(
3059
3251
  Image3,
3060
3252
  {
3061
3253
  source: { uri: item?.logo },
3062
- style: styles12.providerLogo,
3254
+ style: styles15.providerLogo,
3063
3255
  resizeMode: "contain"
3064
3256
  }
3065
- ) : /* @__PURE__ */ React27.createElement(
3066
- View12,
3257
+ ) : /* @__PURE__ */ React31.createElement(
3258
+ View15,
3067
3259
  {
3068
3260
  style: [
3069
- styles12.providerLogoPlaceholder,
3261
+ styles15.providerLogoPlaceholder,
3070
3262
  { backgroundColor: theme.colors.surfaceSecondary }
3071
3263
  ]
3072
3264
  },
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,
3265
+ /* @__PURE__ */ React31.createElement(Text13, { style: { color: theme.colors.text } }, item?.name?.charAt(0) || "?")
3266
+ ), /* @__PURE__ */ React31.createElement(Text13, { style: [styles15.providerName, { color: theme.colors.text }] }, item?.name + "\u200B")),
3267
+ isIntegrationAdded(item?.public_name) && /* @__PURE__ */ React31.createElement(View15, { style: styles15.providerStatus }, /* @__PURE__ */ React31.createElement(CheckCircleIcon, { size: 18, color: theme.colors.success }), /* @__PURE__ */ React31.createElement(
3268
+ Text13,
3077
3269
  {
3078
3270
  style: [
3079
- styles12.providerCount,
3271
+ styles15.providerCount,
3080
3272
  { color: theme.colors.textSecondary }
3081
3273
  ]
3082
3274
  },
3083
3275
  getIntegrationCount(item?.public_name)
3084
3276
  ))
3085
3277
  );
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,
3278
+ const renderSkeletonItem = () => /* @__PURE__ */ React31.createElement(SkeletonItem_default, null);
3279
+ 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(
3280
+ TouchableOpacity6,
3089
3281
  {
3090
3282
  onPress: () => setAddIntegrationMode(null),
3091
- style: styles12.backButton
3283
+ style: styles15.backButton
3092
3284
  },
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(
3285
+ /* @__PURE__ */ React31.createElement(ArrowLeftIcon, { size: 20, color: theme.colors.text })
3286
+ ), /* @__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
3287
  FlatList,
3096
3288
  {
3097
3289
  data: isLoading ? Array.from({ length: 8 }, (_, i) => ({
@@ -3102,14 +3294,14 @@ var Integration = ({
3102
3294
  })) : filteredResults,
3103
3295
  keyExtractor: (item, index) => isLoading ? item.id : `provider-${item.id}-${index}`,
3104
3296
  renderItem: isLoading ? renderSkeletonItem : renderProviderItem,
3105
- style: styles12.list,
3297
+ style: styles15.list,
3106
3298
  contentContainerStyle: [
3107
- styles12.listContent,
3299
+ styles15.listContent,
3108
3300
  { paddingHorizontal: theme.spacing.xl }
3109
3301
  ],
3110
3302
  showsVerticalScrollIndicator: false,
3111
- ListHeaderComponent: /* @__PURE__ */ React27.createElement(
3112
- View12,
3303
+ ListHeaderComponent: /* @__PURE__ */ React31.createElement(
3304
+ View15,
3113
3305
  {
3114
3306
  style: {
3115
3307
  paddingVertical: theme.spacing.sm + 2,
@@ -3117,29 +3309,63 @@ var Integration = ({
3117
3309
  zIndex: 10
3118
3310
  }
3119
3311
  },
3120
- /* @__PURE__ */ React27.createElement(
3312
+ /* @__PURE__ */ React31.createElement(
3121
3313
  Input,
3122
3314
  {
3123
3315
  value: query,
3124
3316
  onChangeText: setQuery,
3125
3317
  placeholder: "Search Integrations...",
3126
- containerStyle: styles12.searchInput
3318
+ containerStyle: styles15.searchInput
3127
3319
  }
3128
- )
3320
+ ),
3321
+ /* @__PURE__ */ React31.createElement(View15, { style: styles15.tabsContainer }, [
3322
+ { label: "All", value: "all" },
3323
+ { label: "Exchanges", value: "exchange" },
3324
+ { label: "Blockchains", value: "blockchain" },
3325
+ { label: "Wallets", value: "wallet" }
3326
+ ].map((tab) => /* @__PURE__ */ React31.createElement(
3327
+ TouchableOpacity6,
3328
+ {
3329
+ key: tab.value,
3330
+ style: [
3331
+ styles15.tab,
3332
+ {
3333
+ backgroundColor: activeTab === tab.value ? theme.colors.primary : theme.colors.surface,
3334
+ borderColor: theme.colors.border
3335
+ }
3336
+ ],
3337
+ onPress: () => setActiveTab(
3338
+ tab.value
3339
+ ),
3340
+ activeOpacity: 0.7
3341
+ },
3342
+ /* @__PURE__ */ React31.createElement(
3343
+ Text13,
3344
+ {
3345
+ style: [
3346
+ styles15.tabText,
3347
+ {
3348
+ color: activeTab === tab.value ? theme.colors.white : theme.colors.text
3349
+ }
3350
+ ]
3351
+ },
3352
+ tab.label
3353
+ )
3354
+ )))
3129
3355
  ),
3130
3356
  stickyHeaderIndices: [0],
3131
- ListEmptyComponent: /* @__PURE__ */ React27.createElement(View12, { style: styles12.emptyContainer }, !isLoading && /* @__PURE__ */ React27.createElement(
3132
- Text11,
3357
+ ListEmptyComponent: /* @__PURE__ */ React31.createElement(View15, { style: styles15.emptyContainer }, !isLoading && /* @__PURE__ */ React31.createElement(
3358
+ Text13,
3133
3359
  {
3134
3360
  style: [
3135
- styles12.emptyText,
3361
+ styles15.emptyText,
3136
3362
  { color: theme.colors.textSecondary }
3137
3363
  ]
3138
3364
  },
3139
3365
  query ? "No search results found" : "No supported integrations found"
3140
3366
  ))
3141
3367
  }
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(
3368
+ ), 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
3369
  Button,
3144
3370
  {
3145
3371
  variant: "outline",
@@ -3147,10 +3373,10 @@ var Integration = ({
3147
3373
  onPress: handleAddIntegration,
3148
3374
  loading: isLoading,
3149
3375
  disabled: isLoading,
3150
- style: styles12.continueButton
3376
+ style: styles15.continueButton
3151
3377
  },
3152
3378
  "Continue"
3153
- ))) : /* @__PURE__ */ React27.createElement(
3379
+ ), /* @__PURE__ */ React31.createElement(Footer, null))) : /* @__PURE__ */ React31.createElement(
3154
3380
  IntegrationForm,
3155
3381
  {
3156
3382
  metadata: addIntegrationMode,
@@ -3164,7 +3390,7 @@ var Integration = ({
3164
3390
  }
3165
3391
  ));
3166
3392
  };
3167
- var styles12 = StyleSheet12.create({
3393
+ var styles15 = StyleSheet15.create({
3168
3394
  headerContent: {
3169
3395
  flexDirection: "row",
3170
3396
  alignItems: "center"
@@ -3187,10 +3413,9 @@ var styles12 = StyleSheet12.create({
3187
3413
  flex: 1
3188
3414
  },
3189
3415
  headerSection: {
3190
- paddingHorizontal: 20,
3191
- // theme.spacing.xl
3192
- paddingTop: 10
3416
+ paddingHorizontal: 20
3193
3417
  // theme.spacing.xl
3418
+ // paddingTop: 10, // theme.spacing.xl
3194
3419
  },
3195
3420
  title: {
3196
3421
  fontSize: 16,
@@ -3279,25 +3504,47 @@ var styles12 = StyleSheet12.create({
3279
3504
  errorAlert: {
3280
3505
  marginTop: 16
3281
3506
  // theme.spacing.lg - consistent alert spacing
3507
+ },
3508
+ tabsContainer: {
3509
+ flexDirection: "row",
3510
+ gap: 4,
3511
+ // theme.spacing.sm
3512
+ flexWrap: "wrap"
3513
+ },
3514
+ tab: {
3515
+ paddingVertical: 8,
3516
+ // theme.spacing.sm
3517
+ paddingHorizontal: 16,
3518
+ // theme.spacing.lg
3519
+ borderRadius: 20,
3520
+ // theme.borderRadius.full / 2
3521
+ borderWidth: 1,
3522
+ alignItems: "center",
3523
+ justifyContent: "center"
3524
+ },
3525
+ tabText: {
3526
+ fontSize: 13,
3527
+ // theme.fontSize.sm
3528
+ fontWeight: "600"
3282
3529
  }
3283
3530
  });
3284
3531
 
3285
3532
  // 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";
3533
+ import React32 from "react";
3534
+ import { StyleSheet as StyleSheet16, Text as Text14, TouchableOpacity as TouchableOpacity7, View as View16 } from "react-native";
3288
3535
  var OTPVerify = ({
3289
3536
  open,
3290
3537
  onSuccess,
3291
3538
  onClose
3292
3539
  }) => {
3293
3540
  const theme = useTheme();
3294
- const [otp, setOtp] = React28.useState("");
3541
+ const [otp, setOtp] = React32.useState("");
3295
3542
  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("");
3543
+ const [isLoading, setIsLoading] = React32.useState(false);
3544
+ const [isResending, setIsResending] = React32.useState(false);
3545
+ const [resendCooldown, setResendCooldown] = React32.useState(0);
3546
+ const [errorMessage, setErrorMessage] = React32.useState("");
3547
+ const [successMessage, setSuccessMessage] = React32.useState("");
3301
3548
  const handleSubmit = async () => {
3302
3549
  if (otp.length !== 6) return;
3303
3550
  setIsLoading(true);
@@ -3348,7 +3595,7 @@ var OTPVerify = ({
3348
3595
  setSuccessMessage("");
3349
3596
  setOtp("");
3350
3597
  };
3351
- React28.useEffect(() => {
3598
+ React32.useEffect(() => {
3352
3599
  if (resendCooldown > 0) {
3353
3600
  const timer = setTimeout(() => {
3354
3601
  setResendCooldown(resendCooldown - 1);
@@ -3357,13 +3604,20 @@ var OTPVerify = ({
3357
3604
  }
3358
3605
  return void 0;
3359
3606
  }, [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,
3607
+ 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(
3608
+ Text14,
3362
3609
  {
3363
- style: [styles13.infoText, { color: theme.colors.textSecondary }]
3610
+ style: [styles16.infoText, { color: theme.colors.textSecondary }]
3364
3611
  },
3365
3612
  "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(
3613
+ ), /* @__PURE__ */ React32.createElement(Text14, { style: [styles16.emailText, { color: theme.colors.text }] }, email)), /* @__PURE__ */ React32.createElement(
3614
+ OTP,
3615
+ {
3616
+ onComplete: handleOtpComplete,
3617
+ length: 6,
3618
+ setErrorMessage
3619
+ }
3620
+ ), 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
3621
  Button,
3368
3622
  {
3369
3623
  variant: "outline",
@@ -3371,44 +3625,44 @@ var OTPVerify = ({
3371
3625
  onPress: handleSubmit,
3372
3626
  loading: isLoading,
3373
3627
  disabled: otp.length !== 6 || isLoading,
3374
- style: styles13.button
3628
+ style: styles16.button
3375
3629
  },
3376
3630
  "Continue"
3377
- ), /* @__PURE__ */ React28.createElement(
3378
- TouchableOpacity6,
3631
+ ), /* @__PURE__ */ React32.createElement(
3632
+ TouchableOpacity7,
3379
3633
  {
3380
3634
  onPress: handleResendOtp,
3381
3635
  disabled: resendCooldown > 0 || isResending,
3382
- style: styles13.resendContainer
3636
+ style: styles16.resendContainer
3383
3637
  },
3384
- isResending ? /* @__PURE__ */ React28.createElement(View13, { style: styles13.resendLoading }, /* @__PURE__ */ React28.createElement(LoaderIcon, { size: 16, color: theme.colors.primary }), /* @__PURE__ */ React28.createElement(
3385
- Text12,
3638
+ isResending ? /* @__PURE__ */ React32.createElement(View16, { style: styles16.resendLoading }, /* @__PURE__ */ React32.createElement(LoaderIcon, { size: 16, color: theme.colors.primary }), /* @__PURE__ */ React32.createElement(
3639
+ Text14,
3386
3640
  {
3387
- style: [styles13.resendText, { color: theme.colors.primary }]
3641
+ style: [styles16.resendText, { color: theme.colors.primary }]
3388
3642
  },
3389
3643
  " ",
3390
3644
  "Sending..."
3391
- )) : resendCooldown > 0 ? /* @__PURE__ */ React28.createElement(
3392
- Text12,
3645
+ )) : resendCooldown > 0 ? /* @__PURE__ */ React32.createElement(
3646
+ Text14,
3393
3647
  {
3394
3648
  style: [
3395
- styles13.resendText,
3649
+ styles16.resendText,
3396
3650
  { color: theme.colors.textSecondary }
3397
3651
  ]
3398
3652
  },
3399
3653
  "Resend OTP in ",
3400
3654
  resendCooldown,
3401
3655
  "s"
3402
- ) : /* @__PURE__ */ React28.createElement(
3403
- Text12,
3656
+ ) : /* @__PURE__ */ React32.createElement(
3657
+ Text14,
3404
3658
  {
3405
- style: [styles13.resendText, { color: theme.colors.primary }]
3659
+ style: [styles16.resendText, { color: theme.colors.primary }]
3406
3660
  },
3407
3661
  "Resend OTP"
3408
3662
  )
3409
- ))));
3663
+ ))), /* @__PURE__ */ React32.createElement(ModalFooter, { style: { paddingVertical: 0 } }, /* @__PURE__ */ React32.createElement(Footer, null)));
3410
3664
  };
3411
- var styles13 = StyleSheet13.create({
3665
+ var styles16 = StyleSheet16.create({
3412
3666
  headerContent: {
3413
3667
  flexDirection: "row",
3414
3668
  alignItems: "center"
@@ -3467,8 +3721,8 @@ var styles13 = StyleSheet13.create({
3467
3721
  });
3468
3722
 
3469
3723
  // src/molecules/Permissions.tsx
3470
- import React29 from "react";
3471
- import { View as View14, Text as Text13, StyleSheet as StyleSheet14 } from "react-native";
3724
+ import React33 from "react";
3725
+ import { StyleSheet as StyleSheet17, Text as Text15, View as View17 } from "react-native";
3472
3726
  var Permissions = ({
3473
3727
  open,
3474
3728
  onClose,
@@ -3476,8 +3730,8 @@ var Permissions = ({
3476
3730
  }) => {
3477
3731
  const { appName, linkToken, setUserConsent } = useKryptosConnect();
3478
3732
  const theme = useTheme();
3479
- const [isLoading, setIsLoading] = React29.useState(false);
3480
- const [errorMessage, setErrorMessage] = React29.useState("");
3733
+ const [isLoading, setIsLoading] = React33.useState(false);
3734
+ const [errorMessage, setErrorMessage] = React33.useState("");
3481
3735
  const handleConsentClick = async () => {
3482
3736
  try {
3483
3737
  setIsLoading(true);
@@ -3500,42 +3754,42 @@ var Permissions = ({
3500
3754
  "Access your transaction history and trading activity",
3501
3755
  "Keep this data updated and accessible when you're offline"
3502
3756
  ];
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,
3757
+ 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(
3758
+ Text15,
3505
3759
  {
3506
- style: [styles14.subtitle, { color: theme.colors.textSecondary }]
3760
+ style: [styles17.subtitle, { color: theme.colors.textSecondary }]
3507
3761
  },
3508
3762
  "Allow ",
3509
3763
  appName,
3510
3764
  " 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,
3765
+ ), 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(
3766
+ Text15,
3513
3767
  {
3514
- style: [styles14.permissionText, { color: theme.colors.text }]
3768
+ style: [styles17.permissionText, { color: theme.colors.text }]
3515
3769
  },
3516
3770
  item
3517
- )))), /* @__PURE__ */ React29.createElement(
3518
- View14,
3771
+ )))), /* @__PURE__ */ React33.createElement(
3772
+ View17,
3519
3773
  {
3520
3774
  style: [
3521
- styles14.infoBox,
3775
+ styles17.infoBox,
3522
3776
  {
3523
3777
  backgroundColor: theme.colors.surface,
3524
3778
  borderColor: theme.colors.border
3525
3779
  }
3526
3780
  ]
3527
3781
  },
3528
- /* @__PURE__ */ React29.createElement(
3529
- Text13,
3782
+ /* @__PURE__ */ React33.createElement(
3783
+ Text15,
3530
3784
  {
3531
- style: [styles14.infoText, { color: theme.colors.textSecondary }]
3785
+ style: [styles17.infoText, { color: theme.colors.textSecondary }]
3532
3786
  },
3533
3787
  "By selecting",
3534
3788
  " ",
3535
- /* @__PURE__ */ React29.createElement(Text13, { style: { fontWeight: "600", color: theme.colors.text } }, "'Allow'"),
3789
+ /* @__PURE__ */ React33.createElement(Text15, { style: { fontWeight: "600", color: theme.colors.text } }, "'Allow'"),
3536
3790
  ", you agree to share this information and keep it updated."
3537
3791
  )
3538
- ))), /* @__PURE__ */ React29.createElement(ModalFooter, null, /* @__PURE__ */ React29.createElement(
3792
+ ))), /* @__PURE__ */ React33.createElement(ModalFooter, { style: { paddingVertical: 8 } }, /* @__PURE__ */ React33.createElement(
3539
3793
  Button,
3540
3794
  {
3541
3795
  variant: "outline",
@@ -3543,12 +3797,12 @@ var Permissions = ({
3543
3797
  onPress: handleConsentClick,
3544
3798
  loading: isLoading,
3545
3799
  disabled: isLoading,
3546
- style: styles14.button
3800
+ style: styles17.button
3547
3801
  },
3548
3802
  "Allow"
3549
- )));
3803
+ ), /* @__PURE__ */ React33.createElement(Footer, null)));
3550
3804
  };
3551
- var styles14 = StyleSheet14.create({
3805
+ var styles17 = StyleSheet17.create({
3552
3806
  container: {
3553
3807
  flex: 1
3554
3808
  },
@@ -3606,8 +3860,8 @@ var styles14 = StyleSheet14.create({
3606
3860
  });
3607
3861
 
3608
3862
  // src/molecules/StatusModal.tsx
3609
- import React30 from "react";
3610
- import { View as View15, Text as Text14, StyleSheet as StyleSheet15 } from "react-native";
3863
+ import React34 from "react";
3864
+ import { StyleSheet as StyleSheet18, Text as Text16, View as View18 } from "react-native";
3611
3865
  var StatusModal = ({
3612
3866
  open,
3613
3867
  onClose,
@@ -3624,18 +3878,18 @@ var StatusModal = ({
3624
3878
  }
3625
3879
  onClose();
3626
3880
  };
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(
3881
+ 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
3882
  Button,
3629
3883
  {
3630
3884
  variant: "outline",
3631
3885
  size: "lg",
3632
3886
  onPress: status === "success" ? onSuccess : onError,
3633
- style: styles15.button
3887
+ style: styles18.button
3634
3888
  },
3635
3889
  status === "success" ? "Continue" : "Try again later"
3636
- ))));
3890
+ ), /* @__PURE__ */ React34.createElement(Footer, null)));
3637
3891
  };
3638
- var styles15 = StyleSheet15.create({
3892
+ var styles18 = StyleSheet18.create({
3639
3893
  container: {
3640
3894
  flex: 1,
3641
3895
  alignItems: "center",
@@ -3659,6 +3913,64 @@ var styles15 = StyleSheet15.create({
3659
3913
  }
3660
3914
  });
3661
3915
 
3916
+ // src/molecules/EndModal.tsx
3917
+ import React35, { useEffect as useEffect2 } from "react";
3918
+ import { StyleSheet as StyleSheet19, Text as Text17, View as View19 } from "react-native";
3919
+ var EndModal = ({ open, onClose }) => {
3920
+ const theme = useTheme();
3921
+ useEffect2(() => {
3922
+ if (!open) return;
3923
+ const timer = setTimeout(() => {
3924
+ onClose();
3925
+ }, 5e3);
3926
+ return () => clearTimeout(timer);
3927
+ }, []);
3928
+ 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(
3929
+ View19,
3930
+ {
3931
+ style: [
3932
+ styles19.iconContainer,
3933
+ { backgroundColor: theme.colors.successLight }
3934
+ ]
3935
+ },
3936
+ /* @__PURE__ */ React35.createElement(SuccessIcon, { size: 80 })
3937
+ ), /* @__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
3938
+ than expected, tap the button below to continue.`))), /* @__PURE__ */ React35.createElement(ModalFooter, { style: { paddingVertical: 8 } }, /* @__PURE__ */ React35.createElement(
3939
+ Button,
3940
+ {
3941
+ variant: "primary",
3942
+ size: "lg",
3943
+ onPress: onClose,
3944
+ style: styles19.button
3945
+ },
3946
+ "Continue to App"
3947
+ ), /* @__PURE__ */ React35.createElement(Footer, null)));
3948
+ };
3949
+ var styles19 = StyleSheet19.create({
3950
+ container: {
3951
+ alignItems: "center",
3952
+ paddingVertical: 20
3953
+ },
3954
+ iconContainer: {
3955
+ width: 80,
3956
+ height: 80,
3957
+ borderRadius: 40,
3958
+ alignItems: "center",
3959
+ justifyContent: "center",
3960
+ marginBottom: 20
3961
+ },
3962
+ message: {
3963
+ fontSize: 14,
3964
+ textAlign: "center",
3965
+ lineHeight: 20,
3966
+ marginBottom: 24,
3967
+ paddingHorizontal: 20
3968
+ },
3969
+ button: {
3970
+ width: "100%"
3971
+ }
3972
+ });
3973
+
3662
3974
  // src/KryptosConnectButton.tsx
3663
3975
  var KryptosConnectButton = ({
3664
3976
  children,
@@ -3669,14 +3981,14 @@ var KryptosConnectButton = ({
3669
3981
  textStyle
3670
3982
  }) => {
3671
3983
  const { theme: themeName } = useKryptosConnect();
3672
- const [open, setOpen] = React31.useState(false);
3984
+ const [open, setOpen] = React36.useState(false);
3673
3985
  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,
3986
+ return /* @__PURE__ */ React36.createElement(React36.Fragment, null, children ? /* @__PURE__ */ React36.createElement(TouchableOpacity8, { onPress: () => setOpen(true), style }, children) : /* @__PURE__ */ React36.createElement(
3987
+ TouchableOpacity8,
3676
3988
  {
3677
3989
  onPress: () => setOpen(true),
3678
3990
  style: [
3679
- styles16.defaultButton,
3991
+ styles20.defaultButton,
3680
3992
  themeName === "light" ? {
3681
3993
  backgroundColor: theme.colors.white,
3682
3994
  borderRadius: theme.borderRadius.md,
@@ -3690,11 +4002,11 @@ var KryptosConnectButton = ({
3690
4002
  ],
3691
4003
  activeOpacity: 0.8
3692
4004
  },
3693
- /* @__PURE__ */ React31.createElement(
3694
- Text15,
4005
+ /* @__PURE__ */ React36.createElement(
4006
+ Text18,
3695
4007
  {
3696
4008
  style: [
3697
- styles16.buttonText,
4009
+ styles20.buttonText,
3698
4010
  {
3699
4011
  color: themeName === "light" ? theme.colors.primary : theme.colors.white,
3700
4012
  fontSize: theme.fontSize.lg
@@ -3705,8 +4017,8 @@ var KryptosConnectButton = ({
3705
4017
  "Connect with",
3706
4018
  " "
3707
4019
  ),
3708
- /* @__PURE__ */ React31.createElement(LogoIcon, { size: 24 })
3709
- ), /* @__PURE__ */ React31.createElement(
4020
+ /* @__PURE__ */ React36.createElement(LogoIcon, { size: 24 })
4021
+ ), /* @__PURE__ */ React36.createElement(
3710
4022
  KryptosConnectModal,
3711
4023
  {
3712
4024
  open,
@@ -3730,9 +4042,11 @@ var KryptosConnectModal = ({
3730
4042
  setUserConsent,
3731
4043
  setUser,
3732
4044
  setEmail,
3733
- setLinkToken
4045
+ setLinkToken,
4046
+ isAuthorized,
4047
+ linkToken
3734
4048
  } = useKryptosConnect();
3735
- const [step, setStep] = React31.useState("INIT" /* INIT */);
4049
+ const [step, setStep] = React36.useState("INIT" /* INIT */);
3736
4050
  const handleClose = () => {
3737
4051
  setOpen(false);
3738
4052
  setIsInitialized(false);
@@ -3750,12 +4064,25 @@ var KryptosConnectModal = ({
3750
4064
  onError?.(userConsent);
3751
4065
  handleClose();
3752
4066
  };
4067
+ const handleConsentClick = async () => {
4068
+ try {
4069
+ if (isAuthorized) {
4070
+ setStep("END" /* END */);
4071
+ return;
4072
+ }
4073
+ const res = await giveUserConsent(linkToken);
4074
+ setUserConsent(res);
4075
+ setStep("STATUS" /* STATUS */);
4076
+ } catch (error) {
4077
+ console.error(error);
4078
+ }
4079
+ };
3753
4080
  const handleAbort = () => {
3754
4081
  onError?.(new Error("User closed the modal"));
3755
4082
  handleClose();
3756
4083
  };
3757
4084
  if (!open) return null;
3758
- return /* @__PURE__ */ React31.createElement(View16, { style: styles16.container }, step === "INIT" /* INIT */ && /* @__PURE__ */ React31.createElement(
4085
+ return /* @__PURE__ */ React36.createElement(View20, { style: styles20.container }, step === "INIT" /* INIT */ && /* @__PURE__ */ React36.createElement(
3759
4086
  Init,
3760
4087
  {
3761
4088
  open,
@@ -3769,7 +4096,7 @@ var KryptosConnectModal = ({
3769
4096
  },
3770
4097
  onClose: handleAbort
3771
4098
  }
3772
- ), step === "AUTH" /* AUTH */ && /* @__PURE__ */ React31.createElement(
4099
+ ), step === "AUTH" /* AUTH */ && /* @__PURE__ */ React36.createElement(
3773
4100
  Auth,
3774
4101
  {
3775
4102
  open,
@@ -3777,28 +4104,28 @@ var KryptosConnectModal = ({
3777
4104
  onGuestSuccess: () => setStep("INTEGRATION" /* INTEGRATION */),
3778
4105
  onClose: handleAbort
3779
4106
  }
3780
- ), step === "OTP" /* OTP */ && /* @__PURE__ */ React31.createElement(
4107
+ ), step === "OTP" /* OTP */ && /* @__PURE__ */ React36.createElement(
3781
4108
  OTPVerify,
3782
4109
  {
3783
4110
  open,
3784
4111
  onSuccess: () => setStep("INTEGRATION" /* INTEGRATION */),
3785
4112
  onClose: handleAbort
3786
4113
  }
3787
- ), step === "INTEGRATION" /* INTEGRATION */ && /* @__PURE__ */ React31.createElement(
4114
+ ), step === "INTEGRATION" /* INTEGRATION */ && /* @__PURE__ */ React36.createElement(
3788
4115
  Integration,
3789
4116
  {
3790
4117
  open,
3791
- onSuccess: () => setStep("PERMISSIONS" /* PERMISSIONS */),
4118
+ onSuccess: handleConsentClick,
3792
4119
  onClose: handleAbort
3793
4120
  }
3794
- ), step === "PERMISSIONS" /* PERMISSIONS */ && /* @__PURE__ */ React31.createElement(
4121
+ ), step === "PERMISSIONS" /* PERMISSIONS */ && /* @__PURE__ */ React36.createElement(
3795
4122
  Permissions,
3796
4123
  {
3797
4124
  open,
3798
4125
  onClose: handleAbort,
3799
4126
  onSuccess: () => setStep("STATUS" /* STATUS */)
3800
4127
  }
3801
- ), step === "STATUS" /* STATUS */ && /* @__PURE__ */ React31.createElement(
4128
+ ), step === "STATUS" /* STATUS */ && /* @__PURE__ */ React36.createElement(
3802
4129
  StatusModal,
3803
4130
  {
3804
4131
  open,
@@ -3807,9 +4134,19 @@ var KryptosConnectModal = ({
3807
4134
  onError: handleError,
3808
4135
  status: userConsent?.public_token ? "success" : "error"
3809
4136
  }
4137
+ ), step === "END" /* END */ && /* @__PURE__ */ React36.createElement(
4138
+ EndModal,
4139
+ {
4140
+ open,
4141
+ onClose: () => {
4142
+ onSuccess?.(userConsent);
4143
+ setStep("INIT" /* INIT */);
4144
+ setOpen(false);
4145
+ }
4146
+ }
3810
4147
  ));
3811
4148
  };
3812
- var styles16 = StyleSheet16.create({
4149
+ var styles20 = StyleSheet20.create({
3813
4150
  defaultButton: {
3814
4151
  flexDirection: "row",
3815
4152
  alignItems: "center",