@paymanai/payman-ask-sdk 2.0.4 → 2.0.6

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.
@@ -1,17 +1,20 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
3
+ var React = require('react');
4
4
  var reactNative = require('react-native');
5
+ var paymanTypescriptAskSdk = require('@paymanai/payman-typescript-ask-sdk');
6
+ var lucideReactNative = require('lucide-react-native');
5
7
  var jsxRuntime = require('react/jsx-runtime');
8
+ var Markdown = require('react-native-markdown-display');
6
9
  var lucideReact = require('lucide-react');
7
10
  var framerMotion = require('framer-motion');
8
11
  var reactDom = require('react-dom');
9
12
  var clsx = require('clsx');
10
13
  var tailwindMerge = require('tailwind-merge');
11
- var paymanTypescriptAskSdk = require('@paymanai/payman-typescript-ask-sdk');
12
- var lucideReactNative = require('lucide-react-native');
13
14
  var Sentry = require('@sentry/react');
14
15
 
16
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
17
+
15
18
  function _interopNamespace(e) {
16
19
  if (e && e.__esModule) return e;
17
20
  var n = Object.create(null);
@@ -24,39 +27,3156 @@ function _interopNamespace(e) {
24
27
  get: function () { return e[k]; }
25
28
  });
26
29
  }
27
- });
30
+ });
31
+ }
32
+ n.default = e;
33
+ return Object.freeze(n);
34
+ }
35
+
36
+ var React__default = /*#__PURE__*/_interopDefault(React);
37
+ var Markdown__default = /*#__PURE__*/_interopDefault(Markdown);
38
+ var Sentry__namespace = /*#__PURE__*/_interopNamespace(Sentry);
39
+
40
+ // src/components/PaymanChat/index.native.tsx
41
+ var PAYMAN_TEAL = "#00858d";
42
+ var SEND_BUTTON_COLOR = "#15687d";
43
+ var SEND_BUTTON_DISABLED_COLOR = "#d1d5db";
44
+ var INPUT_BOTTOM_MARGIN = reactNative.Platform.OS === "ios" ? 18 : 8;
45
+ var LIGHT_PALETTE = {
46
+ surface: "#ffffff",
47
+ soft: "#f4f4f5",
48
+ border: "rgba(15,23,42,0.08)",
49
+ borderFocused: "rgba(15,23,42,0.16)",
50
+ textPrimary: "#0f172a",
51
+ textTertiary: "#94a3b8",
52
+ iconGrey: "#64748b",
53
+ disclaimer: "#94a3b8"
54
+ };
55
+ var DARK_PALETTE = {
56
+ surface: "#0d1719",
57
+ soft: "#162022",
58
+ border: "rgba(255,255,255,0.08)",
59
+ borderFocused: "rgba(255,255,255,0.18)",
60
+ textPrimary: "#f0f9fa",
61
+ textTertiary: "rgba(240,249,250,0.40)",
62
+ iconGrey: "rgba(240,249,250,0.55)",
63
+ disclaimer: "rgba(240,249,250,0.38)"
64
+ };
65
+ var INPUT_FONT_SIZE = 15;
66
+ var INPUT_LINE_HEIGHT = 22;
67
+ var INPUT_MAX_HEIGHT = INPUT_LINE_HEIGHT * 8;
68
+ var ANDROID_RIPPLE_DARK = { color: "rgba(15,23,42,0.10)", borderless: false };
69
+ var ANDROID_RIPPLE_LIGHT = { color: "rgba(255,255,255,0.20)", borderless: false };
70
+ var ChatInputV2 = React.forwardRef(
71
+ function ChatInputV22({
72
+ onSend,
73
+ disabled = false,
74
+ isStreaming = false,
75
+ placeholder = "Type your message\u2026",
76
+ enableVoice = false,
77
+ voiceAvailable = false,
78
+ isRecording = false,
79
+ onVoicePress,
80
+ showResetSession = false,
81
+ onResetSession,
82
+ hideSendButton = false,
83
+ showAttachmentButton,
84
+ showUploadImageButton = true,
85
+ showAttachFileButton = true,
86
+ onUploadImageClick,
87
+ onAttachFileClick,
88
+ hideDisclaimer = false,
89
+ theme = "light",
90
+ topAccessory
91
+ }, ref) {
92
+ const p = theme === "dark" ? DARK_PALETTE : LIGHT_PALETTE;
93
+ const [value, setValue] = React.useState("");
94
+ const [isFocused, setIsFocused] = React.useState(false);
95
+ const [isKeyboardVisible, setIsKeyboardVisible] = React.useState(false);
96
+ const [sheetOpen, setSheetOpen] = React.useState(false);
97
+ const textInputRef = React.useRef(null);
98
+ const hasAttachmentOptions = !!onUploadImageClick && showUploadImageButton || !!onAttachFileClick && showAttachFileButton;
99
+ const showAttachmentMenuButton = (showAttachmentButton ?? true) && hasAttachmentOptions;
100
+ React.useImperativeHandle(
101
+ ref,
102
+ () => ({
103
+ setDraft: (text) => {
104
+ setValue(text);
105
+ requestAnimationFrame(() => textInputRef.current?.focus());
106
+ },
107
+ focus: () => textInputRef.current?.focus()
108
+ }),
109
+ []
110
+ );
111
+ const handleSend = React.useCallback(() => {
112
+ const trimmed = value.trim();
113
+ if (!trimmed || disabled) return;
114
+ onSend(trimmed);
115
+ setValue("");
116
+ }, [value, disabled, onSend]);
117
+ const canSend = value.trim().length > 0 && !disabled;
118
+ const sendDisabled = !canSend || isStreaming;
119
+ const showVoiceButton = enableVoice && !!onVoicePress;
120
+ const isVoiceButtonDisabled = disabled || !voiceAvailable;
121
+ const hasTopAccessory = topAccessory != null;
122
+ const sendScale = React.useRef(new reactNative.Animated.Value(1)).current;
123
+ React.useEffect(() => {
124
+ reactNative.Animated.spring(sendScale, {
125
+ toValue: canSend && !isStreaming ? 1 : 0.94,
126
+ useNativeDriver: true,
127
+ friction: 6,
128
+ tension: 180
129
+ }).start();
130
+ }, [canSend, isStreaming, sendScale]);
131
+ const handleAttachmentPress = React.useCallback(() => {
132
+ if (disabled || isRecording) return;
133
+ setSheetOpen(true);
134
+ }, [disabled, isRecording]);
135
+ const closeSheet = React.useCallback(() => setSheetOpen(false), []);
136
+ React.useEffect(() => {
137
+ const showEvent = reactNative.Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow";
138
+ const hideEvent = reactNative.Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide";
139
+ const showSub = reactNative.Keyboard.addListener(showEvent, () => {
140
+ setIsKeyboardVisible(true);
141
+ });
142
+ const hideSub = reactNative.Keyboard.addListener(hideEvent, () => {
143
+ setIsKeyboardVisible(false);
144
+ });
145
+ return () => {
146
+ showSub.remove();
147
+ hideSub.remove();
148
+ };
149
+ }, []);
150
+ const handlePickImage = React.useCallback(() => {
151
+ closeSheet();
152
+ onUploadImageClick?.();
153
+ }, [closeSheet, onUploadImageClick]);
154
+ const handlePickFile = React.useCallback(() => {
155
+ closeSheet();
156
+ onAttachFileClick?.();
157
+ }, [closeSheet, onAttachFileClick]);
158
+ return /* @__PURE__ */ jsxRuntime.jsxs(
159
+ reactNative.View,
160
+ {
161
+ style: [
162
+ s.outer,
163
+ {
164
+ backgroundColor: p.surface,
165
+ marginBottom: isKeyboardVisible ? 0 : INPUT_BOTTOM_MARGIN
166
+ }
167
+ ],
168
+ children: [
169
+ hasTopAccessory ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s.topAccessory, children: topAccessory }) : null,
170
+ /* @__PURE__ */ jsxRuntime.jsxs(
171
+ reactNative.View,
172
+ {
173
+ style: [
174
+ s.wrapper,
175
+ hasTopAccessory && s.wrapperWithTopAccessory,
176
+ { backgroundColor: p.soft, borderColor: p.border },
177
+ (isFocused || isRecording) && { borderColor: p.borderFocused },
178
+ disabled && s.wrapperDisabled
179
+ ],
180
+ children: [
181
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s.inputRow, children: /* @__PURE__ */ jsxRuntime.jsx(
182
+ reactNative.TextInput,
183
+ {
184
+ ref: textInputRef,
185
+ style: [s.input, { color: p.textPrimary }],
186
+ value,
187
+ onChangeText: (t) => {
188
+ if (isRecording) return;
189
+ setValue(t);
190
+ },
191
+ onFocus: () => setIsFocused(true),
192
+ onBlur: () => setIsFocused(false),
193
+ placeholder: isRecording ? "Listening\u2026" : placeholder,
194
+ placeholderTextColor: p.textTertiary,
195
+ multiline: true,
196
+ editable: !disabled && !isRecording,
197
+ returnKeyType: "default",
198
+ blurOnSubmit: false,
199
+ scrollEnabled: true
200
+ }
201
+ ) }),
202
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s.controls, children: [
203
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s.leftControls, children: [
204
+ showResetSession && onResetSession ? /* @__PURE__ */ jsxRuntime.jsx(
205
+ reactNative.Pressable,
206
+ {
207
+ onPress: onResetSession,
208
+ disabled: isStreaming || isRecording,
209
+ style: [
210
+ s.iconBtn,
211
+ (isStreaming || isRecording) && s.iconBtnDisabled
212
+ ],
213
+ android_ripple: ANDROID_RIPPLE_DARK,
214
+ hitSlop: 6,
215
+ accessibilityLabel: "New session",
216
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.RotateCcw, { size: 18, color: p.iconGrey, strokeWidth: 2 })
217
+ }
218
+ ) : null,
219
+ showAttachmentMenuButton ? /* @__PURE__ */ jsxRuntime.jsx(
220
+ reactNative.Pressable,
221
+ {
222
+ onPress: handleAttachmentPress,
223
+ disabled: disabled || isRecording,
224
+ style: [
225
+ s.iconBtn,
226
+ (disabled || isRecording) && s.iconBtnDisabled
227
+ ],
228
+ android_ripple: ANDROID_RIPPLE_DARK,
229
+ hitSlop: 6,
230
+ accessibilityLabel: "Attach",
231
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Plus, { size: 20, color: p.iconGrey, strokeWidth: 2 })
232
+ }
233
+ ) : null
234
+ ] }),
235
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s.rightControls, children: [
236
+ showVoiceButton ? /* @__PURE__ */ jsxRuntime.jsx(
237
+ reactNative.Pressable,
238
+ {
239
+ onPress: onVoicePress,
240
+ disabled: isVoiceButtonDisabled,
241
+ style: [
242
+ s.iconBtn,
243
+ isRecording && s.iconBtnRecording,
244
+ isVoiceButtonDisabled && s.iconBtnDisabled
245
+ ],
246
+ android_ripple: ANDROID_RIPPLE_DARK,
247
+ hitSlop: 6,
248
+ accessibilityLabel: isRecording ? "Stop recording" : "Voice input",
249
+ children: /* @__PURE__ */ jsxRuntime.jsx(
250
+ lucideReactNative.Mic,
251
+ {
252
+ size: 18,
253
+ color: isRecording ? PAYMAN_TEAL : p.iconGrey,
254
+ strokeWidth: 2
255
+ }
256
+ )
257
+ }
258
+ ) : null,
259
+ !hideSendButton ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: { transform: [{ scale: sendScale }] }, children: /* @__PURE__ */ jsxRuntime.jsx(
260
+ reactNative.Pressable,
261
+ {
262
+ onPress: handleSend,
263
+ disabled: sendDisabled,
264
+ style: [s.sendBtn, sendDisabled && s.sendBtnIdle],
265
+ android_ripple: ANDROID_RIPPLE_LIGHT,
266
+ hitSlop: 4,
267
+ accessibilityLabel: "Send",
268
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ArrowUp, { size: 18, color: "#fff", strokeWidth: 2.75 })
269
+ }
270
+ ) }) : null
271
+ ] })
272
+ ] })
273
+ ]
274
+ }
275
+ ),
276
+ !hideDisclaimer ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [s.disclaimer, { color: p.disclaimer }], children: "AI can make mistakes. Please double-check responses." }) : null,
277
+ /* @__PURE__ */ jsxRuntime.jsx(
278
+ AttachmentSheet,
279
+ {
280
+ visible: sheetOpen,
281
+ onClose: closeSheet,
282
+ showImage: !!onUploadImageClick && showUploadImageButton,
283
+ showFile: !!onAttachFileClick && showAttachFileButton,
284
+ onPickImage: handlePickImage,
285
+ onPickFile: handlePickFile
286
+ }
287
+ )
288
+ ]
289
+ }
290
+ );
291
+ }
292
+ );
293
+ function AttachmentSheet({
294
+ visible,
295
+ onClose,
296
+ showImage,
297
+ showFile,
298
+ onPickImage,
299
+ onPickFile
300
+ }) {
301
+ const translateY = React.useRef(new reactNative.Animated.Value(80)).current;
302
+ const opacity = React.useRef(new reactNative.Animated.Value(0)).current;
303
+ React.useEffect(() => {
304
+ if (visible) {
305
+ reactNative.Animated.parallel([
306
+ reactNative.Animated.timing(opacity, {
307
+ toValue: 1,
308
+ duration: 180,
309
+ useNativeDriver: true
310
+ }),
311
+ reactNative.Animated.spring(translateY, {
312
+ toValue: 0,
313
+ useNativeDriver: true,
314
+ friction: 9,
315
+ tension: 90
316
+ })
317
+ ]).start();
318
+ } else {
319
+ translateY.setValue(80);
320
+ opacity.setValue(0);
321
+ }
322
+ }, [visible, opacity, translateY]);
323
+ return /* @__PURE__ */ jsxRuntime.jsxs(
324
+ reactNative.Modal,
325
+ {
326
+ visible,
327
+ transparent: true,
328
+ animationType: "none",
329
+ onRequestClose: onClose,
330
+ children: [
331
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: [sheet.backdrop, { opacity }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: sheet.backdropPressable, onPress: onClose }) }),
332
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: sheet.sheetWrap, pointerEvents: "box-none", children: /* @__PURE__ */ jsxRuntime.jsxs(
333
+ reactNative.Animated.View,
334
+ {
335
+ style: [
336
+ sheet.sheet,
337
+ { transform: [{ translateY }], opacity }
338
+ ],
339
+ children: [
340
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: sheet.handle }),
341
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: sheet.headerRow, children: [
342
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: sheet.title, children: "Add to message" }),
343
+ /* @__PURE__ */ jsxRuntime.jsx(
344
+ reactNative.Pressable,
345
+ {
346
+ onPress: onClose,
347
+ hitSlop: 8,
348
+ style: sheet.closeBtn,
349
+ android_ripple: ANDROID_RIPPLE_DARK,
350
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 18, color: "#6b6b67", strokeWidth: 2.25 })
351
+ }
352
+ )
353
+ ] }),
354
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: sheet.options, children: [
355
+ showImage ? /* @__PURE__ */ jsxRuntime.jsxs(
356
+ reactNative.Pressable,
357
+ {
358
+ onPress: onPickImage,
359
+ style: sheet.option,
360
+ android_ripple: ANDROID_RIPPLE_DARK,
361
+ children: [
362
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: sheet.optionIconWrap, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ImagePlus, { size: 20, color: PAYMAN_TEAL, strokeWidth: 2 }) }),
363
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1 }, children: [
364
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: sheet.optionTitle, children: "Upload image" }),
365
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: sheet.optionSubtitle, children: "From your camera roll" })
366
+ ] })
367
+ ]
368
+ }
369
+ ) : null,
370
+ showFile ? /* @__PURE__ */ jsxRuntime.jsxs(
371
+ reactNative.Pressable,
372
+ {
373
+ onPress: onPickFile,
374
+ style: sheet.option,
375
+ android_ripple: ANDROID_RIPPLE_DARK,
376
+ children: [
377
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: sheet.optionIconWrap, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Paperclip, { size: 20, color: PAYMAN_TEAL, strokeWidth: 2 }) }),
378
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1 }, children: [
379
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: sheet.optionTitle, children: "Attach file" }),
380
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: sheet.optionSubtitle, children: "PDFs, documents and more" })
381
+ ] })
382
+ ]
383
+ }
384
+ ) : null
385
+ ] })
386
+ ]
387
+ }
388
+ ) })
389
+ ]
390
+ }
391
+ );
392
+ }
393
+ var s = reactNative.StyleSheet.create({
394
+ outer: {
395
+ paddingHorizontal: 12,
396
+ paddingTop: 6,
397
+ paddingBottom: 6
398
+ },
399
+ topAccessory: {
400
+ marginBottom: -1,
401
+ zIndex: 1
402
+ },
403
+ wrapper: {
404
+ borderRadius: 24,
405
+ borderWidth: 1,
406
+ paddingHorizontal: 6,
407
+ paddingTop: 2,
408
+ paddingBottom: 6
409
+ },
410
+ wrapperWithTopAccessory: {
411
+ borderTopLeftRadius: 0,
412
+ borderTopRightRadius: 0
413
+ },
414
+ wrapperFocused: {
415
+ ...reactNative.Platform.select({
416
+ ios: {
417
+ shadowColor: "#000",
418
+ shadowOpacity: 0.04,
419
+ shadowRadius: 10,
420
+ shadowOffset: { width: 0, height: 2 }
421
+ },
422
+ android: { elevation: 0 }
423
+ })
424
+ },
425
+ wrapperDisabled: { opacity: 0.6 },
426
+ inputRow: {
427
+ maxHeight: INPUT_MAX_HEIGHT,
428
+ paddingHorizontal: 12,
429
+ paddingTop: 10,
430
+ paddingBottom: 4
431
+ },
432
+ input: {
433
+ fontSize: INPUT_FONT_SIZE,
434
+ lineHeight: INPUT_LINE_HEIGHT,
435
+ includeFontPadding: false,
436
+ textAlignVertical: "top",
437
+ padding: 0,
438
+ margin: 0
439
+ },
440
+ controls: {
441
+ flexDirection: "row",
442
+ alignItems: "center",
443
+ justifyContent: "space-between",
444
+ paddingHorizontal: 2,
445
+ paddingTop: 2
446
+ },
447
+ leftControls: {
448
+ flexDirection: "row",
449
+ alignItems: "center",
450
+ gap: 2
451
+ },
452
+ rightControls: {
453
+ flexDirection: "row",
454
+ alignItems: "center",
455
+ gap: 2
456
+ },
457
+ iconBtn: {
458
+ width: 32,
459
+ height: 32,
460
+ borderRadius: 16,
461
+ alignItems: "center",
462
+ justifyContent: "center"
463
+ },
464
+ iconBtnDisabled: { opacity: 0.4 },
465
+ iconBtnRecording: { backgroundColor: "rgba(0,133,141,0.10)" },
466
+ sendBtn: {
467
+ width: 34,
468
+ height: 34,
469
+ borderRadius: 17,
470
+ backgroundColor: SEND_BUTTON_COLOR,
471
+ alignItems: "center",
472
+ justifyContent: "center",
473
+ marginLeft: 2,
474
+ ...reactNative.Platform.select({
475
+ ios: {
476
+ shadowColor: SEND_BUTTON_COLOR,
477
+ shadowOpacity: 0.32,
478
+ shadowRadius: 10,
479
+ shadowOffset: { width: 0, height: 4 }
480
+ },
481
+ android: { elevation: 3 }
482
+ })
483
+ },
484
+ sendBtnIdle: {
485
+ backgroundColor: SEND_BUTTON_DISABLED_COLOR,
486
+ opacity: 1,
487
+ shadowOpacity: 0
488
+ },
489
+ disclaimer: {
490
+ fontSize: 11,
491
+ textAlign: "center",
492
+ marginTop: 8,
493
+ paddingHorizontal: 16
494
+ }
495
+ });
496
+ var sheet = reactNative.StyleSheet.create({
497
+ backdrop: {
498
+ ...reactNative.StyleSheet.absoluteFillObject,
499
+ backgroundColor: "rgba(15,23,42,0.35)"
500
+ },
501
+ backdropPressable: { flex: 1 },
502
+ sheetWrap: {
503
+ ...reactNative.StyleSheet.absoluteFillObject,
504
+ justifyContent: "flex-end"
505
+ },
506
+ sheet: {
507
+ backgroundColor: "#ffffff",
508
+ borderTopLeftRadius: 24,
509
+ borderTopRightRadius: 24,
510
+ paddingHorizontal: 20,
511
+ paddingTop: 8,
512
+ paddingBottom: 36,
513
+ ...reactNative.Platform.select({
514
+ ios: {
515
+ shadowColor: "#000",
516
+ shadowOpacity: 0.18,
517
+ shadowRadius: 24,
518
+ shadowOffset: { width: 0, height: -4 }
519
+ },
520
+ android: { elevation: 16 }
521
+ })
522
+ },
523
+ handle: {
524
+ alignSelf: "center",
525
+ width: 44,
526
+ height: 4,
527
+ borderRadius: 2,
528
+ backgroundColor: "rgba(15,23,42,0.12)",
529
+ marginBottom: 12
530
+ },
531
+ headerRow: {
532
+ flexDirection: "row",
533
+ alignItems: "center",
534
+ justifyContent: "space-between",
535
+ marginBottom: 12
536
+ },
537
+ title: {
538
+ fontSize: 16,
539
+ fontWeight: "600",
540
+ color: "#1d1d1f"
541
+ },
542
+ closeBtn: {
543
+ width: 30,
544
+ height: 30,
545
+ borderRadius: 15,
546
+ alignItems: "center",
547
+ justifyContent: "center",
548
+ backgroundColor: "rgba(15,23,42,0.04)"
549
+ },
550
+ options: { gap: 8 },
551
+ option: {
552
+ flexDirection: "row",
553
+ alignItems: "center",
554
+ gap: 12,
555
+ paddingHorizontal: 12,
556
+ paddingVertical: 14,
557
+ borderRadius: 14,
558
+ backgroundColor: "#f8fafc",
559
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
560
+ borderColor: "rgba(15,23,42,0.06)"
561
+ },
562
+ optionIconWrap: {
563
+ width: 38,
564
+ height: 38,
565
+ borderRadius: 19,
566
+ backgroundColor: "rgba(0,133,141,0.10)",
567
+ alignItems: "center",
568
+ justifyContent: "center"
569
+ },
570
+ optionTitle: {
571
+ fontSize: 15,
572
+ fontWeight: "600",
573
+ color: "#1d1d1f"
574
+ },
575
+ optionSubtitle: {
576
+ fontSize: 12,
577
+ color: "#6b6b67",
578
+ marginTop: 2
579
+ }
580
+ });
581
+ var DEFAULT_MAX_LENGTH = 6;
582
+ var MAX_SUPPORTED_LENGTH = 12;
583
+ var OTP_ERROR_BORDER = "#ef4444";
584
+ var COMPLETE_PULSE_MS = 350;
585
+ var SHAKE_MS = 400;
586
+ function OtpInput({
587
+ value,
588
+ onChange,
589
+ maxLength,
590
+ disabled = false,
591
+ error = false
592
+ }) {
593
+ const inputRefs = React.useRef([]);
594
+ const shakeAnim = React.useRef(new reactNative.Animated.Value(0)).current;
595
+ const scaleAnim = React.useRef(new reactNative.Animated.Value(1)).current;
596
+ const prevLenRef = React.useRef(0);
597
+ const [internalError, setInternalError] = React.useState(false);
598
+ const safeMaxLength = Number.isInteger(maxLength) && maxLength > 0 ? Math.min(maxLength, MAX_SUPPORTED_LENGTH) : DEFAULT_MAX_LENGTH;
599
+ const digits = value.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
600
+ const isFull = value.length === safeMaxLength && /^\d+$/.test(value);
601
+ React.useEffect(() => {
602
+ if (!disabled) {
603
+ inputRefs.current[0]?.focus();
604
+ }
605
+ }, [disabled]);
606
+ React.useEffect(() => {
607
+ if (!error) {
608
+ setInternalError(false);
609
+ return;
610
+ }
611
+ setInternalError(true);
612
+ reactNative.Animated.sequence([
613
+ reactNative.Animated.timing(shakeAnim, { toValue: 1, duration: SHAKE_MS, useNativeDriver: true }),
614
+ reactNative.Animated.timing(shakeAnim, { toValue: 0, duration: 0, useNativeDriver: true })
615
+ ]).start();
616
+ }, [error, shakeAnim]);
617
+ React.useEffect(() => {
618
+ if (isFull && prevLenRef.current < safeMaxLength) {
619
+ reactNative.Animated.sequence([
620
+ reactNative.Animated.timing(scaleAnim, { toValue: 1.04, duration: COMPLETE_PULSE_MS * 0.4, useNativeDriver: true }),
621
+ reactNative.Animated.timing(scaleAnim, { toValue: 1, duration: COMPLETE_PULSE_MS * 0.6, useNativeDriver: true })
622
+ ]).start();
623
+ }
624
+ prevLenRef.current = value.length;
625
+ }, [isFull, value.length, safeMaxLength, scaleAnim]);
626
+ const shakeTranslate = shakeAnim.interpolate({
627
+ inputRange: [0, 0.15, 0.3, 0.45, 0.6, 0.75, 0.9, 1],
628
+ outputRange: [0, -6, 5, -4, 3, -2, 1, 0]
629
+ });
630
+ const focusInput = (index) => {
631
+ if (index >= 0 && index < safeMaxLength) {
632
+ inputRefs.current[index]?.focus();
633
+ }
634
+ };
635
+ const updateValue = (newDigits) => {
636
+ onChange(newDigits.join("").slice(0, safeMaxLength));
637
+ };
638
+ const handleChange = (index, text) => {
639
+ const cleaned = text.replace(/\D/g, "");
640
+ if (cleaned.length > 1) {
641
+ const pasted = cleaned.slice(0, safeMaxLength);
642
+ const newDigits2 = pasted.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
643
+ updateValue(newDigits2);
644
+ focusInput(Math.min(pasted.length, safeMaxLength - 1));
645
+ return;
646
+ }
647
+ const char = cleaned.slice(-1);
648
+ const newDigits = [...digits];
649
+ newDigits[index] = char;
650
+ updateValue(newDigits);
651
+ if (char && index < safeMaxLength - 1) {
652
+ focusInput(index + 1);
653
+ }
654
+ };
655
+ const handleKeyPress = (index, key) => {
656
+ if (key === "Backspace") {
657
+ if (digits[index]) {
658
+ const newDigits = [...digits];
659
+ newDigits[index] = "";
660
+ updateValue(newDigits);
661
+ } else if (index > 0) {
662
+ const newDigits = [...digits];
663
+ newDigits[index - 1] = "";
664
+ updateValue(newDigits);
665
+ focusInput(index - 1);
666
+ }
667
+ }
668
+ };
669
+ return /* @__PURE__ */ jsxRuntime.jsx(
670
+ reactNative.Animated.View,
671
+ {
672
+ style: [
673
+ s2.container,
674
+ { transform: [{ translateX: shakeTranslate }, { scale: scaleAnim }] }
675
+ ],
676
+ children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
677
+ reactNative.TextInput,
678
+ {
679
+ ref: (el) => {
680
+ inputRefs.current[i] = el;
681
+ },
682
+ value: digit,
683
+ editable: !disabled,
684
+ keyboardType: "number-pad",
685
+ maxLength: 1,
686
+ onChangeText: (text) => handleChange(i, text),
687
+ onKeyPress: ({ nativeEvent }) => handleKeyPress(i, nativeEvent.key),
688
+ onFocus: () => inputRefs.current[i]?.setNativeProps({ selection: { start: 0, end: 1 } }),
689
+ style: [
690
+ s2.input,
691
+ disabled && s2.inputDisabled,
692
+ internalError && s2.inputError
693
+ ],
694
+ accessibilityLabel: `Digit ${i + 1}`
695
+ },
696
+ i
697
+ ))
698
+ }
699
+ );
700
+ }
701
+ var PAYMAN_OTP = {
702
+ bg: "#FFFFFF",
703
+ border: "rgba(0,0,0,0.1)",
704
+ fg: "#18181b",
705
+ disabledBg: "rgba(0,0,0,0.03)"
706
+ };
707
+ var s2 = reactNative.StyleSheet.create({
708
+ container: { flexDirection: "row", gap: 8, justifyContent: "center" },
709
+ input: {
710
+ width: 44,
711
+ height: 50,
712
+ textAlign: "center",
713
+ fontSize: 20,
714
+ fontWeight: "600",
715
+ borderWidth: 1,
716
+ borderColor: PAYMAN_OTP.border,
717
+ borderRadius: 10,
718
+ color: PAYMAN_OTP.fg,
719
+ backgroundColor: PAYMAN_OTP.bg
720
+ },
721
+ inputDisabled: { backgroundColor: PAYMAN_OTP.disabledBg, opacity: 0.5 },
722
+ inputError: {
723
+ borderColor: OTP_ERROR_BORDER,
724
+ borderWidth: 1.5
725
+ }
726
+ });
727
+
728
+ // src/components/UserActionModal/constants.ts
729
+ var BUTTON_LABELS = {
730
+ /** Link-style actions (new layout) */
731
+ RESEND_CODE: "Resend OTP",
732
+ CANCEL_TRANSFER: "Cancel Payment",
733
+ /** Short cancel label for payee approval flows */
734
+ CANCEL: "Cancel"
735
+ };
736
+ var RESEND_OTP_COOLDOWN_SECONDS = 30;
737
+ var DEFAULT_OTP_MAX_LENGTH = 6;
738
+ var MIN_OTP_MAX_LENGTH = 1;
739
+ var MAX_OTP_MAX_LENGTH = 12;
740
+ var ACTION_PENDING_TIMEOUT_MS = 15e3;
741
+ var MODAL_CONTENT = {
742
+ LOADING_APPROVE: "Verifying...",
743
+ LOADING_REJECT: "Rejecting...",
744
+ LOADING_RESEND: "Resending...",
745
+ RESEND_AVAILABLE_IN: "Resend OTP in",
746
+ SECURED_BY_PREFIX: "Secured by",
747
+ SECURED_BY_BRAND: "Payman"
748
+ };
749
+
750
+ // src/components/UserActionModal/utils.ts
751
+ function getOtpSchemaFromRequest(schema) {
752
+ const properties = schema?.properties;
753
+ const otp = properties?.otp;
754
+ const maxLengthRaw = otp?.maxLength;
755
+ const parsedMaxLength = Number.isInteger(maxLengthRaw) ? Number(maxLengthRaw) : DEFAULT_OTP_MAX_LENGTH;
756
+ const clampedMaxLength = Math.min(
757
+ MAX_OTP_MAX_LENGTH,
758
+ Math.max(MIN_OTP_MAX_LENGTH, parsedMaxLength)
759
+ );
760
+ return {
761
+ maxLength: clampedMaxLength
762
+ };
763
+ }
764
+ function formatAmountForDisplay(amount) {
765
+ const normalized = amount.replace(/,/g, "").trim();
766
+ const n = Number(normalized);
767
+ if (!Number.isFinite(n)) {
768
+ return amount.startsWith("$") ? amount : `$${amount}`;
769
+ }
770
+ return new Intl.NumberFormat("en-US", {
771
+ style: "currency",
772
+ currency: "USD"
773
+ }).format(n);
774
+ }
775
+ var BRAND = "#15687d";
776
+ var TEXT_PRIMARY = "#111827";
777
+ var TEXT_SECONDARY = "#64748b";
778
+ var BORDER = "rgba(15,23,42,0.10)";
779
+ var OTP_ERROR_FLASH_MS = 600;
780
+ function InlineVerificationPanel({
781
+ userActionRequest,
782
+ clearOtpTrigger,
783
+ onApprove,
784
+ onReject,
785
+ onResend
786
+ }) {
787
+ const [otp, setOtp] = React.useState("");
788
+ const [actionType, setActionType] = React.useState(null);
789
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
790
+ const [resendCooldownRemaining, setResendCooldownRemaining] = React.useState(0);
791
+ const [otpError, setOtpError] = React.useState(false);
792
+ const entrance = React.useRef(new reactNative.Animated.Value(0)).current;
793
+ const lastAutoSubmittedRef = React.useRef("");
794
+ const submitInFlightRef = React.useRef(false);
795
+ const submitGenerationRef = React.useRef(0);
796
+ const schema = getOtpSchemaFromRequest(userActionRequest?.requestedSchema);
797
+ const resetActionState = React.useCallback(() => {
798
+ setIsSubmitting(false);
799
+ setActionType(null);
800
+ }, []);
801
+ React.useEffect(() => {
802
+ if (userActionRequest) {
803
+ setResendCooldownRemaining(RESEND_OTP_COOLDOWN_SECONDS);
804
+ entrance.setValue(0);
805
+ reactNative.Animated.timing(entrance, {
806
+ toValue: 1,
807
+ duration: 220,
808
+ easing: reactNative.Easing.out(reactNative.Easing.cubic),
809
+ useNativeDriver: true
810
+ }).start();
811
+ } else {
812
+ setOtp("");
813
+ resetActionState();
814
+ setResendCooldownRemaining(0);
815
+ setOtpError(false);
816
+ lastAutoSubmittedRef.current = "";
817
+ submitInFlightRef.current = false;
818
+ submitGenerationRef.current += 1;
819
+ }
820
+ }, [entrance, resetActionState, userActionRequest]);
821
+ React.useEffect(() => {
822
+ if (resendCooldownRemaining <= 0) return;
823
+ const timer = setTimeout(
824
+ () => setResendCooldownRemaining((prev) => prev - 1),
825
+ 1e3
826
+ );
827
+ return () => clearTimeout(timer);
828
+ }, [resendCooldownRemaining]);
829
+ React.useEffect(() => {
830
+ if (clearOtpTrigger <= 0) return;
831
+ setOtpError(true);
832
+ const timer = setTimeout(() => {
833
+ setOtpError(false);
834
+ setOtp("");
835
+ resetActionState();
836
+ }, OTP_ERROR_FLASH_MS);
837
+ return () => clearTimeout(timer);
838
+ }, [clearOtpTrigger, resetActionState]);
839
+ React.useEffect(() => {
840
+ if (!userActionRequest || !isSubmitting) return;
841
+ if (actionType !== "approve" && actionType !== "reject") return;
842
+ const timeout = setTimeout(
843
+ () => resetActionState(),
844
+ ACTION_PENDING_TIMEOUT_MS
845
+ );
846
+ return () => clearTimeout(timeout);
847
+ }, [actionType, isSubmitting, resetActionState, userActionRequest]);
848
+ React.useEffect(() => {
849
+ if (!userActionRequest) return;
850
+ if (otp.length !== schema.maxLength || !/^\d+$/.test(otp)) return;
851
+ if (isSubmitting || submitInFlightRef.current) return;
852
+ if (lastAutoSubmittedRef.current === otp) return;
853
+ lastAutoSubmittedRef.current = otp;
854
+ submitInFlightRef.current = true;
855
+ const submitGeneration = submitGenerationRef.current;
856
+ void (async () => {
857
+ setIsSubmitting(true);
858
+ setActionType("approve");
859
+ try {
860
+ await onApprove(otp);
861
+ } catch {
862
+ if (submitGenerationRef.current !== submitGeneration) return;
863
+ resetActionState();
864
+ lastAutoSubmittedRef.current = otp;
865
+ } finally {
866
+ if (submitGenerationRef.current !== submitGeneration) return;
867
+ submitInFlightRef.current = false;
868
+ }
869
+ })();
870
+ }, [
871
+ isSubmitting,
872
+ onApprove,
873
+ otp,
874
+ resetActionState,
875
+ schema.maxLength,
876
+ userActionRequest
877
+ ]);
878
+ const handleReject = React.useCallback(async () => {
879
+ setIsSubmitting(true);
880
+ setActionType("reject");
881
+ try {
882
+ await onReject();
883
+ } catch {
884
+ resetActionState();
885
+ }
886
+ }, [onReject, resetActionState]);
887
+ const handleResend = React.useCallback(async () => {
888
+ if (resendCooldownRemaining > 0) return;
889
+ setIsSubmitting(true);
890
+ setActionType("resend");
891
+ try {
892
+ await onResend();
893
+ setResendCooldownRemaining(RESEND_OTP_COOLDOWN_SECONDS);
894
+ } catch {
895
+ } finally {
896
+ setActionType(null);
897
+ setIsSubmitting(false);
898
+ }
899
+ }, [onResend, resendCooldownRemaining]);
900
+ if (!userActionRequest) return null;
901
+ const translateY = entrance.interpolate({
902
+ inputRange: [0, 1],
903
+ outputRange: [10, 0]
904
+ });
905
+ const isVerifying = actionType === "approve" && isSubmitting;
906
+ const isCancelling = actionType === "reject" && isSubmitting;
907
+ return /* @__PURE__ */ jsxRuntime.jsxs(
908
+ reactNative.Animated.View,
909
+ {
910
+ style: [
911
+ s3.panel,
912
+ { opacity: entrance, transform: [{ translateY }] }
913
+ ],
914
+ accessibilityLabel: "payman-inline-verification",
915
+ children: [
916
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s3.title, children: "Enter the verification code sent to your email" }),
917
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s3.otpWrap, accessibilityLabel: "payman-otp-wrap", children: /* @__PURE__ */ jsxRuntime.jsx(
918
+ OtpInput,
919
+ {
920
+ value: otp,
921
+ onChange: setOtp,
922
+ maxLength: schema.maxLength,
923
+ disabled: isSubmitting,
924
+ error: otpError
925
+ }
926
+ ) }),
927
+ isVerifying ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s3.statusRow, children: [
928
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "small", color: BRAND }),
929
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s3.statusText, children: MODAL_CONTENT.LOADING_APPROVE })
930
+ ] }) : null,
931
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s3.actions, children: [
932
+ /* @__PURE__ */ jsxRuntime.jsx(
933
+ reactNative.Pressable,
934
+ {
935
+ onPress: handleResend,
936
+ disabled: isSubmitting || resendCooldownRemaining > 0,
937
+ hitSlop: 8,
938
+ accessibilityLabel: "payman-inline-verification-resend",
939
+ children: /* @__PURE__ */ jsxRuntime.jsx(
940
+ reactNative.Text,
941
+ {
942
+ style: [
943
+ s3.actionText,
944
+ (isSubmitting || resendCooldownRemaining > 0) && s3.actionTextDisabled
945
+ ],
946
+ children: actionType === "resend" ? MODAL_CONTENT.LOADING_RESEND : resendCooldownRemaining > 0 ? `${MODAL_CONTENT.RESEND_AVAILABLE_IN} ${resendCooldownRemaining}s` : BUTTON_LABELS.RESEND_CODE
947
+ }
948
+ )
949
+ }
950
+ ),
951
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s3.divider }),
952
+ /* @__PURE__ */ jsxRuntime.jsx(
953
+ reactNative.Pressable,
954
+ {
955
+ onPress: handleReject,
956
+ disabled: isSubmitting,
957
+ hitSlop: 8,
958
+ accessibilityLabel: "payman-inline-verification-cancel",
959
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s3.cancelContent, children: [
960
+ isCancelling ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "small", color: TEXT_SECONDARY }) : null,
961
+ /* @__PURE__ */ jsxRuntime.jsx(
962
+ reactNative.Text,
963
+ {
964
+ style: [
965
+ s3.actionText,
966
+ isSubmitting && !isCancelling && s3.actionTextDisabled
967
+ ],
968
+ children: isCancelling ? MODAL_CONTENT.LOADING_REJECT : BUTTON_LABELS.CANCEL
969
+ }
970
+ )
971
+ ] })
972
+ }
973
+ )
974
+ ] })
975
+ ]
976
+ }
977
+ );
978
+ }
979
+ var s3 = reactNative.StyleSheet.create({
980
+ panel: {
981
+ backgroundColor: "#f8fafc",
982
+ borderWidth: 1,
983
+ borderBottomWidth: 0,
984
+ borderColor: BORDER,
985
+ borderTopLeftRadius: 24,
986
+ borderTopRightRadius: 24,
987
+ paddingHorizontal: 14,
988
+ paddingTop: 14,
989
+ paddingBottom: 12
990
+ },
991
+ title: {
992
+ color: TEXT_PRIMARY,
993
+ fontSize: 14,
994
+ fontWeight: "600",
995
+ lineHeight: 20,
996
+ textAlign: "center",
997
+ marginBottom: 12
998
+ },
999
+ otpWrap: {
1000
+ alignItems: "center"
1001
+ },
1002
+ statusRow: {
1003
+ flexDirection: "row",
1004
+ alignItems: "center",
1005
+ justifyContent: "center",
1006
+ gap: 8,
1007
+ marginTop: 10
1008
+ },
1009
+ statusText: {
1010
+ color: TEXT_SECONDARY,
1011
+ fontSize: 12,
1012
+ fontWeight: "500"
1013
+ },
1014
+ actions: {
1015
+ flexDirection: "row",
1016
+ alignItems: "center",
1017
+ justifyContent: "center",
1018
+ gap: 12,
1019
+ marginTop: 12
1020
+ },
1021
+ actionText: {
1022
+ color: BRAND,
1023
+ fontSize: 12,
1024
+ fontWeight: "600"
1025
+ },
1026
+ actionTextDisabled: {
1027
+ color: TEXT_SECONDARY,
1028
+ opacity: 0.55
1029
+ },
1030
+ divider: {
1031
+ width: 1,
1032
+ height: 14,
1033
+ backgroundColor: BORDER
1034
+ },
1035
+ cancelContent: {
1036
+ flexDirection: "row",
1037
+ alignItems: "center",
1038
+ gap: 6
1039
+ }
1040
+ });
1041
+
1042
+ // src/utils/errorMessages.ts
1043
+ var WORKFLOW_FAILED = "WORKFLOW_FAILED";
1044
+ var STREAM_NOT_STARTED = "STREAM_NOT_STARTED";
1045
+ var HTTP_ERROR_PREFIX = /^HTTP\s+(\d+)\s*:\s*([\s\S]+)$/;
1046
+ function isFriendlyWorkflowError(errorDetails) {
1047
+ if (!errorDetails) return false;
1048
+ return errorDetails === WORKFLOW_FAILED || errorDetails === STREAM_NOT_STARTED || errorDetails.includes(WORKFLOW_FAILED);
1049
+ }
1050
+ function parseErrorPayload(payload) {
1051
+ try {
1052
+ const parsed = JSON.parse(payload);
1053
+ if (typeof parsed === "string") {
1054
+ return { message: parsed.trim() || void 0 };
1055
+ }
1056
+ if (typeof parsed === "object" && parsed !== null) {
1057
+ const record = parsed;
1058
+ return {
1059
+ status: typeof record.status === "number" ? record.status : void 0,
1060
+ message: typeof record.message === "string" && record.message.trim() ? record.message.trim() : void 0
1061
+ };
1062
+ }
1063
+ } catch {
1064
+ }
1065
+ return {};
1066
+ }
1067
+ function getConflictErrorMessage(errorDetails) {
1068
+ if (!errorDetails) return void 0;
1069
+ const trimmedError = errorDetails.trim();
1070
+ const httpMatch = trimmedError.match(HTTP_ERROR_PREFIX);
1071
+ const httpStatus = httpMatch ? Number(httpMatch[1]) : void 0;
1072
+ const rawPayload = (httpMatch ? httpMatch[2] : trimmedError).trim();
1073
+ const payload = parseErrorPayload(rawPayload);
1074
+ const status = payload.status ?? httpStatus;
1075
+ if (status !== 409) {
1076
+ return void 0;
1077
+ }
1078
+ if (payload.message) {
1079
+ return payload.message;
1080
+ }
1081
+ return rawPayload || void 0;
1082
+ }
1083
+ var TEAL = "#00858d";
1084
+ function UserMessageV2({
1085
+ message,
1086
+ actions,
1087
+ onEdit,
1088
+ onRetry,
1089
+ retryDisabled = false
1090
+ }) {
1091
+ const [copied, setCopied] = React.useState(false);
1092
+ const timerRef = React.useRef(null);
1093
+ const showCopyAction = actions?.copy ?? true;
1094
+ const showEditAction = actions?.edit ?? false;
1095
+ const showRetryAction = actions?.retry ?? false;
1096
+ const hasVisibleActions = showCopyAction || showEditAction && !!onEdit || showRetryAction && !!onRetry;
1097
+ const fadeIn = React.useRef(new reactNative.Animated.Value(0)).current;
1098
+ const slideIn = React.useRef(new reactNative.Animated.Value(8)).current;
1099
+ React.useEffect(() => {
1100
+ reactNative.Animated.parallel([
1101
+ reactNative.Animated.timing(fadeIn, {
1102
+ toValue: 1,
1103
+ duration: 200,
1104
+ easing: reactNative.Easing.out(reactNative.Easing.cubic),
1105
+ useNativeDriver: true
1106
+ }),
1107
+ reactNative.Animated.timing(slideIn, {
1108
+ toValue: 0,
1109
+ duration: 200,
1110
+ easing: reactNative.Easing.out(reactNative.Easing.cubic),
1111
+ useNativeDriver: true
1112
+ })
1113
+ ]).start();
1114
+ }, [fadeIn, slideIn]);
1115
+ const handleCopy = React.useCallback(() => {
1116
+ reactNative.Clipboard.setString(message.content);
1117
+ setCopied(true);
1118
+ if (timerRef.current) clearTimeout(timerRef.current);
1119
+ timerRef.current = setTimeout(() => setCopied(false), 1800);
1120
+ }, [message.content]);
1121
+ React.useEffect(() => {
1122
+ return () => {
1123
+ if (timerRef.current) clearTimeout(timerRef.current);
1124
+ };
1125
+ }, []);
1126
+ const conflictErr = message.errorDetails ? getConflictErrorMessage(message.errorDetails) ?? message.errorDetails : null;
1127
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1128
+ reactNative.Animated.View,
1129
+ {
1130
+ style: [s4.wrapper, { opacity: fadeIn, transform: [{ translateY: slideIn }] }],
1131
+ children: [
1132
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s4.bubble, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { selectable: true, style: s4.text, children: message.content }) }),
1133
+ message.isError && conflictErr ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s4.errorRow, children: [
1134
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.AlertCircle, { size: 13, color: "rgba(239, 68, 68, 0.8)", strokeWidth: 2 }),
1135
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s4.errorText, children: conflictErr })
1136
+ ] }) : null,
1137
+ hasVisibleActions ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s4.actions, children: [
1138
+ showCopyAction ? /* @__PURE__ */ jsxRuntime.jsx(
1139
+ reactNative.Pressable,
1140
+ {
1141
+ onPress: handleCopy,
1142
+ hitSlop: 8,
1143
+ style: s4.actionBtn,
1144
+ accessibilityLabel: "Copy message",
1145
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Check, { size: 13, color: "#059669", strokeWidth: 2.5 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Copy, { size: 13, color: "#94a3b8", strokeWidth: 2 })
1146
+ }
1147
+ ) : null,
1148
+ showEditAction && onEdit ? /* @__PURE__ */ jsxRuntime.jsx(
1149
+ reactNative.Pressable,
1150
+ {
1151
+ onPress: () => onEdit(message.id),
1152
+ hitSlop: 8,
1153
+ style: s4.actionBtn,
1154
+ accessibilityLabel: "Edit message",
1155
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Pencil, { size: 13, color: "#94a3b8", strokeWidth: 2 })
1156
+ }
1157
+ ) : null,
1158
+ showRetryAction && onRetry ? /* @__PURE__ */ jsxRuntime.jsx(
1159
+ reactNative.Pressable,
1160
+ {
1161
+ onPress: () => onRetry(message.id),
1162
+ disabled: retryDisabled,
1163
+ hitSlop: 8,
1164
+ style: [s4.actionBtn, retryDisabled && s4.actionBtnDisabled],
1165
+ accessibilityLabel: "Retry message",
1166
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.RotateCcw, { size: 13, color: "#94a3b8", strokeWidth: 2 })
1167
+ }
1168
+ ) : null
1169
+ ] }) : null
1170
+ ]
1171
+ }
1172
+ );
1173
+ }
1174
+ var s4 = reactNative.StyleSheet.create({
1175
+ wrapper: {
1176
+ paddingHorizontal: 16,
1177
+ paddingVertical: 5,
1178
+ alignItems: "flex-end"
1179
+ },
1180
+ bubble: {
1181
+ backgroundColor: TEAL,
1182
+ borderRadius: 20,
1183
+ borderBottomRightRadius: 6,
1184
+ paddingHorizontal: 14,
1185
+ paddingVertical: 10,
1186
+ maxWidth: 320
1187
+ },
1188
+ text: {
1189
+ fontSize: 15,
1190
+ lineHeight: 22,
1191
+ color: "#fff"
1192
+ },
1193
+ errorRow: {
1194
+ flexDirection: "row",
1195
+ alignItems: "flex-start",
1196
+ gap: 6,
1197
+ marginTop: 4,
1198
+ paddingRight: 4,
1199
+ maxWidth: 320
1200
+ },
1201
+ errorText: {
1202
+ flex: 1,
1203
+ fontSize: 12,
1204
+ color: "rgba(239, 68, 68, 0.95)",
1205
+ lineHeight: 18
1206
+ },
1207
+ actions: {
1208
+ flexDirection: "row",
1209
+ marginTop: 6,
1210
+ gap: 4
1211
+ },
1212
+ actionBtn: {
1213
+ padding: 6,
1214
+ borderRadius: 8
1215
+ },
1216
+ actionBtnDisabled: {
1217
+ opacity: 0.45
1218
+ }
1219
+ });
1220
+ var THINKING_SPEED = {
1221
+ normal: [6, 8],
1222
+ fast: 1,
1223
+ punctuation: [20, 30],
1224
+ newline: [12, 18],
1225
+ idle: 30
1226
+ };
1227
+ var RESPONSE_SPEED = {
1228
+ normal: [4, 8],
1229
+ fast: 1,
1230
+ punctuation: [20, 30],
1231
+ newline: [10, 15],
1232
+ idle: 30
1233
+ };
1234
+ function charDelay(char, speed) {
1235
+ if (char === "*") return speed.fast;
1236
+ if (char === "\n") return speed.newline[0] + Math.random() * speed.newline[1];
1237
+ if (".!?,;:".includes(char))
1238
+ return speed.punctuation[0] + Math.random() * speed.punctuation[1];
1239
+ return speed.normal[0] + Math.random() * speed.normal[1];
1240
+ }
1241
+ var MARKDOWN_IMAGE_REGEX = /^!\[[^\]]*\]\([^)]*\)/;
1242
+ var typingProgressCache = /* @__PURE__ */ new Map();
1243
+ function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDisplayedText, cacheKey) {
1244
+ const cached = cacheKey ? typingProgressCache.get(cacheKey) : void 0;
1245
+ const hydratedFromCache = cached !== void 0 && targetText.startsWith(cached) ? cached : void 0;
1246
+ const [displayedText, setDisplayedText] = React.useState(hydratedFromCache ?? "");
1247
+ const displayedRef = React.useRef(hydratedFromCache ?? "");
1248
+ const targetRef = React.useRef(targetText);
1249
+ const enabledRef = React.useRef(enabled);
1250
+ const initialDisplayedRef = React.useRef(initialDisplayedText);
1251
+ const cacheKeyRef = React.useRef(cacheKey);
1252
+ const timerRef = React.useRef(null);
1253
+ const runningRef = React.useRef(false);
1254
+ targetRef.current = targetText;
1255
+ enabledRef.current = enabled;
1256
+ initialDisplayedRef.current = initialDisplayedText;
1257
+ cacheKeyRef.current = cacheKey;
1258
+ const writeDisplayed = (next) => {
1259
+ displayedRef.current = next;
1260
+ setDisplayedText(next);
1261
+ if (cacheKeyRef.current) {
1262
+ typingProgressCache.set(cacheKeyRef.current, next);
1263
+ }
1264
+ };
1265
+ React.useEffect(() => {
1266
+ if (!enabled) {
1267
+ if (timerRef.current) {
1268
+ clearTimeout(timerRef.current);
1269
+ timerRef.current = null;
1270
+ }
1271
+ runningRef.current = false;
1272
+ displayedRef.current = targetText;
1273
+ setDisplayedText(targetText);
1274
+ if (cacheKeyRef.current) {
1275
+ typingProgressCache.delete(cacheKeyRef.current);
1276
+ }
1277
+ return;
1278
+ }
1279
+ if (displayedRef.current && !targetRef.current.startsWith(displayedRef.current)) {
1280
+ displayedRef.current = "";
1281
+ setDisplayedText("");
1282
+ if (cacheKeyRef.current) typingProgressCache.delete(cacheKeyRef.current);
1283
+ }
1284
+ if (displayedRef.current.length === 0 && initialDisplayedRef.current && targetRef.current.startsWith(initialDisplayedRef.current)) {
1285
+ writeDisplayed(initialDisplayedRef.current);
1286
+ }
1287
+ if (runningRef.current) return;
1288
+ runningRef.current = true;
1289
+ const tick = () => {
1290
+ if (!enabledRef.current) {
1291
+ runningRef.current = false;
1292
+ return;
1293
+ }
1294
+ if (displayedRef.current && !targetRef.current.startsWith(displayedRef.current)) {
1295
+ let divergeAt = 0;
1296
+ const minLen = Math.min(displayedRef.current.length, targetRef.current.length);
1297
+ while (divergeAt < minLen && displayedRef.current[divergeAt] === targetRef.current[divergeAt]) {
1298
+ divergeAt++;
1299
+ }
1300
+ const imgStart = targetRef.current.slice(0, divergeAt).lastIndexOf("![");
1301
+ if (imgStart >= 0) {
1302
+ const newImgMatch = MARKDOWN_IMAGE_REGEX.exec(targetRef.current.slice(imgStart));
1303
+ const oldImgMatch = MARKDOWN_IMAGE_REGEX.exec(displayedRef.current.slice(imgStart));
1304
+ if (newImgMatch && oldImgMatch) {
1305
+ const oldImgEnd = imgStart + oldImgMatch[0].length;
1306
+ const newImgEnd = imgStart + newImgMatch[0].length;
1307
+ const newCursor = Math.min(
1308
+ Math.max(displayedRef.current.length + (newImgEnd - oldImgEnd), newImgEnd),
1309
+ targetRef.current.length
1310
+ );
1311
+ writeDisplayed(targetRef.current.slice(0, newCursor));
1312
+ timerRef.current = setTimeout(tick, 0);
1313
+ return;
1314
+ }
1315
+ }
1316
+ writeDisplayed(targetRef.current.slice(0, imgStart >= 0 ? imgStart : divergeAt));
1317
+ timerRef.current = setTimeout(tick, 0);
1318
+ return;
1319
+ }
1320
+ if (displayedRef.current.length < targetRef.current.length) {
1321
+ const remaining = targetRef.current.slice(displayedRef.current.length);
1322
+ const imgMatch = MARKDOWN_IMAGE_REGEX.exec(remaining);
1323
+ if (imgMatch) {
1324
+ writeDisplayed(displayedRef.current + imgMatch[0]);
1325
+ timerRef.current = setTimeout(tick, 0);
1326
+ return;
1327
+ }
1328
+ const nextChar = remaining[0];
1329
+ writeDisplayed(displayedRef.current + nextChar);
1330
+ const delay = charDelay(nextChar, speed);
1331
+ timerRef.current = setTimeout(tick, delay);
1332
+ } else {
1333
+ timerRef.current = setTimeout(tick, speed.idle);
1334
+ }
1335
+ };
1336
+ tick();
1337
+ return () => {
1338
+ if (timerRef.current) {
1339
+ clearTimeout(timerRef.current);
1340
+ timerRef.current = null;
1341
+ }
1342
+ runningRef.current = false;
1343
+ };
1344
+ }, [enabled]);
1345
+ const isTyping = enabled && displayedRef.current.length < targetRef.current.length;
1346
+ return {
1347
+ displayedText: enabled ? displayedText : targetText,
1348
+ isTyping
1349
+ };
1350
+ }
1351
+ var CURSOR_MESSAGES = [
1352
+ "Analyzing",
1353
+ "Processing",
1354
+ "Calculating",
1355
+ "Reviewing",
1356
+ "Verifying",
1357
+ "Assessing",
1358
+ "Evaluating",
1359
+ "Checking",
1360
+ "Planning",
1361
+ "Working",
1362
+ "Updating",
1363
+ "Validating",
1364
+ "Monitoring",
1365
+ "Optimizing",
1366
+ "Reconciling",
1367
+ "Forecasting",
1368
+ "Inspecting",
1369
+ "Organizing",
1370
+ "Sorting",
1371
+ "Scanning",
1372
+ "Balancing",
1373
+ "Summarizing",
1374
+ "Predicting",
1375
+ "Comparing",
1376
+ "Tracking",
1377
+ "Adjusting",
1378
+ "Examining",
1379
+ "Mapping",
1380
+ "Modeling",
1381
+ "Reporting",
1382
+ "Confirming"
1383
+ ];
1384
+ var FINAL_CURSOR_MESSAGE = "Finishing up";
1385
+ var INITIAL_THINKING_PLACEHOLDER = [
1386
+ "**Getting things ready**",
1387
+ "Putting things together"
1388
+ ].join("\n");
1389
+ var PAYMAN_TEAL2 = "#00858d";
1390
+ var TEXT_PRIMARY2 = "#0f172a";
1391
+ var TEXT_SECONDARY2 = "#475569";
1392
+ var TEXT_TERTIARY = "#94a3b8";
1393
+ var TEXT_MUTED = "#cbd5e1";
1394
+ if (reactNative.Platform.OS === "android" && reactNative.UIManager.setLayoutAnimationEnabledExperimental) {
1395
+ reactNative.UIManager.setLayoutAnimationEnabledExperimental(true);
1396
+ }
1397
+ function PaymanMarkNative({ size = 14 }) {
1398
+ const scale = React.useRef(new reactNative.Animated.Value(0.7)).current;
1399
+ const opacity = React.useRef(new reactNative.Animated.Value(0.6)).current;
1400
+ React.useEffect(() => {
1401
+ const loop = reactNative.Animated.loop(
1402
+ reactNative.Animated.parallel([
1403
+ reactNative.Animated.sequence([
1404
+ reactNative.Animated.timing(scale, {
1405
+ toValue: 1.6,
1406
+ duration: 1100,
1407
+ easing: reactNative.Easing.out(reactNative.Easing.cubic),
1408
+ useNativeDriver: true
1409
+ }),
1410
+ reactNative.Animated.timing(scale, {
1411
+ toValue: 0.7,
1412
+ duration: 0,
1413
+ useNativeDriver: true
1414
+ })
1415
+ ]),
1416
+ reactNative.Animated.sequence([
1417
+ reactNative.Animated.timing(opacity, {
1418
+ toValue: 0,
1419
+ duration: 1100,
1420
+ easing: reactNative.Easing.out(reactNative.Easing.cubic),
1421
+ useNativeDriver: true
1422
+ }),
1423
+ reactNative.Animated.timing(opacity, {
1424
+ toValue: 0.55,
1425
+ duration: 0,
1426
+ useNativeDriver: true
1427
+ })
1428
+ ])
1429
+ ])
1430
+ );
1431
+ loop.start();
1432
+ return () => loop.stop();
1433
+ }, [scale, opacity]);
1434
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [mark.wrap, { width: size, height: size }], children: [
1435
+ /* @__PURE__ */ jsxRuntime.jsx(
1436
+ reactNative.Animated.View,
1437
+ {
1438
+ style: [
1439
+ mark.ring,
1440
+ {
1441
+ width: size,
1442
+ height: size,
1443
+ borderRadius: size / 2,
1444
+ transform: [{ scale }],
1445
+ opacity
1446
+ }
1447
+ ]
1448
+ }
1449
+ ),
1450
+ /* @__PURE__ */ jsxRuntime.jsx(
1451
+ reactNative.View,
1452
+ {
1453
+ style: [
1454
+ mark.core,
1455
+ {
1456
+ width: size * 0.55,
1457
+ height: size * 0.55,
1458
+ borderRadius: size * 0.55
1459
+ }
1460
+ ]
1461
+ }
1462
+ )
1463
+ ] });
1464
+ }
1465
+ function ShimmerText({
1466
+ children,
1467
+ style
1468
+ }) {
1469
+ const opacity = React.useRef(new reactNative.Animated.Value(0.5)).current;
1470
+ React.useEffect(() => {
1471
+ const anim = reactNative.Animated.loop(
1472
+ reactNative.Animated.sequence([
1473
+ reactNative.Animated.timing(opacity, {
1474
+ toValue: 1,
1475
+ duration: 900,
1476
+ easing: reactNative.Easing.inOut(reactNative.Easing.ease),
1477
+ useNativeDriver: true
1478
+ }),
1479
+ reactNative.Animated.timing(opacity, {
1480
+ toValue: 0.5,
1481
+ duration: 900,
1482
+ easing: reactNative.Easing.inOut(reactNative.Easing.ease),
1483
+ useNativeDriver: true
1484
+ })
1485
+ ])
1486
+ );
1487
+ anim.start();
1488
+ return () => anim.stop();
1489
+ }, [opacity]);
1490
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.Text, { style: [style, { opacity }], selectable: false, children });
1491
+ }
1492
+ function AnimatedSeconds({ value, style }) {
1493
+ const prevRef = React.useRef(value);
1494
+ const opacity = React.useRef(new reactNative.Animated.Value(1)).current;
1495
+ const translate = React.useRef(new reactNative.Animated.Value(0)).current;
1496
+ const [shown, setShown] = React.useState(value);
1497
+ React.useEffect(() => {
1498
+ if (value === prevRef.current) return;
1499
+ prevRef.current = value;
1500
+ reactNative.Animated.sequence([
1501
+ reactNative.Animated.parallel([
1502
+ reactNative.Animated.timing(opacity, { toValue: 0, duration: 90, useNativeDriver: true }),
1503
+ reactNative.Animated.timing(translate, { toValue: -4, duration: 90, useNativeDriver: true })
1504
+ ])
1505
+ ]).start(() => {
1506
+ setShown(value);
1507
+ translate.setValue(4);
1508
+ reactNative.Animated.parallel([
1509
+ reactNative.Animated.timing(opacity, { toValue: 1, duration: 140, useNativeDriver: true }),
1510
+ reactNative.Animated.timing(translate, { toValue: 0, duration: 140, useNativeDriver: true })
1511
+ ]).start();
1512
+ });
1513
+ }, [value, opacity, translate]);
1514
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.Text, { style: [style, { opacity, transform: [{ translateY: translate }] }], selectable: false, children: formatDuration(shown) });
1515
+ }
1516
+ function formatDuration(seconds) {
1517
+ if (seconds < 60) return `${seconds}s`;
1518
+ const m = Math.floor(seconds / 60);
1519
+ const s9 = seconds % 60;
1520
+ return s9 > 0 ? `${m}m ${s9}s` : `${m}m`;
1521
+ }
1522
+ function parseThinking(content) {
1523
+ const lines = content.split("\n");
1524
+ const out = [];
1525
+ for (const raw of lines) {
1526
+ const line = raw.trim();
1527
+ if (!line) continue;
1528
+ const stmt = line.match(/^\*\*(.+)\*\*$/);
1529
+ if (stmt) {
1530
+ out.push({ type: "statement", text: stmt[1].trim() });
1531
+ continue;
1532
+ }
1533
+ if (line.startsWith("\u2713 ")) {
1534
+ out.push({ type: "status", variant: "success", text: line.slice(2).trim() });
1535
+ continue;
1536
+ }
1537
+ if (line.startsWith("\u2717 ")) {
1538
+ out.push({ type: "status", variant: "error", text: line.slice(2).trim() });
1539
+ continue;
1540
+ }
1541
+ out.push({ type: "detail", text: line });
1542
+ }
1543
+ return out;
1544
+ }
1545
+ function ThinkingBlock({
1546
+ content,
1547
+ isStreaming,
1548
+ durationSec,
1549
+ startedAt
1550
+ }) {
1551
+ const [open, setOpen] = React.useState(true);
1552
+ const [cursorIdx, setCursorIdx] = React.useState(0);
1553
+ const [elapsedSec, setElapsedSec] = React.useState(
1554
+ () => isStreaming && startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)) : 0
1555
+ );
1556
+ const elapsedSecRef = React.useRef(elapsedSec);
1557
+ const frozenSecRef = React.useRef(null);
1558
+ const prevStreaming = React.useRef(isStreaming);
1559
+ const chevronRot = React.useRef(new reactNative.Animated.Value(open ? 1 : 0)).current;
1560
+ const parsed = React.useMemo(() => parseThinking(content), [content]);
1561
+ const isFinalizingPhase = React.useMemo(() => {
1562
+ const statements = parsed.filter(
1563
+ (l) => l.type === "statement"
1564
+ );
1565
+ return statements.length > 0 && statements[statements.length - 1].text === "Finalizing";
1566
+ }, [parsed]);
1567
+ React.useEffect(() => {
1568
+ if (prevStreaming.current && !isStreaming) {
1569
+ reactNative.LayoutAnimation.configureNext({
1570
+ duration: 220,
1571
+ create: { type: "easeInEaseOut", property: "opacity" },
1572
+ update: { type: "easeInEaseOut" },
1573
+ delete: { type: "easeInEaseOut", property: "opacity" }
1574
+ });
1575
+ setOpen(false);
1576
+ frozenSecRef.current = elapsedSecRef.current;
1577
+ }
1578
+ prevStreaming.current = isStreaming;
1579
+ }, [isStreaming]);
1580
+ React.useEffect(() => {
1581
+ if (!isStreaming || !startedAt) return;
1582
+ let active = true;
1583
+ const tick = () => {
1584
+ if (!active) return;
1585
+ const val = Math.max(0, Math.floor((Date.now() - startedAt) / 1e3));
1586
+ elapsedSecRef.current = val;
1587
+ setElapsedSec(val);
1588
+ };
1589
+ tick();
1590
+ const id = setInterval(tick, 1e3);
1591
+ return () => {
1592
+ active = false;
1593
+ clearInterval(id);
1594
+ };
1595
+ }, [isStreaming, startedAt]);
1596
+ React.useEffect(() => {
1597
+ if (!isStreaming || isFinalizingPhase) return;
1598
+ const id = setInterval(() => {
1599
+ setCursorIdx((i) => (i + 1) % CURSOR_MESSAGES.length);
1600
+ }, 4e3);
1601
+ return () => clearInterval(id);
1602
+ }, [isStreaming, isFinalizingPhase]);
1603
+ React.useEffect(() => {
1604
+ reactNative.Animated.timing(chevronRot, {
1605
+ toValue: open ? 1 : 0,
1606
+ duration: 180,
1607
+ easing: reactNative.Easing.inOut(reactNative.Easing.ease),
1608
+ useNativeDriver: true
1609
+ }).start();
1610
+ }, [open, chevronRot]);
1611
+ const justStoppedSec = !isStreaming && prevStreaming.current && startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)) : void 0;
1612
+ const finalSec = (() => {
1613
+ const candidates = [
1614
+ frozenSecRef.current,
1615
+ justStoppedSec,
1616
+ frozenSecRef.current == null && !prevStreaming.current ? durationSec : void 0
1617
+ ].filter((v) => typeof v === "number" && Number.isFinite(v));
1618
+ return candidates.length ? Math.max(...candidates) : void 0;
1619
+ })();
1620
+ const cursorText = isFinalizingPhase ? FINAL_CURSOR_MESSAGE : CURSOR_MESSAGES[cursorIdx];
1621
+ const toggle = React.useCallback(() => {
1622
+ reactNative.LayoutAnimation.configureNext({
1623
+ duration: 200,
1624
+ create: { type: "easeInEaseOut", property: "opacity" },
1625
+ update: { type: "easeInEaseOut" },
1626
+ delete: { type: "easeInEaseOut", property: "opacity" }
1627
+ });
1628
+ setOpen((o) => !o);
1629
+ }, []);
1630
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: ts.container, children: [
1631
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { style: ts.header, onPress: toggle, hitSlop: 6, children: [
1632
+ /* @__PURE__ */ jsxRuntime.jsx(
1633
+ reactNative.Animated.View,
1634
+ {
1635
+ style: {
1636
+ transform: [
1637
+ {
1638
+ rotate: chevronRot.interpolate({
1639
+ inputRange: [0, 1],
1640
+ outputRange: ["0deg", "90deg"]
1641
+ })
1642
+ }
1643
+ ]
1644
+ },
1645
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronRight, { size: 14, color: TEXT_TERTIARY, strokeWidth: 2.25 })
1646
+ }
1647
+ ),
1648
+ isStreaming ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: ts.headerLabelRow, children: [
1649
+ /* @__PURE__ */ jsxRuntime.jsx(ShimmerText, { style: ts.headerLabel, children: "Working on it\u2026" }),
1650
+ startedAt !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(AnimatedSeconds, { value: elapsedSec, style: ts.timerText }) : null
1651
+ ] }) : finalSec != null && finalSec > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: ts.headerLabelRow, children: [
1652
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: ts.headerLabelStatic, children: "Thought for " }),
1653
+ /* @__PURE__ */ jsxRuntime.jsx(AnimatedSeconds, { value: finalSec, style: ts.headerLabelStatic })
1654
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: ts.headerLabelStatic, children: "Thought" })
1655
+ ] }),
1656
+ open ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: ts.body, children: [
1657
+ parsed.map((item, i) => {
1658
+ if (item.type === "statement") {
1659
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: ts.statement, children: item.text }, i);
1660
+ }
1661
+ if (item.type === "status") {
1662
+ return /* @__PURE__ */ jsxRuntime.jsx(
1663
+ reactNative.View,
1664
+ {
1665
+ style: [
1666
+ ts.statusBadge,
1667
+ item.variant === "success" ? ts.statusSuccessBg : ts.statusErrorBg
1668
+ ],
1669
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1670
+ reactNative.Text,
1671
+ {
1672
+ style: [
1673
+ ts.statusBadgeText,
1674
+ item.variant === "success" ? ts.statusSuccessText : ts.statusErrorText
1675
+ ],
1676
+ children: item.text
1677
+ }
1678
+ )
1679
+ },
1680
+ i
1681
+ );
1682
+ }
1683
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: ts.detail, children: item.text }, i);
1684
+ }),
1685
+ isStreaming ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: ts.cursorRow, children: [
1686
+ /* @__PURE__ */ jsxRuntime.jsx(PaymanMarkNative, { size: 14 }),
1687
+ /* @__PURE__ */ jsxRuntime.jsx(ShimmerText, { style: ts.cursorLabel, children: cursorText })
1688
+ ] }) : null
1689
+ ] }) : null
1690
+ ] });
1691
+ }
1692
+ function StreamingDot() {
1693
+ const opacity = React.useRef(new reactNative.Animated.Value(0.3)).current;
1694
+ React.useEffect(() => {
1695
+ const anim = reactNative.Animated.loop(
1696
+ reactNative.Animated.sequence([
1697
+ reactNative.Animated.timing(opacity, { toValue: 1, duration: 700, easing: reactNative.Easing.inOut(reactNative.Easing.ease), useNativeDriver: true }),
1698
+ reactNative.Animated.timing(opacity, { toValue: 0.3, duration: 700, easing: reactNative.Easing.inOut(reactNative.Easing.ease), useNativeDriver: true })
1699
+ ])
1700
+ );
1701
+ anim.start();
1702
+ return () => anim.stop();
1703
+ }, [opacity]);
1704
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: [dotStyle.dot, { opacity }] });
1705
+ }
1706
+ function getFormattedThinking(message, includeInitialPlaceholder) {
1707
+ const plain = message.allThinkingText || message.activeThinkingText || "";
1708
+ const base = message.formattedThinkingText || paymanTypescriptAskSdk.buildFormattedThinking(message.steps, plain);
1709
+ if (includeInitialPlaceholder && base) {
1710
+ return INITIAL_THINKING_PLACEHOLDER + "\n" + base;
1711
+ }
1712
+ if (includeInitialPlaceholder) {
1713
+ return INITIAL_THINKING_PLACEHOLDER;
1714
+ }
1715
+ return base;
1716
+ }
1717
+ function AssistantMessageV2({
1718
+ message,
1719
+ onExecutionTraceClick: _onExecutionTraceClick,
1720
+ actions
1721
+ }) {
1722
+ const [copied, setCopied] = React.useState(false);
1723
+ const copyTimerRef = React.useRef(null);
1724
+ const showCopyAction = actions?.copy ?? true;
1725
+ const isHistorical = !!message.isHistorical;
1726
+ const hasEverStreamed = React.useRef(!!message.isStreaming && !isHistorical);
1727
+ const hasShownInitialThinking = React.useRef(
1728
+ !isHistorical && message.streamProgress === "processing"
1729
+ );
1730
+ if (message.isStreaming && !isHistorical) hasEverStreamed.current = true;
1731
+ const fadeIn = React.useRef(new reactNative.Animated.Value(0)).current;
1732
+ React.useEffect(() => {
1733
+ reactNative.Animated.timing(fadeIn, {
1734
+ toValue: 1,
1735
+ duration: 220,
1736
+ easing: reactNative.Easing.out(reactNative.Easing.cubic),
1737
+ useNativeDriver: true
1738
+ }).start();
1739
+ }, [fadeIn]);
1740
+ const rawResponseContent = (() => {
1741
+ const raw = message.isStreaming && !isHistorical ? message.streamingContent || message.content : message.content;
1742
+ if (!raw) return "";
1743
+ return raw.replace(/\\n/g, "\n");
1744
+ })();
1745
+ const hasReadyStreamPhase = !isHistorical && (message.streamProgress === "processing" || Boolean(message.steps?.length) || Boolean(message.allThinkingText) || Boolean(message.activeThinkingText) || Boolean(rawResponseContent));
1746
+ if (hasReadyStreamPhase && !message.isError) {
1747
+ hasShownInitialThinking.current = true;
1748
+ }
1749
+ const includeInitialPlaceholder = !isHistorical && hasShownInitialThinking.current && !message.isError;
1750
+ const rawThinkingContent = React.useMemo(
1751
+ () => getFormattedThinking(message, includeInitialPlaceholder),
1752
+ [message, includeInitialPlaceholder]
1753
+ );
1754
+ const isThinkingStreaming = !isHistorical && !!message.isStreaming && !rawResponseContent && !message.isError;
1755
+ const { displayedText: thinkingContent } = useTypingEffect(
1756
+ rawThinkingContent,
1757
+ hasEverStreamed.current && isThinkingStreaming,
1758
+ THINKING_SPEED,
1759
+ includeInitialPlaceholder ? INITIAL_THINKING_PLACEHOLDER : void 0,
1760
+ `thinking:${message.id}`
1761
+ );
1762
+ const hasThinkingContent = Boolean(thinkingContent);
1763
+ const showThinkingBlock = !isHistorical && (hasThinkingContent || isThinkingStreaming);
1764
+ const showLegacyThinkingPhase = !isHistorical && !!message.isStreaming && !message.isError && !rawResponseContent && message.streamProgress === "started";
1765
+ const responseTypingEnabled = !isHistorical && hasEverStreamed.current && Boolean(rawResponseContent) && !message.isError;
1766
+ const { displayedText: displayContent, isTyping: isResponseTyping } = useTypingEffect(
1767
+ rawResponseContent,
1768
+ responseTypingEnabled,
1769
+ RESPONSE_SPEED,
1770
+ void 0,
1771
+ `response:${message.id}`
1772
+ );
1773
+ const requestStartedAt = React.useMemo(() => {
1774
+ if (!message.timestamp) return void 0;
1775
+ const t = Date.parse(message.timestamp);
1776
+ return Number.isFinite(t) ? t : void 0;
1777
+ }, [message.timestamp]);
1778
+ const thinkingDuration = React.useMemo(() => {
1779
+ const steps = message.steps;
1780
+ if (!steps || steps.length === 0) return void 0;
1781
+ const last = steps[steps.length - 1];
1782
+ if (requestStartedAt && last.timestamp) {
1783
+ return Math.max(0, Math.round((last.timestamp - requestStartedAt) / 1e3));
1784
+ }
1785
+ const first = steps[0];
1786
+ if (first.timestamp && last.timestamp) {
1787
+ return Math.round((last.timestamp - first.timestamp) / 1e3);
1788
+ }
1789
+ const total = steps.reduce((sum, s9) => sum + (s9.elapsedMs || 0), 0);
1790
+ return total > 0 ? Math.round(total / 1e3) : void 0;
1791
+ }, [message.steps, requestStartedAt]);
1792
+ const handleCopy = React.useCallback(() => {
1793
+ reactNative.Clipboard.setString(displayContent);
1794
+ setCopied(true);
1795
+ if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
1796
+ copyTimerRef.current = setTimeout(() => setCopied(false), 1800);
1797
+ }, [displayContent]);
1798
+ React.useEffect(() => {
1799
+ return () => {
1800
+ if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
1801
+ };
1802
+ }, []);
1803
+ const conflictErrorMessage = getConflictErrorMessage(message.errorDetails);
1804
+ const isConflictError = Boolean(conflictErrorMessage);
1805
+ const resolvedErrorText = (() => {
1806
+ if (conflictErrorMessage) return conflictErrorMessage;
1807
+ if (isFriendlyWorkflowError(message.errorDetails) && !message.errorDetails) {
1808
+ return "Oops, something went wrong. Please try again.";
1809
+ }
1810
+ return message.errorDetails;
1811
+ })();
1812
+ if (isConflictError) {
1813
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: [s5.wrapper, { opacity: fadeIn }], children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s5.errorRow, children: [
1814
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.AlertCircle, { size: 15, color: "#ef4444", strokeWidth: 2 }),
1815
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { selectable: true, style: s5.errorText, children: conflictErrorMessage })
1816
+ ] }) });
1817
+ }
1818
+ if (message.isError && !displayContent && !hasThinkingContent) {
1819
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: [s5.wrapper, { opacity: fadeIn }], children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s5.errorRow, children: [
1820
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.AlertCircle, { size: 15, color: "#ef4444", strokeWidth: 2 }),
1821
+ resolvedErrorText ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { selectable: true, style: s5.errorText, children: resolvedErrorText }) : null
1822
+ ] }) });
1823
+ }
1824
+ if (showLegacyThinkingPhase && !showThinkingBlock) {
1825
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: [s5.wrapper, { opacity: fadeIn }], children: /* @__PURE__ */ jsxRuntime.jsx(ShimmerText, { style: s5.legacyThinking, children: "Working on it\u2026" }) });
1826
+ }
1827
+ const hasPartialError = message.isError && displayContent && !isConflictError;
1828
+ const isCancelled = message.isCancelled;
1829
+ const isDone = !message.isStreaming && displayContent && !hasPartialError && !isResponseTyping;
1830
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Animated.View, { style: [s5.wrapper, { opacity: fadeIn }], children: [
1831
+ showThinkingBlock ? /* @__PURE__ */ jsxRuntime.jsx(
1832
+ ThinkingBlock,
1833
+ {
1834
+ content: thinkingContent,
1835
+ isStreaming: isThinkingStreaming,
1836
+ durationSec: message.thinkingDurationSec ?? thinkingDuration,
1837
+ startedAt: requestStartedAt
1838
+ }
1839
+ ) : null,
1840
+ displayContent ? isResponseTyping ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { selectable: true, style: s5.plainText, children: displayContent }) : /* @__PURE__ */ jsxRuntime.jsx(Markdown__default.default, { style: mdStyles, children: displayContent }) : !isThinkingStreaming && !hasThinkingContent ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s5.placeholder, children: "\u2026" }) : null,
1841
+ isCancelled && message.isStreaming ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s5.pausedRow, children: [
1842
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.WifiOff, { size: 14, color: "rgba(217, 119, 6, 0.85)", strokeWidth: 2 }),
1843
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s5.pausedText, children: "Connection slow \u2014 resuming\u2026" })
1844
+ ] }) : null,
1845
+ hasPartialError ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s5.errorRow, children: [
1846
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.AlertCircle, { size: 15, color: "#ef4444", strokeWidth: 2 }),
1847
+ resolvedErrorText ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { selectable: true, style: s5.errorText, children: resolvedErrorText }) : null
1848
+ ] }) : null,
1849
+ message.isStreaming && displayContent && !isCancelled ? /* @__PURE__ */ jsxRuntime.jsx(StreamingDot, {}) : null,
1850
+ isDone && showCopyAction ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s5.actions, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: handleCopy, hitSlop: 8, style: s5.actionBtn, children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Check, { size: 14, color: "#059669", strokeWidth: 2.5 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Copy, { size: 14, color: TEXT_TERTIARY, strokeWidth: 2 }) }) }) : null
1851
+ ] });
1852
+ }
1853
+ var s5 = reactNative.StyleSheet.create({
1854
+ wrapper: {
1855
+ paddingHorizontal: 16,
1856
+ paddingVertical: 6,
1857
+ alignItems: "flex-start"
1858
+ },
1859
+ plainText: {
1860
+ fontSize: 15,
1861
+ lineHeight: 23,
1862
+ color: TEXT_PRIMARY2
1863
+ },
1864
+ placeholder: {
1865
+ fontSize: 14,
1866
+ color: TEXT_MUTED
1867
+ },
1868
+ legacyThinking: {
1869
+ fontSize: 14,
1870
+ color: TEXT_SECONDARY2,
1871
+ fontStyle: "italic"
1872
+ },
1873
+ errorRow: {
1874
+ flexDirection: "row",
1875
+ alignItems: "flex-start",
1876
+ gap: 8,
1877
+ marginTop: 4
1878
+ },
1879
+ errorText: {
1880
+ flex: 1,
1881
+ fontSize: 14,
1882
+ color: "#ef4444",
1883
+ lineHeight: 20
1884
+ },
1885
+ pausedRow: {
1886
+ flexDirection: "row",
1887
+ alignItems: "center",
1888
+ gap: 6,
1889
+ marginTop: 6
1890
+ },
1891
+ pausedText: {
1892
+ fontSize: 13,
1893
+ color: "rgba(217, 119, 6, 0.95)"
1894
+ },
1895
+ actions: {
1896
+ flexDirection: "row",
1897
+ marginTop: 6,
1898
+ gap: 4
1899
+ },
1900
+ actionBtn: {
1901
+ padding: 6,
1902
+ borderRadius: 8
1903
+ }
1904
+ });
1905
+ var ts = reactNative.StyleSheet.create({
1906
+ container: {
1907
+ marginBottom: 8,
1908
+ paddingLeft: 4,
1909
+ alignSelf: "stretch"
1910
+ },
1911
+ header: {
1912
+ flexDirection: "row",
1913
+ alignItems: "center",
1914
+ gap: 8,
1915
+ paddingVertical: 4
1916
+ },
1917
+ headerLabelRow: {
1918
+ flexDirection: "row",
1919
+ alignItems: "center"
1920
+ },
1921
+ headerLabel: {
1922
+ fontSize: 13,
1923
+ color: TEXT_SECONDARY2,
1924
+ fontWeight: "500"
1925
+ },
1926
+ headerLabelStatic: {
1927
+ fontSize: 13,
1928
+ color: TEXT_SECONDARY2,
1929
+ fontWeight: "500"
1930
+ },
1931
+ timerText: {
1932
+ fontSize: 13,
1933
+ color: TEXT_TERTIARY,
1934
+ marginLeft: 6,
1935
+ fontVariant: ["tabular-nums"]
1936
+ },
1937
+ body: {
1938
+ marginTop: 6,
1939
+ marginLeft: 22,
1940
+ paddingLeft: 12,
1941
+ borderLeftWidth: 2,
1942
+ borderLeftColor: "rgba(0,133,141,0.15)",
1943
+ gap: 4
1944
+ },
1945
+ statement: {
1946
+ fontSize: 13,
1947
+ fontWeight: "500",
1948
+ color: TEXT_PRIMARY2,
1949
+ marginTop: 4
1950
+ },
1951
+ detail: {
1952
+ fontSize: 13,
1953
+ color: TEXT_SECONDARY2,
1954
+ lineHeight: 20
1955
+ },
1956
+ statusBadge: {
1957
+ alignSelf: "flex-start",
1958
+ borderRadius: 999,
1959
+ paddingHorizontal: 10,
1960
+ paddingVertical: 3,
1961
+ borderWidth: reactNative.StyleSheet.hairlineWidth,
1962
+ marginTop: 2
1963
+ },
1964
+ statusBadgeText: {
1965
+ fontSize: 11,
1966
+ fontWeight: "500"
1967
+ },
1968
+ statusSuccessBg: {
1969
+ backgroundColor: "rgba(5,150,105,0.06)",
1970
+ borderColor: "rgba(5,150,105,0.18)"
1971
+ },
1972
+ statusSuccessText: { color: "#059669" },
1973
+ statusErrorBg: {
1974
+ backgroundColor: "rgba(239,68,68,0.06)",
1975
+ borderColor: "rgba(239,68,68,0.18)"
1976
+ },
1977
+ statusErrorText: { color: "#ef4444" },
1978
+ cursorRow: {
1979
+ flexDirection: "row",
1980
+ alignItems: "center",
1981
+ gap: 8,
1982
+ marginTop: 4,
1983
+ minHeight: 18
1984
+ },
1985
+ cursorLabel: {
1986
+ fontSize: 13,
1987
+ color: TEXT_SECONDARY2
1988
+ }
1989
+ });
1990
+ var dotStyle = reactNative.StyleSheet.create({
1991
+ dot: {
1992
+ width: 7,
1993
+ height: 7,
1994
+ borderRadius: 4,
1995
+ backgroundColor: PAYMAN_TEAL2,
1996
+ marginTop: 6
1997
+ }
1998
+ });
1999
+ var mark = reactNative.StyleSheet.create({
2000
+ wrap: {
2001
+ alignItems: "center",
2002
+ justifyContent: "center",
2003
+ position: "relative"
2004
+ },
2005
+ ring: {
2006
+ position: "absolute",
2007
+ borderWidth: 1.5,
2008
+ borderColor: PAYMAN_TEAL2,
2009
+ backgroundColor: "transparent"
2010
+ },
2011
+ core: {
2012
+ backgroundColor: PAYMAN_TEAL2
2013
+ }
2014
+ });
2015
+ var mdStyles = reactNative.StyleSheet.create({
2016
+ body: {
2017
+ fontSize: 15,
2018
+ lineHeight: 23,
2019
+ color: TEXT_PRIMARY2
2020
+ },
2021
+ heading1: { fontSize: 20, fontWeight: "700", color: TEXT_PRIMARY2, marginTop: 12, marginBottom: 4 },
2022
+ heading2: { fontSize: 17, fontWeight: "700", color: TEXT_PRIMARY2, marginTop: 10, marginBottom: 4 },
2023
+ heading3: { fontSize: 15, fontWeight: "600", color: TEXT_PRIMARY2, marginTop: 8, marginBottom: 2 },
2024
+ strong: { fontWeight: "700" },
2025
+ em: { fontStyle: "italic" },
2026
+ code_inline: {
2027
+ fontFamily: reactNative.Platform.OS === "ios" ? "Menlo" : "monospace",
2028
+ fontSize: 13,
2029
+ backgroundColor: "rgba(15,23,42,0.06)",
2030
+ borderRadius: 4,
2031
+ paddingHorizontal: 4,
2032
+ color: TEXT_PRIMARY2
2033
+ },
2034
+ fence: {
2035
+ backgroundColor: "rgba(15,23,42,0.05)",
2036
+ borderRadius: 8,
2037
+ padding: 12,
2038
+ marginVertical: 6,
2039
+ fontFamily: reactNative.Platform.OS === "ios" ? "Menlo" : "monospace",
2040
+ fontSize: 13,
2041
+ color: TEXT_PRIMARY2
2042
+ },
2043
+ blockquote: {
2044
+ borderLeftWidth: 3,
2045
+ borderLeftColor: "#cbd5e1",
2046
+ paddingLeft: 12,
2047
+ marginLeft: 0,
2048
+ marginVertical: 4,
2049
+ opacity: 0.8
2050
+ },
2051
+ bullet_list: { marginVertical: 4 },
2052
+ ordered_list: { marginVertical: 4 },
2053
+ list_item: { marginVertical: 2 },
2054
+ hr: { backgroundColor: "rgba(15,23,42,0.1)", height: 1, marginVertical: 8 },
2055
+ link: { color: PAYMAN_TEAL2, textDecorationLine: "underline" },
2056
+ table: {
2057
+ borderWidth: 1,
2058
+ borderColor: "rgba(15,23,42,0.1)",
2059
+ borderRadius: 6,
2060
+ marginVertical: 6,
2061
+ overflow: "hidden"
2062
+ },
2063
+ th: { backgroundColor: "rgba(15,23,42,0.05)", padding: 8, fontWeight: "600", fontSize: 13 },
2064
+ td: {
2065
+ padding: 8,
2066
+ fontSize: 13,
2067
+ borderTopWidth: 1,
2068
+ borderTopColor: "rgba(15,23,42,0.07)"
2069
+ }
2070
+ });
2071
+ var NEAR_BOTTOM_THRESHOLD = 120;
2072
+ var MessageListV2 = React.forwardRef(
2073
+ function MessageListV22({
2074
+ messages,
2075
+ isLoadingSession = false,
2076
+ onEditUserMessage,
2077
+ onRetryUserMessage,
2078
+ onImageClick: _onImageClick,
2079
+ onExecutionTraceClick,
2080
+ messageActions,
2081
+ retryDisabled = false
2082
+ // userAction props are handled by the modal in PaymanChat.native — ignored here
2083
+ }, ref) {
2084
+ const scrollViewRef = React.useRef(null);
2085
+ const followingBottomRef = React.useRef(true);
2086
+ const isProgrammaticScrollRef = React.useRef(false);
2087
+ const prevCountRef = React.useRef(messages.length);
2088
+ const [showScrollBtn, setShowScrollBtn] = React.useState(false);
2089
+ const scrollToBottom = React.useCallback((animated = false) => {
2090
+ isProgrammaticScrollRef.current = true;
2091
+ followingBottomRef.current = true;
2092
+ setShowScrollBtn(false);
2093
+ scrollViewRef.current?.scrollToEnd({ animated });
2094
+ const clear = () => {
2095
+ isProgrammaticScrollRef.current = false;
2096
+ };
2097
+ if (animated) {
2098
+ setTimeout(clear, 400);
2099
+ } else {
2100
+ requestAnimationFrame(clear);
2101
+ }
2102
+ }, []);
2103
+ React.useImperativeHandle(
2104
+ ref,
2105
+ () => ({
2106
+ scrollToBottom: (animated = false) => scrollToBottom(animated)
2107
+ }),
2108
+ [scrollToBottom]
2109
+ );
2110
+ React.useEffect(() => {
2111
+ const prevCount = prevCountRef.current;
2112
+ prevCountRef.current = messages.length;
2113
+ if (messages.length > prevCount) {
2114
+ const last = messages[messages.length - 1];
2115
+ if (last?.role === "user" || followingBottomRef.current) {
2116
+ followingBottomRef.current = true;
2117
+ requestAnimationFrame(() => scrollToBottom(false));
2118
+ }
2119
+ }
2120
+ }, [messages.length, scrollToBottom]);
2121
+ React.useEffect(() => {
2122
+ if (messages.length > 0) {
2123
+ setTimeout(() => scrollToBottom(false), 50);
2124
+ }
2125
+ }, []);
2126
+ const handleContentSizeChange = React.useCallback(() => {
2127
+ if (followingBottomRef.current) {
2128
+ scrollViewRef.current?.scrollToEnd({ animated: false });
2129
+ }
2130
+ }, []);
2131
+ const handleScroll = React.useCallback(
2132
+ (e) => {
2133
+ if (isProgrammaticScrollRef.current) return;
2134
+ const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent;
2135
+ const distanceFromBottom = contentSize.height - contentOffset.y - layoutMeasurement.height;
2136
+ const nearBottom = distanceFromBottom <= NEAR_BOTTOM_THRESHOLD;
2137
+ followingBottomRef.current = nearBottom;
2138
+ setShowScrollBtn(!nearBottom);
2139
+ },
2140
+ []
2141
+ );
2142
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s6.root, children: [
2143
+ /* @__PURE__ */ jsxRuntime.jsxs(
2144
+ reactNative.ScrollView,
2145
+ {
2146
+ ref: scrollViewRef,
2147
+ style: s6.scroll,
2148
+ contentContainerStyle: s6.content,
2149
+ onScroll: handleScroll,
2150
+ onContentSizeChange: handleContentSizeChange,
2151
+ scrollEventThrottle: 16,
2152
+ keyboardDismissMode: "interactive",
2153
+ keyboardShouldPersistTaps: "handled",
2154
+ children: [
2155
+ isLoadingSession ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s6.loadingContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "large", color: "#00858d" }) }) : messages.map(
2156
+ (message) => message.role === "user" ? /* @__PURE__ */ jsxRuntime.jsx(
2157
+ UserMessageV2,
2158
+ {
2159
+ message,
2160
+ actions: messageActions?.userMessageActions,
2161
+ onEdit: onEditUserMessage,
2162
+ onRetry: onRetryUserMessage,
2163
+ retryDisabled
2164
+ },
2165
+ message.id
2166
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
2167
+ AssistantMessageV2,
2168
+ {
2169
+ message,
2170
+ onExecutionTraceClick,
2171
+ actions: messageActions?.assistantMessageActions
2172
+ },
2173
+ message.id
2174
+ )
2175
+ ),
2176
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s6.bottomPad })
2177
+ ]
2178
+ }
2179
+ ),
2180
+ showScrollBtn ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s6.scrollBtnContainer, pointerEvents: "box-none", children: /* @__PURE__ */ jsxRuntime.jsx(
2181
+ reactNative.Pressable,
2182
+ {
2183
+ style: s6.scrollBtn,
2184
+ onPress: () => scrollToBottom(true),
2185
+ hitSlop: 8,
2186
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ArrowDown, { size: 16, color: "#555", strokeWidth: 2.5 })
2187
+ }
2188
+ ) }) : null
2189
+ ] });
2190
+ }
2191
+ );
2192
+ var s6 = reactNative.StyleSheet.create({
2193
+ root: {
2194
+ flex: 1,
2195
+ minHeight: 0,
2196
+ position: "relative"
2197
+ },
2198
+ scroll: {
2199
+ flex: 1
2200
+ },
2201
+ content: {
2202
+ flexGrow: 1,
2203
+ paddingTop: 12,
2204
+ paddingBottom: 4
2205
+ },
2206
+ loadingContainer: {
2207
+ flex: 1,
2208
+ alignItems: "center",
2209
+ justifyContent: "center",
2210
+ paddingVertical: 60
2211
+ },
2212
+ bottomPad: {
2213
+ height: 16
2214
+ },
2215
+ scrollBtnContainer: {
2216
+ position: "absolute",
2217
+ bottom: 16,
2218
+ left: 0,
2219
+ right: 0,
2220
+ alignItems: "center"
2221
+ },
2222
+ scrollBtn: {
2223
+ backgroundColor: "#fff",
2224
+ borderRadius: 20,
2225
+ width: 36,
2226
+ height: 36,
2227
+ alignItems: "center",
2228
+ justifyContent: "center",
2229
+ shadowColor: "#000",
2230
+ shadowOffset: { width: 0, height: 2 },
2231
+ shadowOpacity: 0.12,
2232
+ shadowRadius: 6,
2233
+ elevation: 4,
2234
+ borderWidth: 1,
2235
+ borderColor: "rgba(0,0,0,0.07)"
2236
+ }
2237
+ });
2238
+ var COMPACT_BREAKPOINT = 560;
2239
+ var PAYMAN_GREEN = "#0A3B44";
2240
+ function getCategoryGlyph(label) {
2241
+ const normalizedLabel = label.toLowerCase();
2242
+ if (normalizedLabel.includes("pay") || normalizedLabel.includes("transfer")) return "->";
2243
+ if (normalizedLabel.includes("account")) return "[]";
2244
+ if (normalizedLabel.includes("insight") || normalizedLabel.includes("analytics")) return "/_";
2245
+ if (normalizedLabel.includes("product")) return "o";
2246
+ return "+";
2247
+ }
2248
+ function formatSuggestionTitle(value) {
2249
+ return value.replace(
2250
+ /\b(Good (?:morning|afternoon|evening))[ \t]+(?=how can I help)/i,
2251
+ "$1 - "
2252
+ );
2253
+ }
2254
+ function PromptSuggestionsV2({
2255
+ title,
2256
+ categories,
2257
+ disabled = false,
2258
+ onPromptClick
2259
+ }) {
2260
+ const { width } = reactNative.useWindowDimensions();
2261
+ const isCompact = width < COMPACT_BREAKPOINT;
2262
+ const validCategories = React.useMemo(
2263
+ () => categories.filter((category) => category.prompts.length > 0),
2264
+ [categories]
2265
+ );
2266
+ const [activeCategoryIndex, setActiveCategoryIndex] = React.useState(null);
2267
+ React.useEffect(() => {
2268
+ if (activeCategoryIndex != null && (activeCategoryIndex < 0 || activeCategoryIndex >= validCategories.length)) {
2269
+ setActiveCategoryIndex(null);
2270
+ }
2271
+ }, [activeCategoryIndex, validCategories.length]);
2272
+ if (validCategories.length === 0) return null;
2273
+ const activeCategory = activeCategoryIndex == null ? null : validCategories[activeCategoryIndex] ?? null;
2274
+ const displayTitle = title ? formatSuggestionTitle(title) : void 0;
2275
+ const categoryButtons = validCategories.map((category, categoryIndex) => {
2276
+ const isActive = activeCategoryIndex === categoryIndex;
2277
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2278
+ reactNative.Pressable,
2279
+ {
2280
+ accessibilityRole: "button",
2281
+ accessibilityLabel: `${category.label} prompts`,
2282
+ accessibilityState: { expanded: isActive, selected: isActive },
2283
+ onPress: () => setActiveCategoryIndex(
2284
+ (currentIndex) => currentIndex === categoryIndex ? null : categoryIndex
2285
+ ),
2286
+ style: ({ pressed }) => [
2287
+ styles.categoryButton,
2288
+ isActive && styles.categoryButtonActive,
2289
+ pressed && styles.categoryButtonPressed
2290
+ ],
2291
+ children: [
2292
+ category.icon ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.customIcon, children: category.icon }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.categoryIcon, isActive && styles.categoryIconActive], children: getCategoryGlyph(category.label) }),
2293
+ /* @__PURE__ */ jsxRuntime.jsx(
2294
+ reactNative.Text,
2295
+ {
2296
+ numberOfLines: 1,
2297
+ style: [styles.categoryText, isActive && styles.categoryTextActive],
2298
+ children: category.label
2299
+ }
2300
+ )
2301
+ ]
2302
+ },
2303
+ `${category.label}-${categoryIndex}`
2304
+ );
2305
+ });
2306
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.root, children: [
2307
+ displayTitle ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.title, isCompact && styles.titleCompact], children: displayTitle }) : null,
2308
+ isCompact ? /* @__PURE__ */ jsxRuntime.jsx(
2309
+ reactNative.ScrollView,
2310
+ {
2311
+ horizontal: true,
2312
+ showsHorizontalScrollIndicator: false,
2313
+ contentContainerStyle: styles.categoryScrollContent,
2314
+ style: styles.categoryScroll,
2315
+ children: categoryButtons
2316
+ }
2317
+ ) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.categoryWrap, children: categoryButtons }),
2318
+ activeCategory ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.promptCard, isCompact && styles.promptCardCompact], children: activeCategory.prompts.map((prompt, promptIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
2319
+ reactNative.Pressable,
2320
+ {
2321
+ accessibilityRole: "button",
2322
+ accessibilityLabel: `Use suggested prompt: ${prompt}`,
2323
+ disabled,
2324
+ onPress: () => onPromptClick(prompt),
2325
+ style: ({ pressed }) => [
2326
+ styles.promptButton,
2327
+ promptIndex > 0 && styles.promptButtonDivider,
2328
+ pressed && !disabled && styles.promptButtonPressed,
2329
+ disabled && styles.promptButtonDisabled
2330
+ ],
2331
+ children: [
2332
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.promptText, children: prompt }),
2333
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.promptArrow, children: "->" })
2334
+ ]
2335
+ },
2336
+ `${prompt}-${promptIndex}`
2337
+ )) }) : null
2338
+ ] });
2339
+ }
2340
+ var styles = reactNative.StyleSheet.create({
2341
+ root: {
2342
+ width: "100%",
2343
+ alignItems: "center"
2344
+ },
2345
+ title: {
2346
+ marginBottom: 8,
2347
+ color: "#18181b",
2348
+ fontSize: 16,
2349
+ fontWeight: "500",
2350
+ lineHeight: 24,
2351
+ textAlign: "center"
2352
+ },
2353
+ titleCompact: {
2354
+ maxWidth: 340,
2355
+ paddingHorizontal: 16,
2356
+ fontSize: 16,
2357
+ lineHeight: 24
2358
+ },
2359
+ categoryWrap: {
2360
+ width: "100%",
2361
+ flexDirection: "row",
2362
+ flexWrap: "wrap",
2363
+ justifyContent: "center",
2364
+ marginBottom: 12
2365
+ },
2366
+ categoryScroll: {
2367
+ width: "100%",
2368
+ marginBottom: 12
2369
+ },
2370
+ categoryScrollContent: {
2371
+ paddingHorizontal: 16,
2372
+ paddingVertical: 2
2373
+ },
2374
+ categoryButton: {
2375
+ minHeight: 30,
2376
+ flexDirection: "row",
2377
+ alignItems: "center",
2378
+ justifyContent: "center",
2379
+ marginHorizontal: 4,
2380
+ marginVertical: 4,
2381
+ paddingHorizontal: 12,
2382
+ paddingVertical: 6,
2383
+ borderWidth: 1,
2384
+ borderColor: "#e4e4e7",
2385
+ borderRadius: 999,
2386
+ backgroundColor: "#ffffff"
2387
+ },
2388
+ categoryButtonActive: {
2389
+ borderColor: PAYMAN_GREEN,
2390
+ backgroundColor: PAYMAN_GREEN
2391
+ },
2392
+ categoryButtonPressed: {
2393
+ opacity: 0.82
2394
+ },
2395
+ customIcon: {
2396
+ marginRight: 6
2397
+ },
2398
+ categoryIcon: {
2399
+ marginRight: 6,
2400
+ color: PAYMAN_GREEN,
2401
+ fontSize: 11,
2402
+ fontWeight: "700",
2403
+ lineHeight: 14
2404
+ },
2405
+ categoryIconActive: {
2406
+ color: "#ffffff"
2407
+ },
2408
+ categoryText: {
2409
+ maxWidth: 180,
2410
+ color: "#3f3f46",
2411
+ fontSize: 11,
2412
+ fontWeight: "600",
2413
+ lineHeight: 14
2414
+ },
2415
+ categoryTextActive: {
2416
+ color: "#ffffff"
2417
+ },
2418
+ promptCard: {
2419
+ width: "100%",
2420
+ maxWidth: 600,
2421
+ overflow: "hidden",
2422
+ borderWidth: 1,
2423
+ borderColor: "#e4e4e7",
2424
+ borderRadius: 16,
2425
+ backgroundColor: "#ffffff"
2426
+ },
2427
+ promptCardCompact: {
2428
+ width: "auto",
2429
+ alignSelf: "stretch",
2430
+ marginHorizontal: 16,
2431
+ borderRadius: 14
2432
+ },
2433
+ promptButton: {
2434
+ minHeight: 50,
2435
+ flexDirection: "row",
2436
+ alignItems: "center",
2437
+ justifyContent: "space-between",
2438
+ paddingHorizontal: 16,
2439
+ paddingVertical: 12
2440
+ },
2441
+ promptButtonDivider: {
2442
+ borderTopWidth: 1,
2443
+ borderTopColor: "#e4e4e7"
2444
+ },
2445
+ promptButtonPressed: {
2446
+ backgroundColor: "#eef7f7"
2447
+ },
2448
+ promptButtonDisabled: {
2449
+ opacity: 0.5
2450
+ },
2451
+ promptText: {
2452
+ flex: 1,
2453
+ paddingRight: 12,
2454
+ color: "#27272a",
2455
+ fontSize: 13,
2456
+ lineHeight: 18
2457
+ },
2458
+ promptArrow: {
2459
+ color: PAYMAN_GREEN,
2460
+ fontSize: 13,
2461
+ lineHeight: 16
2462
+ }
2463
+ });
2464
+ var WaveformBar = React.memo(
2465
+ ({
2466
+ delay,
2467
+ isActive,
2468
+ color
2469
+ }) => {
2470
+ const height = React.useRef(new reactNative.Animated.Value(6)).current;
2471
+ React.useEffect(() => {
2472
+ if (isActive) {
2473
+ const animation = reactNative.Animated.loop(
2474
+ reactNative.Animated.sequence([
2475
+ reactNative.Animated.timing(height, {
2476
+ toValue: 14 + Math.random() * 10,
2477
+ duration: 300 + Math.random() * 50,
2478
+ delay,
2479
+ easing: reactNative.Easing.inOut(reactNative.Easing.ease),
2480
+ useNativeDriver: false
2481
+ }),
2482
+ reactNative.Animated.timing(height, {
2483
+ toValue: 6 + Math.random() * 4,
2484
+ duration: 300 + Math.random() * 50,
2485
+ easing: reactNative.Easing.inOut(reactNative.Easing.ease),
2486
+ useNativeDriver: false
2487
+ })
2488
+ ])
2489
+ );
2490
+ animation.start();
2491
+ return () => animation.stop();
2492
+ } else {
2493
+ reactNative.Animated.timing(height, {
2494
+ toValue: 6,
2495
+ duration: 300,
2496
+ useNativeDriver: false
2497
+ }).start();
2498
+ }
2499
+ }, [isActive, delay, height]);
2500
+ return /* @__PURE__ */ jsxRuntime.jsx(
2501
+ reactNative.Animated.View,
2502
+ {
2503
+ style: [styles2.waveformBar, { height, backgroundColor: color }]
2504
+ }
2505
+ );
2506
+ }
2507
+ );
2508
+ WaveformBar.displayName = "WaveformBar";
2509
+ var RollingText = React.memo(({ text, color }) => {
2510
+ const [lines, setLines] = React__default.default.useState([]);
2511
+ const [currentLineIndex, setCurrentLineIndex] = React__default.default.useState(0);
2512
+ const translateY = React.useRef(new reactNative.Animated.Value(0)).current;
2513
+ const opacity = React.useRef(new reactNative.Animated.Value(1)).current;
2514
+ React.useEffect(() => {
2515
+ if (!text) {
2516
+ setLines([]);
2517
+ setCurrentLineIndex(0);
2518
+ return;
2519
+ }
2520
+ const words = text.split(" ");
2521
+ const newLines = [];
2522
+ let currentLine = "";
2523
+ words.forEach((word) => {
2524
+ const testLine = currentLine ? `${currentLine} ${word}` : word;
2525
+ if (testLine.length > 35 && currentLine) {
2526
+ newLines.push(currentLine);
2527
+ currentLine = word;
2528
+ } else {
2529
+ currentLine = testLine;
2530
+ }
2531
+ });
2532
+ if (currentLine) {
2533
+ newLines.push(currentLine);
2534
+ }
2535
+ setLines(newLines);
2536
+ if (newLines.length > 0) {
2537
+ const newIndex = newLines.length - 1;
2538
+ if (newIndex > currentLineIndex) {
2539
+ reactNative.Animated.sequence([
2540
+ reactNative.Animated.parallel([
2541
+ reactNative.Animated.timing(translateY, {
2542
+ toValue: -20,
2543
+ duration: 150,
2544
+ useNativeDriver: true
2545
+ }),
2546
+ reactNative.Animated.timing(opacity, {
2547
+ toValue: 0,
2548
+ duration: 150,
2549
+ useNativeDriver: true
2550
+ })
2551
+ ]),
2552
+ reactNative.Animated.timing(translateY, {
2553
+ toValue: 20,
2554
+ duration: 0,
2555
+ useNativeDriver: true
2556
+ }),
2557
+ reactNative.Animated.parallel([
2558
+ reactNative.Animated.timing(translateY, {
2559
+ toValue: 0,
2560
+ duration: 200,
2561
+ easing: reactNative.Easing.out(reactNative.Easing.ease),
2562
+ useNativeDriver: true
2563
+ }),
2564
+ reactNative.Animated.timing(opacity, {
2565
+ toValue: 1,
2566
+ duration: 200,
2567
+ useNativeDriver: true
2568
+ })
2569
+ ])
2570
+ ]).start();
2571
+ setCurrentLineIndex(newIndex);
2572
+ }
2573
+ }
2574
+ }, [text, currentLineIndex, translateY, opacity]);
2575
+ const currentText = lines[currentLineIndex] || text;
2576
+ return /* @__PURE__ */ jsxRuntime.jsx(
2577
+ reactNative.Animated.Text,
2578
+ {
2579
+ style: [
2580
+ styles2.transcribedText,
2581
+ {
2582
+ color,
2583
+ opacity,
2584
+ transform: [{ translateY }]
2585
+ }
2586
+ ],
2587
+ numberOfLines: 1,
2588
+ children: currentText
2589
+ }
2590
+ );
2591
+ });
2592
+ RollingText.displayName = "RollingText";
2593
+ var VoiceOverlay = React.memo(
2594
+ ({
2595
+ visible,
2596
+ voiceState,
2597
+ transcribedText,
2598
+ onStopRecording
2599
+ }) => {
2600
+ const panelHeight = React.useRef(new reactNative.Animated.Value(0)).current;
2601
+ const contentOpacity = React.useRef(new reactNative.Animated.Value(0)).current;
2602
+ const [mounted, setMounted] = React.useState(false);
2603
+ const isListening = voiceState === "listening";
2604
+ const PANEL_CONTENT_HEIGHT = 160;
2605
+ const bgColor = "#15687d";
2606
+ const textColor = "#ffffff";
2607
+ const mutedColor = "rgba(255,255,255,0.75)";
2608
+ const primaryColor = "#ffffff";
2609
+ React.useEffect(() => {
2610
+ if (visible) {
2611
+ setMounted(true);
2612
+ reactNative.Animated.sequence([
2613
+ reactNative.Animated.timing(panelHeight, {
2614
+ toValue: PANEL_CONTENT_HEIGHT,
2615
+ duration: 300,
2616
+ easing: reactNative.Easing.out(reactNative.Easing.cubic),
2617
+ useNativeDriver: false
2618
+ }),
2619
+ reactNative.Animated.timing(contentOpacity, {
2620
+ toValue: 1,
2621
+ duration: 150,
2622
+ useNativeDriver: true
2623
+ })
2624
+ ]).start();
2625
+ } else {
2626
+ reactNative.Animated.parallel([
2627
+ reactNative.Animated.timing(contentOpacity, {
2628
+ toValue: 0,
2629
+ duration: 100,
2630
+ useNativeDriver: true
2631
+ }),
2632
+ reactNative.Animated.timing(panelHeight, {
2633
+ toValue: 0,
2634
+ duration: 220,
2635
+ easing: reactNative.Easing.in(reactNative.Easing.ease),
2636
+ useNativeDriver: false
2637
+ })
2638
+ ]).start(() => setMounted(false));
2639
+ }
2640
+ }, [visible, panelHeight, contentOpacity]);
2641
+ if (!mounted) return null;
2642
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onStopRecording, style: styles2.panelWrapper, children: /* @__PURE__ */ jsxRuntime.jsx(
2643
+ reactNative.Animated.View,
2644
+ {
2645
+ style: [
2646
+ styles2.panel,
2647
+ {
2648
+ height: panelHeight,
2649
+ backgroundColor: bgColor
2650
+ }
2651
+ ],
2652
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Animated.View, { style: [styles2.content, { opacity: contentOpacity }], children: [
2653
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.textContainer, children: transcribedText.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(RollingText, { text: transcribedText, color: textColor }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.placeholderText, { color: mutedColor }], children: "Listening..." }) }),
2654
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.controlsContainer, children: [
2655
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.waveformContainer, children: [0, 1, 2, 3, 4].map((index) => /* @__PURE__ */ jsxRuntime.jsx(
2656
+ WaveformBar,
2657
+ {
2658
+ delay: index * 20,
2659
+ isActive: isListening,
2660
+ color: primaryColor
2661
+ },
2662
+ index
2663
+ )) }),
2664
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.hintText, { color: mutedColor }], children: "Tap to stop" })
2665
+ ] })
2666
+ ] })
2667
+ }
2668
+ ) });
2669
+ }
2670
+ );
2671
+ VoiceOverlay.displayName = "VoiceOverlay";
2672
+ var styles2 = reactNative.StyleSheet.create({
2673
+ panelWrapper: {
2674
+ zIndex: 10,
2675
+ elevation: 10
2676
+ },
2677
+ panel: {
2678
+ overflow: "hidden",
2679
+ borderTopLeftRadius: 20,
2680
+ borderTopRightRadius: 20
2681
+ },
2682
+ content: {
2683
+ flex: 1,
2684
+ paddingHorizontal: 24,
2685
+ paddingTop: 20
2686
+ },
2687
+ textContainer: {
2688
+ height: 32,
2689
+ justifyContent: "center",
2690
+ marginBottom: 16,
2691
+ overflow: "hidden"
2692
+ },
2693
+ transcribedText: {
2694
+ fontSize: 18,
2695
+ fontWeight: "500",
2696
+ textAlign: "left"
2697
+ },
2698
+ placeholderText: {
2699
+ fontSize: 15,
2700
+ textAlign: "left",
2701
+ fontWeight: "800"
2702
+ },
2703
+ controlsContainer: {
2704
+ flex: 1,
2705
+ alignItems: "center",
2706
+ justifyContent: "flex-start"
2707
+ },
2708
+ waveformContainer: {
2709
+ flexDirection: "row",
2710
+ alignItems: "center",
2711
+ justifyContent: "center",
2712
+ gap: 5,
2713
+ height: 28,
2714
+ marginBottom: 12
2715
+ },
2716
+ waveformBar: {
2717
+ width: 3,
2718
+ borderRadius: 2
2719
+ },
2720
+ hintText: {
2721
+ fontSize: 12
2722
+ }
2723
+ });
2724
+ var DEFAULT_ACCENT = "#00858d";
2725
+ function getPalette(theme, accent) {
2726
+ if (theme === "dark") {
2727
+ return {
2728
+ background: "#0d1719",
2729
+ textPrimary: "#f5f8f8",
2730
+ textSecondary: "rgba(245,248,248,0.72)",
2731
+ textMuted: "rgba(245,248,248,0.45)",
2732
+ heroHaloFrom: "rgba(0,133,141,0.16)",
2733
+ heroHaloTo: "rgba(0,133,141,0.06)",
2734
+ heroRing: "rgba(0,133,141,0.35)",
2735
+ heroDot: accent,
2736
+ disabledText: "rgba(245,248,248,0.45)"
2737
+ };
2738
+ }
2739
+ return {
2740
+ background: "#ffffff",
2741
+ textPrimary: "#1d1d1f",
2742
+ textSecondary: "#5e5d5a",
2743
+ textMuted: "#8a8a86",
2744
+ heroHaloFrom: "rgba(0,133,141,0.10)",
2745
+ heroHaloTo: "rgba(0,133,141,0.02)",
2746
+ heroRing: "rgba(0,133,141,0.20)",
2747
+ heroDot: accent,
2748
+ disabledText: "#8a8a86"
2749
+ };
2750
+ }
2751
+ var PaymanChat = React.forwardRef(
2752
+ function PaymanChat2({ config, callbacks = {}, children }, ref) {
2753
+ const {
2754
+ messages,
2755
+ sendMessage,
2756
+ clearMessages,
2757
+ cancelStream,
2758
+ resetSession: resetChatSession,
2759
+ getSessionId,
2760
+ getMessages,
2761
+ isWaitingForResponse,
2762
+ userActionState,
2763
+ approveUserAction,
2764
+ rejectUserAction,
2765
+ resendOtp,
2766
+ loadSession,
2767
+ loadingSessionId
2768
+ } = paymanTypescriptAskSdk.useChatV2(config, callbacks);
2769
+ const voiceEnabled = config.ui?.input?.voice === true || typeof config.ui?.input?.voice === "object" && config.ui.input.voice !== null;
2770
+ const {
2771
+ voiceState,
2772
+ transcribedText,
2773
+ isAvailable: voiceAvailable,
2774
+ isRecording,
2775
+ startRecording,
2776
+ stopRecording,
2777
+ clearTranscript
2778
+ } = paymanTypescriptAskSdk.useVoice();
2779
+ const attachmentsCfg = config.ui?.input?.attachments;
2780
+ const attachmentsAllowed = attachmentsCfg === void 0 || attachmentsCfg === true || typeof attachmentsCfg === "object" && attachmentsCfg !== null;
2781
+ const showUploadImage = attachmentsAllowed && (typeof attachmentsCfg !== "object" || attachmentsCfg === null ? true : attachmentsCfg.uploadImage !== false);
2782
+ const showAttachFile = attachmentsAllowed && (typeof attachmentsCfg !== "object" || attachmentsCfg === null ? true : attachmentsCfg.attachFile !== false);
2783
+ const [hasEverSentMessage, setHasEverSentMessage] = React.useState(false);
2784
+ const chatInputRef = React.useRef(null);
2785
+ const messageListRef = React.useRef(null);
2786
+ const resetToEmptyRef = React.useRef(false);
2787
+ React.useEffect(() => {
2788
+ if (resetToEmptyRef.current) {
2789
+ if (messages.length === 0) {
2790
+ setHasEverSentMessage(false);
2791
+ resetToEmptyRef.current = false;
2792
+ }
2793
+ return;
2794
+ }
2795
+ if (messages.length > 0 && !hasEverSentMessage) {
2796
+ setHasEverSentMessage(true);
2797
+ }
2798
+ }, [messages.length, hasEverSentMessage]);
2799
+ const prevRecordingRef = React.useRef(isRecording);
2800
+ React.useEffect(() => {
2801
+ const wasRecording = prevRecordingRef.current;
2802
+ prevRecordingRef.current = isRecording;
2803
+ if (wasRecording && !isRecording && transcribedText.trim()) {
2804
+ chatInputRef.current?.setDraft(transcribedText.trim());
2805
+ }
2806
+ }, [isRecording, transcribedText]);
2807
+ const handleVoicePress = React.useCallback(async () => {
2808
+ if (!voiceAvailable) return;
2809
+ if (isRecording) {
2810
+ stopRecording();
2811
+ return;
2812
+ }
2813
+ clearTranscript();
2814
+ await startRecording();
2815
+ }, [voiceAvailable, isRecording, stopRecording, clearTranscript, startRecording]);
2816
+ const handleSend = React.useCallback(
2817
+ (text) => {
2818
+ if (isRecording) stopRecording();
2819
+ if (!text.trim()) return;
2820
+ void sendMessage(text.trim());
2821
+ },
2822
+ [isRecording, stopRecording, sendMessage]
2823
+ );
2824
+ const dismissKeyboard = React.useCallback(() => {
2825
+ reactNative.Keyboard.dismiss();
2826
+ }, []);
2827
+ const handleEditMessageDraft = React.useCallback(
2828
+ (messageId) => {
2829
+ const targetMessage = messages.find(
2830
+ (message) => message.id === messageId && message.role === "user"
2831
+ );
2832
+ if (!targetMessage?.content.trim()) return;
2833
+ chatInputRef.current?.setDraft(targetMessage.content);
2834
+ requestAnimationFrame(() => {
2835
+ messageListRef.current?.scrollToBottom(true);
2836
+ });
2837
+ },
2838
+ [messages]
2839
+ );
2840
+ const handleRetryUserMessage = React.useCallback(
2841
+ (messageId) => {
2842
+ if (isWaitingForResponse) return;
2843
+ const targetMessage = messages.find(
2844
+ (message) => message.id === messageId && message.role === "user"
2845
+ );
2846
+ if (!targetMessage?.content.trim()) return;
2847
+ void sendMessage(targetMessage.content.trim());
2848
+ requestAnimationFrame(() => {
2849
+ messageListRef.current?.scrollToBottom(false);
2850
+ });
2851
+ },
2852
+ [isWaitingForResponse, messages, sendMessage]
2853
+ );
2854
+ const performResetSession = React.useCallback(() => {
2855
+ resetToEmptyRef.current = true;
2856
+ if (isRecording) stopRecording();
2857
+ clearTranscript();
2858
+ chatInputRef.current?.setDraft("");
2859
+ resetChatSession();
2860
+ callbacks.onResetSession?.();
2861
+ }, [isRecording, stopRecording, clearTranscript, resetChatSession, callbacks]);
2862
+ React.useImperativeHandle(
2863
+ ref,
2864
+ () => ({
2865
+ resetSession: performResetSession,
2866
+ clearMessages,
2867
+ cancelStream,
2868
+ getSessionId,
2869
+ getMessages,
2870
+ loadSession
2871
+ }),
2872
+ [performResetSession, clearMessages, cancelStream, getSessionId, getMessages, loadSession]
2873
+ );
2874
+ const ui = config.ui ?? {};
2875
+ const theme = ui.theme === "dark" ? "dark" : "light";
2876
+ const accent = ui.accent ?? DEFAULT_ACCENT;
2877
+ const palette = React.useMemo(() => getPalette(theme, accent), [theme, accent]);
2878
+ const placeholder = ui.input?.placeholder ?? "Type your message\u2026";
2879
+ const showResetButton = ui.input?.showResetButton ?? false;
2880
+ const messageActionsConfig = ui.messages?.actions;
2881
+ const messageActions = React.useMemo(
2882
+ () => ({
2883
+ userMessageActions: {
2884
+ copy: messageActionsConfig?.userMessageActions?.copy ?? true,
2885
+ edit: messageActionsConfig?.userMessageActions?.edit ?? false,
2886
+ retry: messageActionsConfig?.userMessageActions?.retry ?? false
2887
+ },
2888
+ assistantMessageActions: {
2889
+ copy: messageActionsConfig?.assistantMessageActions?.copy ?? true,
2890
+ trace: messageActionsConfig?.assistantMessageActions?.trace ?? true
2891
+ }
2892
+ }),
2893
+ [messageActionsConfig]
2894
+ );
2895
+ const isEmpty = messages.length === 0;
2896
+ const showEmptyShell = isEmpty && !hasEverSentMessage;
2897
+ const emptyStateText = ui.emptyState?.text ?? "How may I assist you today?";
2898
+ const emptyStateEyebrow = ui.emptyState?.eyebrow;
2899
+ const showEmptyIcon = ui.emptyState?.icon ?? true;
2900
+ const emptyStateLogo = ui.emptyState?.logo;
2901
+ const suggestions = ui.emptyState?.suggestions;
2902
+ const showSuggestions = suggestions != null && suggestions.enabled !== false && suggestions.categories.some((category) => category.prompts.length > 0);
2903
+ const availability = config.availability;
2904
+ if (availability?.state === "disabled") {
2905
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [s7.root, { backgroundColor: palette.background }], children: [
2906
+ children,
2907
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s7.disabledContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [s7.disabledText, { color: palette.disabledText }], children: "Chat is currently disabled" }) })
2908
+ ] });
2909
+ }
2910
+ const isReadOnly = availability?.state === "readOnly";
2911
+ const hideSendForVerification = userActionState.request != null && userActionState.result == null;
2912
+ const verificationPanel = userActionState.request ? /* @__PURE__ */ jsxRuntime.jsx(
2913
+ InlineVerificationPanel,
2914
+ {
2915
+ userActionRequest: userActionState.request,
2916
+ clearOtpTrigger: userActionState.clearOtpTrigger,
2917
+ onApprove: approveUserAction,
2918
+ onReject: rejectUserAction,
2919
+ onResend: resendOtp
2920
+ }
2921
+ ) : null;
2922
+ const inputProps = {
2923
+ onSend: handleSend,
2924
+ onCancel: cancelStream,
2925
+ disabled: false,
2926
+ isStreaming: isWaitingForResponse,
2927
+ placeholder: isRecording ? "Listening\u2026" : placeholder,
2928
+ enableVoice: voiceEnabled,
2929
+ voiceAvailable: voiceEnabled && voiceAvailable,
2930
+ isRecording,
2931
+ onVoicePress: voiceEnabled ? handleVoicePress : void 0,
2932
+ showResetSession: showResetButton,
2933
+ onResetSession: performResetSession,
2934
+ showUploadImageButton: showUploadImage,
2935
+ showAttachFileButton: showAttachFile,
2936
+ onUploadImageClick: callbacks.onUploadImageClick,
2937
+ onAttachFileClick: callbacks.onAttachFileClick,
2938
+ theme,
2939
+ hideSendButton: hideSendForVerification,
2940
+ topAccessory: verificationPanel
2941
+ };
2942
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2943
+ reactNative.KeyboardAvoidingView,
2944
+ {
2945
+ style: [s7.root, { backgroundColor: palette.background }],
2946
+ behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
2947
+ keyboardVerticalOffset: 0,
2948
+ children: [
2949
+ children,
2950
+ showEmptyShell ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s7.emptyStateRoot, children: [
2951
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s7.emptyStateCenter, onTouchStart: dismissKeyboard, children: [
2952
+ emptyStateLogo ? emptyStateLogo : showEmptyIcon ? /* @__PURE__ */ jsxRuntime.jsx(HeroMark, { palette }) : null,
2953
+ emptyStateEyebrow ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [s7.emptyEyebrow, { color: palette.textMuted }], children: emptyStateEyebrow }) : null,
2954
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [s7.emptyStateText, { color: "#94a3b8" }], children: emptyStateText }),
2955
+ !emptyStateLogo && !showSuggestions ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [s7.emptyStateSubtext, { color: palette.textSecondary }], children: "Ask anything about your accounts, payments, or transfers." }) : null,
2956
+ showSuggestions ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s7.emptySuggestions, children: /* @__PURE__ */ jsxRuntime.jsx(
2957
+ PromptSuggestionsV2,
2958
+ {
2959
+ categories: suggestions.categories,
2960
+ disabled: isWaitingForResponse,
2961
+ onPromptClick: handleSend
2962
+ }
2963
+ ) }) : null
2964
+ ] }),
2965
+ !isReadOnly ? /* @__PURE__ */ jsxRuntime.jsx(ChatInputV2, { ref: chatInputRef, ...inputProps }) : null
2966
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2967
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: s7.messageListWrapper, onTouchStart: dismissKeyboard, children: /* @__PURE__ */ jsxRuntime.jsx(
2968
+ MessageListV2,
2969
+ {
2970
+ ref: messageListRef,
2971
+ messages,
2972
+ isStreaming: isWaitingForResponse,
2973
+ isLoadingSession: !!loadingSessionId,
2974
+ onEditUserMessage: handleEditMessageDraft,
2975
+ onRetryUserMessage: handleRetryUserMessage,
2976
+ onExecutionTraceClick: callbacks.onExecutionTraceClick,
2977
+ messageActions,
2978
+ retryDisabled: isWaitingForResponse
2979
+ }
2980
+ ) }),
2981
+ voiceEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
2982
+ VoiceOverlay,
2983
+ {
2984
+ visible: isRecording,
2985
+ voiceState,
2986
+ transcribedText,
2987
+ onStopRecording: stopRecording
2988
+ }
2989
+ ) : null,
2990
+ !isReadOnly ? /* @__PURE__ */ jsxRuntime.jsx(
2991
+ ChatInputV2,
2992
+ {
2993
+ ref: chatInputRef,
2994
+ ...inputProps
2995
+ }
2996
+ ) : null
2997
+ ] })
2998
+ ]
2999
+ }
3000
+ );
28
3001
  }
29
- n.default = e;
30
- return Object.freeze(n);
3002
+ );
3003
+ function HeroMark({ palette }) {
3004
+ const scale = React.useRef(new reactNative.Animated.Value(0.92)).current;
3005
+ const opacity = React.useRef(new reactNative.Animated.Value(0)).current;
3006
+ const ringSpin = React.useRef(new reactNative.Animated.Value(0)).current;
3007
+ const dotPulse = React.useRef(new reactNative.Animated.Value(0)).current;
3008
+ React.useEffect(() => {
3009
+ reactNative.Animated.parallel([
3010
+ reactNative.Animated.timing(opacity, {
3011
+ toValue: 1,
3012
+ duration: 420,
3013
+ easing: reactNative.Easing.out(reactNative.Easing.cubic),
3014
+ useNativeDriver: true
3015
+ }),
3016
+ reactNative.Animated.spring(scale, {
3017
+ toValue: 1,
3018
+ friction: 6,
3019
+ tension: 90,
3020
+ useNativeDriver: true
3021
+ })
3022
+ ]).start();
3023
+ reactNative.Animated.loop(
3024
+ reactNative.Animated.timing(ringSpin, {
3025
+ toValue: 1,
3026
+ duration: 14e3,
3027
+ easing: reactNative.Easing.linear,
3028
+ useNativeDriver: true
3029
+ })
3030
+ ).start();
3031
+ reactNative.Animated.loop(
3032
+ reactNative.Animated.sequence([
3033
+ reactNative.Animated.timing(dotPulse, {
3034
+ toValue: 1,
3035
+ duration: 1600,
3036
+ easing: reactNative.Easing.inOut(reactNative.Easing.cubic),
3037
+ useNativeDriver: true
3038
+ }),
3039
+ reactNative.Animated.timing(dotPulse, {
3040
+ toValue: 0,
3041
+ duration: 1600,
3042
+ easing: reactNative.Easing.inOut(reactNative.Easing.cubic),
3043
+ useNativeDriver: true
3044
+ })
3045
+ ])
3046
+ ).start();
3047
+ }, [opacity, scale, ringSpin, dotPulse]);
3048
+ const ringRotate = ringSpin.interpolate({
3049
+ inputRange: [0, 1],
3050
+ outputRange: ["0deg", "360deg"]
3051
+ });
3052
+ const dotScale = dotPulse.interpolate({
3053
+ inputRange: [0, 1],
3054
+ outputRange: [0.92, 1.06]
3055
+ });
3056
+ return /* @__PURE__ */ jsxRuntime.jsx(
3057
+ reactNative.Animated.View,
3058
+ {
3059
+ style: [hero.halo, {
3060
+ backgroundColor: palette.heroHaloFrom,
3061
+ opacity,
3062
+ transform: [{ scale }]
3063
+ }],
3064
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [hero.haloInner, { backgroundColor: palette.heroHaloTo }], children: [
3065
+ /* @__PURE__ */ jsxRuntime.jsx(
3066
+ reactNative.Animated.View,
3067
+ {
3068
+ style: [
3069
+ hero.ring,
3070
+ { borderColor: palette.heroRing, transform: [{ rotate: ringRotate }] }
3071
+ ]
3072
+ }
3073
+ ),
3074
+ /* @__PURE__ */ jsxRuntime.jsx(
3075
+ reactNative.Animated.View,
3076
+ {
3077
+ style: [
3078
+ hero.dot,
3079
+ { backgroundColor: palette.heroDot, transform: [{ scale: dotScale }] }
3080
+ ]
3081
+ }
3082
+ )
3083
+ ] })
3084
+ }
3085
+ );
31
3086
  }
32
-
33
- var Sentry__namespace = /*#__PURE__*/_interopNamespace(Sentry);
34
-
35
- // src/components/PaymanChat/index.native.tsx
36
- var PaymanChat = react.forwardRef(function PaymanChat2(_props, _ref) {
37
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.root, children: [
38
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.title, children: "PaymanChat v2" }),
39
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.body, children: "React Native support is coming in a follow-up release. Please use the web SDK for now." })
40
- ] });
41
- });
42
- var styles = reactNative.StyleSheet.create({
3087
+ var s7 = reactNative.StyleSheet.create({
43
3088
  root: {
3089
+ flex: 1,
3090
+ overflow: "hidden"
3091
+ },
3092
+ messageListWrapper: {
3093
+ flex: 1,
3094
+ minHeight: 0
3095
+ },
3096
+ emptyStateRoot: {
3097
+ flex: 1,
3098
+ justifyContent: "flex-end"
3099
+ },
3100
+ emptyStateCenter: {
44
3101
  flex: 1,
45
3102
  alignItems: "center",
46
3103
  justifyContent: "center",
47
- padding: 24
3104
+ paddingHorizontal: 32,
3105
+ paddingBottom: 24
48
3106
  },
49
- title: {
50
- fontSize: 16,
3107
+ emptyEyebrow: {
3108
+ marginTop: 28,
3109
+ marginBottom: 8,
3110
+ fontSize: 13,
51
3111
  fontWeight: "600",
52
- marginBottom: 8
3112
+ letterSpacing: 0.4,
3113
+ textTransform: "uppercase"
53
3114
  },
54
- body: {
55
- fontSize: 13,
56
- color: "#666",
3115
+ emptyStateText: {
3116
+ fontSize: 30,
3117
+ fontWeight: "600",
3118
+ textAlign: "center",
3119
+ letterSpacing: -0.7,
3120
+ lineHeight: 36,
3121
+ // Lean into a serif on iOS for a Claude-like editorial feel; system on Android
3122
+ ...reactNative.Platform.select({
3123
+ ios: { fontFamily: "Georgia" },
3124
+ default: {}
3125
+ }),
3126
+ marginTop: 24
3127
+ },
3128
+ emptyStateSubtext: {
3129
+ marginTop: 10,
3130
+ fontSize: 15,
3131
+ lineHeight: 22,
3132
+ textAlign: "center",
3133
+ letterSpacing: -0.15,
3134
+ maxWidth: 320
3135
+ },
3136
+ emptySuggestions: {
3137
+ width: "100%",
3138
+ marginTop: 16
3139
+ },
3140
+ disabledContainer: {
3141
+ flex: 1,
3142
+ alignItems: "center",
3143
+ justifyContent: "center",
3144
+ padding: 16
3145
+ },
3146
+ disabledText: {
3147
+ fontSize: 14,
57
3148
  textAlign: "center"
58
3149
  }
59
3150
  });
3151
+ var hero = reactNative.StyleSheet.create({
3152
+ halo: {
3153
+ width: 96,
3154
+ height: 96,
3155
+ borderRadius: 48,
3156
+ alignItems: "center",
3157
+ justifyContent: "center"
3158
+ },
3159
+ haloInner: {
3160
+ width: 76,
3161
+ height: 76,
3162
+ borderRadius: 38,
3163
+ alignItems: "center",
3164
+ justifyContent: "center"
3165
+ },
3166
+ ring: {
3167
+ position: "absolute",
3168
+ width: 60,
3169
+ height: 60,
3170
+ borderRadius: 30,
3171
+ borderWidth: 1.5,
3172
+ borderStyle: "dashed"
3173
+ },
3174
+ dot: {
3175
+ width: 18,
3176
+ height: 18,
3177
+ borderRadius: 9
3178
+ }
3179
+ });
60
3180
  function cn(...inputs) {
61
3181
  return tailwindMerge.twMerge(clsx.clsx(inputs));
62
3182
  }
@@ -94,24 +3214,24 @@ function useSessionHistory(config, options = {}, optimisticActivity) {
94
3214
  const minWidth = options.minWidth ?? DEFAULT_MIN_WIDTH;
95
3215
  const maxWidth = options.maxWidth ?? DEFAULT_MAX_WIDTH;
96
3216
  const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;
97
- const persistKey = react.useMemo(
3217
+ const persistKey = React.useMemo(
98
3218
  () => getPersistKey(config, options),
99
3219
  [config.workflow.id, options.persistKey]
100
3220
  );
101
- const [width, setWidthState] = react.useState(() => {
3221
+ const [width, setWidthState] = React.useState(() => {
102
3222
  const persisted = loadPersistedState(persistKey);
103
3223
  return persisted?.width ?? defaultWidth;
104
3224
  });
105
- const [collapsed, setCollapsedState] = react.useState(() => {
3225
+ const [collapsed, setCollapsedState] = React.useState(() => {
106
3226
  const persisted = loadPersistedState(persistKey);
107
3227
  return persisted?.collapsed ?? options.defaultCollapsed ?? false;
108
3228
  });
109
- react.useEffect(() => {
3229
+ React.useEffect(() => {
110
3230
  const persisted = loadPersistedState(persistKey);
111
3231
  setWidthState(persisted?.width ?? defaultWidth);
112
3232
  setCollapsedState(persisted?.collapsed ?? options.defaultCollapsed ?? false);
113
3233
  }, [persistKey]);
114
- const setWidth = react.useCallback(
3234
+ const setWidth = React.useCallback(
115
3235
  (px) => {
116
3236
  const clamped = Math.max(minWidth, Math.min(maxWidth, Math.round(px)));
117
3237
  setWidthState(clamped);
@@ -119,7 +3239,7 @@ function useSessionHistory(config, options = {}, optimisticActivity) {
119
3239
  },
120
3240
  [collapsed, maxWidth, minWidth, persistKey]
121
3241
  );
122
- const setCollapsed = react.useCallback(
3242
+ const setCollapsed = React.useCallback(
123
3243
  (value) => {
124
3244
  setCollapsedState((prev) => {
125
3245
  const next = typeof value === "function" ? value(prev) : value;
@@ -130,15 +3250,15 @@ function useSessionHistory(config, options = {}, optimisticActivity) {
130
3250
  [persistKey, width]
131
3251
  );
132
3252
  const isReady = !!(config.session?.owner?.id && (config.workflow.id || config.workflow.name));
133
- const [sessions, setSessions] = react.useState([]);
134
- const [isLoading, setIsLoading] = react.useState(false);
135
- const [error, setError] = react.useState(null);
136
- const [page, setPage] = react.useState(0);
137
- const [hasNext, setHasNext] = react.useState(false);
138
- const inFlightRef = react.useRef(null);
139
- const configRef = react.useRef(config);
3253
+ const [sessions, setSessions] = React.useState([]);
3254
+ const [isLoading, setIsLoading] = React.useState(false);
3255
+ const [error, setError] = React.useState(null);
3256
+ const [page, setPage] = React.useState(0);
3257
+ const [hasNext, setHasNext] = React.useState(false);
3258
+ const inFlightRef = React.useRef(null);
3259
+ const configRef = React.useRef(config);
140
3260
  configRef.current = config;
141
- const fetchPage = react.useCallback(
3261
+ const fetchPage = React.useCallback(
142
3262
  async (pageIndex, replace) => {
143
3263
  if (!isReady) return;
144
3264
  inFlightRef.current?.abort();
@@ -167,12 +3287,12 @@ function useSessionHistory(config, options = {}, optimisticActivity) {
167
3287
  },
168
3288
  [isReady, pageSize]
169
3289
  );
170
- const refresh = react.useCallback(() => fetchPage(0, true), [fetchPage]);
171
- const loadMore = react.useCallback(async () => {
3290
+ const refresh = React.useCallback(() => fetchPage(0, true), [fetchPage]);
3291
+ const loadMore = React.useCallback(async () => {
172
3292
  if (!hasNext || isLoading) return;
173
3293
  await fetchPage(page + 1, false);
174
3294
  }, [fetchPage, hasNext, isLoading, page]);
175
- react.useEffect(() => {
3295
+ React.useEffect(() => {
176
3296
  if (!optimisticActivity) return;
177
3297
  setSessions((prev) => {
178
3298
  const next = [...prev];
@@ -213,7 +3333,7 @@ function useSessionHistory(config, options = {}, optimisticActivity) {
213
3333
  config.workflow.version,
214
3334
  optimisticActivity
215
3335
  ]);
216
- react.useEffect(() => {
3336
+ React.useEffect(() => {
217
3337
  if (!isReady) return;
218
3338
  void fetchPage(0, true);
219
3339
  return () => {
@@ -243,11 +3363,11 @@ function useSessionHistory(config, options = {}, optimisticActivity) {
243
3363
  }
244
3364
  var MOBILE_BREAKPOINT = 640;
245
3365
  function useIsMobile() {
246
- const [isMobile, setIsMobile] = react.useState(() => {
3366
+ const [isMobile, setIsMobile] = React.useState(() => {
247
3367
  if (typeof window === "undefined") return false;
248
3368
  return window.innerWidth < MOBILE_BREAKPOINT;
249
3369
  });
250
- react.useEffect(() => {
3370
+ React.useEffect(() => {
251
3371
  if (typeof window === "undefined") return;
252
3372
  const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
253
3373
  const handler = (e) => setIsMobile(e.matches);
@@ -290,11 +3410,11 @@ function SessionHistorySidebar({
290
3410
  onMobileOpenChange
291
3411
  }) {
292
3412
  const isMobile = useIsMobile();
293
- const mobileThemeSourceRef = react.useRef(null);
294
- const [mobilePortalThemeStyle, setMobilePortalThemeStyle] = react.useState({});
3413
+ const mobileThemeSourceRef = React.useRef(null);
3414
+ const [mobilePortalThemeStyle, setMobilePortalThemeStyle] = React.useState({});
295
3415
  const history = useSessionHistory(config, options, optimisticActivity);
296
3416
  const showNewSessionButton = options.showNewSessionButton === true;
297
- react.useEffect(() => {
3417
+ React.useEffect(() => {
298
3418
  if (!isMobile) return;
299
3419
  setMobilePortalThemeStyle(readPortalThemeStyle(mobileThemeSourceRef.current));
300
3420
  }, [isMobile, mobileOpen]);
@@ -324,8 +3444,8 @@ function SessionHistorySidebar({
324
3444
  showNewSessionButton,
325
3445
  onNewSession,
326
3446
  newSessionDisabled,
327
- onSelectSession: (s3) => {
328
- onSelectSession(s3);
3447
+ onSelectSession: (s9) => {
3448
+ onSelectSession(s9);
329
3449
  onMobileOpenChange(false);
330
3450
  }
331
3451
  }
@@ -358,10 +3478,10 @@ function DesktopSidebar({
358
3478
  }) {
359
3479
  const { width, setWidth, collapsed, setCollapsed, minWidth, maxWidth } = history;
360
3480
  const reduceMotion = framerMotion.useReducedMotion();
361
- const dragStateRef = react.useRef(null);
362
- const [isDragging, setIsDragging] = react.useState(false);
363
- const [handleHover, setHandleHover] = react.useState(false);
364
- const onResizeStart = react.useCallback(
3481
+ const dragStateRef = React.useRef(null);
3482
+ const [isDragging, setIsDragging] = React.useState(false);
3483
+ const [handleHover, setHandleHover] = React.useState(false);
3484
+ const onResizeStart = React.useCallback(
365
3485
  (e) => {
366
3486
  e.preventDefault();
367
3487
  dragStateRef.current = { startX: e.clientX, startWidth: width };
@@ -369,7 +3489,7 @@ function DesktopSidebar({
369
3489
  },
370
3490
  [width]
371
3491
  );
372
- react.useEffect(() => {
3492
+ React.useEffect(() => {
373
3493
  if (!isDragging) return;
374
3494
  const onMove = (e) => {
375
3495
  const st = dragStateRef.current;
@@ -514,8 +3634,8 @@ function CollapsedButton({
514
3634
  onSelectSession
515
3635
  }) {
516
3636
  const reduceMotion = framerMotion.useReducedMotion();
517
- const [hoverOpen, setHoverOpen] = react.useState(false);
518
- const leaveTimerRef = react.useRef(null);
3637
+ const [hoverOpen, setHoverOpen] = React.useState(false);
3638
+ const leaveTimerRef = React.useRef(null);
519
3639
  const openPopover = () => {
520
3640
  if (leaveTimerRef.current) clearTimeout(leaveTimerRef.current);
521
3641
  setHoverOpen(true);
@@ -527,7 +3647,7 @@ function CollapsedButton({
527
3647
  POPOVER_LEAVE_DELAY_MS
528
3648
  );
529
3649
  };
530
- react.useEffect(
3650
+ React.useEffect(
531
3651
  () => () => {
532
3652
  if (leaveTimerRef.current) clearTimeout(leaveTimerRef.current);
533
3653
  },
@@ -593,8 +3713,8 @@ function CollapsedButton({
593
3713
  activeSessionId,
594
3714
  loadingSessionId,
595
3715
  recentlyCompletedSessionIds,
596
- onSelectSession: (s3) => {
597
- onSelectSession(s3);
3716
+ onSelectSession: (s9) => {
3717
+ onSelectSession(s9);
598
3718
  setHoverOpen(false);
599
3719
  }
600
3720
  }
@@ -744,10 +3864,10 @@ function SessionList({
744
3864
  recentlyCompletedSessionIds,
745
3865
  onSelectSession
746
3866
  }) {
747
- const listRef = react.useRef(null);
3867
+ const listRef = React.useRef(null);
748
3868
  const { sessions, hasNext, isLoading, error, loadMore, isReady, refresh } = history;
749
- const formattedNow = react.useMemo(() => /* @__PURE__ */ new Date(), []);
750
- const sessionGroups = react.useMemo(
3869
+ const formattedNow = React.useMemo(() => /* @__PURE__ */ new Date(), []);
3870
+ const sessionGroups = React.useMemo(
751
3871
  () => groupSessionsByDate(sessions, formattedNow),
752
3872
  [sessions, formattedNow]
753
3873
  );
@@ -771,16 +3891,16 @@ function SessionList({
771
3891
  "aria-label": group.label,
772
3892
  children: [
773
3893
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-sidebar-group-label", children: group.label }),
774
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-sidebar-group-items", children: group.sessions.map((s3) => /* @__PURE__ */ jsxRuntime.jsx(
3894
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-sidebar-group-items", children: group.sessions.map((s9) => /* @__PURE__ */ jsxRuntime.jsx(
775
3895
  SessionRow,
776
3896
  {
777
- session: s3,
778
- isActive: s3.sessionId === activeSessionId,
779
- isLoading: s3.sessionId === loadingSessionId,
780
- isRecentlyCompleted: recentlyCompletedSessionIds?.has(s3.sessionId) ?? false,
3897
+ session: s9,
3898
+ isActive: s9.sessionId === activeSessionId,
3899
+ isLoading: s9.sessionId === loadingSessionId,
3900
+ isRecentlyCompleted: recentlyCompletedSessionIds?.has(s9.sessionId) ?? false,
781
3901
  onSelect: onSelectSession
782
3902
  },
783
- s3.sessionId
3903
+ s9.sessionId
784
3904
  )) })
785
3905
  ]
786
3906
  },
@@ -975,7 +4095,7 @@ function ChatHeader({
975
4095
  showResetSession = false,
976
4096
  children
977
4097
  }) {
978
- const [copiedSessionId, setCopiedSessionId] = react.useState(false);
4098
+ const [copiedSessionId, setCopiedSessionId] = React.useState(false);
979
4099
  const handleCopySessionId = () => {
980
4100
  if (sessionId && onCopySessionId) {
981
4101
  reactNative.Clipboard.setString(sessionId);
@@ -984,21 +4104,21 @@ function ChatHeader({
984
4104
  onCopySessionId(sessionId);
985
4105
  }
986
4106
  };
987
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.container, children: [
988
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.left, children: [
989
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.title, children: "Chat" }),
990
- sessionId && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { onPress: handleCopySessionId, style: styles2.sessionChip, children: [
991
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.sessionText, children: sessionId.length > 20 ? `${sessionId.substring(0, 8)}\u2026${sessionId.slice(-8)}` : sessionId }),
992
- copiedSessionId ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.copyHint, children: "copied" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.copyHint, children: "copy" })
4107
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.container, children: [
4108
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.left, children: [
4109
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: "Chat" }),
4110
+ sessionId && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Pressable, { onPress: handleCopySessionId, style: styles3.sessionChip, children: [
4111
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.sessionText, children: sessionId.length > 20 ? `${sessionId.substring(0, 8)}\u2026${sessionId.slice(-8)}` : sessionId }),
4112
+ copiedSessionId ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.copyHint, children: "copied" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.copyHint, children: "copy" })
993
4113
  ] })
994
4114
  ] }),
995
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.right, children: [
996
- showResetSession && onNewSession && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onNewSession, style: styles2.btn, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.btnText, children: "Reset" }) }),
4115
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.right, children: [
4116
+ showResetSession && onNewSession && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: onNewSession, style: styles3.btn, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.btnText, children: "Reset" }) }),
997
4117
  children
998
4118
  ] })
999
4119
  ] });
1000
4120
  }
1001
- var styles2 = reactNative.StyleSheet.create({
4121
+ var styles3 = reactNative.StyleSheet.create({
1002
4122
  container: {
1003
4123
  flexDirection: "row",
1004
4124
  alignItems: "center",
@@ -1032,203 +4152,8 @@ var styles2 = reactNative.StyleSheet.create({
1032
4152
 
1033
4153
  // src/assets/payman-mono-crop-blue.png
1034
4154
  var payman_mono_crop_blue_default = "data:image/png;base64,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";
1035
- var DEFAULT_MAX_LENGTH = 6;
1036
- var MAX_SUPPORTED_LENGTH = 12;
1037
- var OTP_ERROR_BORDER = "#ef4444";
1038
- var COMPLETE_PULSE_MS = 350;
1039
- var SHAKE_MS = 400;
1040
- function OtpInput({
1041
- value,
1042
- onChange,
1043
- maxLength,
1044
- disabled = false,
1045
- error = false
1046
- }) {
1047
- const inputRefs = react.useRef([]);
1048
- const shakeAnim = react.useRef(new reactNative.Animated.Value(0)).current;
1049
- const scaleAnim = react.useRef(new reactNative.Animated.Value(1)).current;
1050
- const prevLenRef = react.useRef(0);
1051
- const [internalError, setInternalError] = react.useState(false);
1052
- const safeMaxLength = Number.isInteger(maxLength) && maxLength > 0 ? Math.min(maxLength, MAX_SUPPORTED_LENGTH) : DEFAULT_MAX_LENGTH;
1053
- const digits = value.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
1054
- const isFull = value.length === safeMaxLength && /^\d+$/.test(value);
1055
- react.useEffect(() => {
1056
- if (!disabled) {
1057
- inputRefs.current[0]?.focus();
1058
- }
1059
- }, [disabled]);
1060
- react.useEffect(() => {
1061
- if (!error) {
1062
- setInternalError(false);
1063
- return;
1064
- }
1065
- setInternalError(true);
1066
- reactNative.Animated.sequence([
1067
- reactNative.Animated.timing(shakeAnim, { toValue: 1, duration: SHAKE_MS, useNativeDriver: true }),
1068
- reactNative.Animated.timing(shakeAnim, { toValue: 0, duration: 0, useNativeDriver: true })
1069
- ]).start();
1070
- }, [error, shakeAnim]);
1071
- react.useEffect(() => {
1072
- if (isFull && prevLenRef.current < safeMaxLength) {
1073
- reactNative.Animated.sequence([
1074
- reactNative.Animated.timing(scaleAnim, { toValue: 1.04, duration: COMPLETE_PULSE_MS * 0.4, useNativeDriver: true }),
1075
- reactNative.Animated.timing(scaleAnim, { toValue: 1, duration: COMPLETE_PULSE_MS * 0.6, useNativeDriver: true })
1076
- ]).start();
1077
- }
1078
- prevLenRef.current = value.length;
1079
- }, [isFull, value.length, safeMaxLength, scaleAnim]);
1080
- const shakeTranslate = shakeAnim.interpolate({
1081
- inputRange: [0, 0.15, 0.3, 0.45, 0.6, 0.75, 0.9, 1],
1082
- outputRange: [0, -6, 5, -4, 3, -2, 1, 0]
1083
- });
1084
- const focusInput = (index) => {
1085
- if (index >= 0 && index < safeMaxLength) {
1086
- inputRefs.current[index]?.focus();
1087
- }
1088
- };
1089
- const updateValue = (newDigits) => {
1090
- onChange(newDigits.join("").slice(0, safeMaxLength));
1091
- };
1092
- const handleChange = (index, text) => {
1093
- const cleaned = text.replace(/\D/g, "");
1094
- if (cleaned.length > 1) {
1095
- const pasted = cleaned.slice(0, safeMaxLength);
1096
- const newDigits2 = pasted.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
1097
- updateValue(newDigits2);
1098
- focusInput(Math.min(pasted.length, safeMaxLength - 1));
1099
- return;
1100
- }
1101
- const char = cleaned.slice(-1);
1102
- const newDigits = [...digits];
1103
- newDigits[index] = char;
1104
- updateValue(newDigits);
1105
- if (char && index < safeMaxLength - 1) {
1106
- focusInput(index + 1);
1107
- }
1108
- };
1109
- const handleKeyPress = (index, key) => {
1110
- if (key === "Backspace") {
1111
- if (digits[index]) {
1112
- const newDigits = [...digits];
1113
- newDigits[index] = "";
1114
- updateValue(newDigits);
1115
- } else if (index > 0) {
1116
- const newDigits = [...digits];
1117
- newDigits[index - 1] = "";
1118
- updateValue(newDigits);
1119
- focusInput(index - 1);
1120
- }
1121
- }
1122
- };
1123
- return /* @__PURE__ */ jsxRuntime.jsx(
1124
- reactNative.Animated.View,
1125
- {
1126
- style: [
1127
- s.container,
1128
- { transform: [{ translateX: shakeTranslate }, { scale: scaleAnim }] }
1129
- ],
1130
- children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
1131
- reactNative.TextInput,
1132
- {
1133
- ref: (el) => {
1134
- inputRefs.current[i] = el;
1135
- },
1136
- value: digit,
1137
- editable: !disabled,
1138
- keyboardType: "number-pad",
1139
- maxLength: 1,
1140
- onChangeText: (text) => handleChange(i, text),
1141
- onKeyPress: ({ nativeEvent }) => handleKeyPress(i, nativeEvent.key),
1142
- onFocus: () => inputRefs.current[i]?.setNativeProps({ selection: { start: 0, end: 1 } }),
1143
- style: [
1144
- s.input,
1145
- disabled && s.inputDisabled,
1146
- internalError && s.inputError
1147
- ],
1148
- accessibilityLabel: `Digit ${i + 1}`
1149
- },
1150
- i
1151
- ))
1152
- }
1153
- );
1154
- }
1155
- var PAYMAN_OTP = {
1156
- bg: "#FFFFFF",
1157
- border: "rgba(0,0,0,0.1)",
1158
- fg: "#18181b",
1159
- disabledBg: "rgba(0,0,0,0.03)"
1160
- };
1161
- var s = reactNative.StyleSheet.create({
1162
- container: { flexDirection: "row", gap: 8, justifyContent: "center" },
1163
- input: {
1164
- width: 44,
1165
- height: 50,
1166
- textAlign: "center",
1167
- fontSize: 20,
1168
- fontWeight: "600",
1169
- borderWidth: 1,
1170
- borderColor: PAYMAN_OTP.border,
1171
- borderRadius: 10,
1172
- color: PAYMAN_OTP.fg,
1173
- backgroundColor: PAYMAN_OTP.bg
1174
- },
1175
- inputDisabled: { backgroundColor: PAYMAN_OTP.disabledBg, opacity: 0.5 },
1176
- inputError: {
1177
- borderColor: OTP_ERROR_BORDER,
1178
- borderWidth: 1.5
1179
- }
1180
- });
1181
-
1182
- // src/components/UserActionModal/constants.ts
1183
- var BUTTON_LABELS = {
1184
- /** Link-style actions (new layout) */
1185
- RESEND_CODE: "Resend OTP",
1186
- CANCEL_TRANSFER: "Cancel Payment",
1187
- /** Short cancel label for payee approval flows */
1188
- CANCEL: "Cancel"
1189
- };
1190
- var RESEND_OTP_COOLDOWN_SECONDS = 30;
1191
- var DEFAULT_OTP_MAX_LENGTH = 6;
1192
- var MIN_OTP_MAX_LENGTH = 1;
1193
- var MAX_OTP_MAX_LENGTH = 12;
1194
- var ACTION_PENDING_TIMEOUT_MS = 15e3;
1195
- var MODAL_CONTENT = {
1196
- LOADING_APPROVE: "Verifying...",
1197
- LOADING_REJECT: "Rejecting...",
1198
- LOADING_RESEND: "Resending...",
1199
- RESEND_AVAILABLE_IN: "Resend OTP in",
1200
- SECURED_BY_PREFIX: "Secured by",
1201
- SECURED_BY_BRAND: "Payman"
1202
- };
1203
-
1204
- // src/components/UserActionModal/utils.ts
1205
- function getOtpSchemaFromRequest(schema) {
1206
- const properties = schema?.properties;
1207
- const otp = properties?.otp;
1208
- const maxLengthRaw = otp?.maxLength;
1209
- const parsedMaxLength = Number.isInteger(maxLengthRaw) ? Number(maxLengthRaw) : DEFAULT_OTP_MAX_LENGTH;
1210
- const clampedMaxLength = Math.min(
1211
- MAX_OTP_MAX_LENGTH,
1212
- Math.max(MIN_OTP_MAX_LENGTH, parsedMaxLength)
1213
- );
1214
- return {
1215
- maxLength: clampedMaxLength
1216
- };
1217
- }
1218
- function formatAmountForDisplay(amount) {
1219
- const normalized = amount.replace(/,/g, "").trim();
1220
- const n = Number(normalized);
1221
- if (!Number.isFinite(n)) {
1222
- return amount.startsWith("$") ? amount : `$${amount}`;
1223
- }
1224
- return new Intl.NumberFormat("en-US", {
1225
- style: "currency",
1226
- currency: "USD"
1227
- }).format(n);
1228
- }
1229
4155
  var PAYMAN_BRAND_GREEN = "#0A3B44";
1230
4156
  var PAYMAN = {
1231
- foreground: "#18181b",
1232
4157
  mutedForeground: "#71717a",
1233
4158
  border: "#e4e4e7",
1234
4159
  card: "#ffffff",
@@ -1237,7 +4162,7 @@ var PAYMAN = {
1237
4162
  var { width: SCREEN_WIDTH } = reactNative.Dimensions.get("window");
1238
4163
  var DIALOG_MAX_WIDTH = Math.min(440, SCREEN_WIDTH * 0.94);
1239
4164
  var DIALOG_PADDING = 28;
1240
- var OTP_ERROR_FLASH_MS = 600;
4165
+ var OTP_ERROR_FLASH_MS2 = 600;
1241
4166
  function UserActionModal({
1242
4167
  isOpen,
1243
4168
  userActionRequest,
@@ -1246,17 +4171,17 @@ function UserActionModal({
1246
4171
  onResend,
1247
4172
  clearOtpTrigger
1248
4173
  }) {
1249
- const [otp, setOtp] = react.useState("");
1250
- const [actionType, setActionType] = react.useState(null);
1251
- const [isSubmitting, setIsSubmitting] = react.useState(false);
1252
- const [resendCooldownRemaining, setResendCooldownRemaining] = react.useState(0);
1253
- const [keyboardVisible, setKeyboardVisible] = react.useState(false);
1254
- const [otpError, setOtpError] = react.useState(false);
1255
- const lastAutoSubmittedRef = react.useRef("");
1256
- const submitInFlightRef = react.useRef(false);
1257
- const submitGenerationRef = react.useRef(0);
4174
+ const [otp, setOtp] = React.useState("");
4175
+ const [actionType, setActionType] = React.useState(null);
4176
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
4177
+ const [resendCooldownRemaining, setResendCooldownRemaining] = React.useState(0);
4178
+ const [keyboardVisible, setKeyboardVisible] = React.useState(false);
4179
+ const [otpError, setOtpError] = React.useState(false);
4180
+ const lastAutoSubmittedRef = React.useRef("");
4181
+ const submitInFlightRef = React.useRef(false);
4182
+ const submitGenerationRef = React.useRef(0);
1258
4183
  const schema = getOtpSchemaFromRequest(userActionRequest?.requestedSchema);
1259
- react.useEffect(() => {
4184
+ React.useEffect(() => {
1260
4185
  const show = reactNative.Keyboard.addListener(
1261
4186
  reactNative.Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow",
1262
4187
  () => setKeyboardVisible(true)
@@ -1270,11 +4195,11 @@ function UserActionModal({
1270
4195
  hide.remove();
1271
4196
  };
1272
4197
  }, []);
1273
- const resetActionState = react.useCallback(() => {
4198
+ const resetActionState = React.useCallback(() => {
1274
4199
  setIsSubmitting(false);
1275
4200
  setActionType(null);
1276
4201
  }, []);
1277
- react.useEffect(() => {
4202
+ React.useEffect(() => {
1278
4203
  if (isOpen) {
1279
4204
  setResendCooldownRemaining(RESEND_OTP_COOLDOWN_SECONDS);
1280
4205
  } else {
@@ -1287,7 +4212,7 @@ function UserActionModal({
1287
4212
  submitGenerationRef.current += 1;
1288
4213
  }
1289
4214
  }, [isOpen, resetActionState]);
1290
- react.useEffect(() => {
4215
+ React.useEffect(() => {
1291
4216
  if (resendCooldownRemaining <= 0) return;
1292
4217
  const timer = setTimeout(
1293
4218
  () => setResendCooldownRemaining((prev) => prev - 1),
@@ -1295,18 +4220,18 @@ function UserActionModal({
1295
4220
  );
1296
4221
  return () => clearTimeout(timer);
1297
4222
  }, [resendCooldownRemaining]);
1298
- react.useEffect(() => {
4223
+ React.useEffect(() => {
1299
4224
  if (clearOtpTrigger > 0) {
1300
4225
  setOtpError(true);
1301
4226
  const t = setTimeout(() => {
1302
4227
  setOtpError(false);
1303
4228
  setOtp("");
1304
4229
  resetActionState();
1305
- }, OTP_ERROR_FLASH_MS);
4230
+ }, OTP_ERROR_FLASH_MS2);
1306
4231
  return () => clearTimeout(t);
1307
4232
  }
1308
4233
  }, [clearOtpTrigger, resetActionState]);
1309
- react.useEffect(() => {
4234
+ React.useEffect(() => {
1310
4235
  if (!isOpen || !isSubmitting) return;
1311
4236
  if (actionType !== "approve" && actionType !== "reject") return;
1312
4237
  const timeout = setTimeout(
@@ -1315,7 +4240,7 @@ function UserActionModal({
1315
4240
  );
1316
4241
  return () => clearTimeout(timeout);
1317
4242
  }, [isOpen, isSubmitting, actionType, resetActionState]);
1318
- react.useEffect(() => {
4243
+ React.useEffect(() => {
1319
4244
  if (!isOpen || !userActionRequest) return;
1320
4245
  if (otp.length !== schema.maxLength || !/^\d+$/.test(otp)) {
1321
4246
  return;
@@ -1348,7 +4273,7 @@ function UserActionModal({
1348
4273
  onApprove,
1349
4274
  resetActionState
1350
4275
  ]);
1351
- const handleReject = react.useCallback(async () => {
4276
+ const handleReject = React.useCallback(async () => {
1352
4277
  setIsSubmitting(true);
1353
4278
  setActionType("reject");
1354
4279
  try {
@@ -1357,7 +4282,7 @@ function UserActionModal({
1357
4282
  resetActionState();
1358
4283
  }
1359
4284
  }, [onReject, resetActionState]);
1360
- const handleResend = react.useCallback(async () => {
4285
+ const handleResend = React.useCallback(async () => {
1361
4286
  if (resendCooldownRemaining > 0) return;
1362
4287
  setIsSubmitting(true);
1363
4288
  setActionType("resend");
@@ -1388,32 +4313,32 @@ function UserActionModal({
1388
4313
  children: /* @__PURE__ */ jsxRuntime.jsx(
1389
4314
  reactNative.KeyboardAvoidingView,
1390
4315
  {
1391
- style: [s2.keyboardAvoid, { justifyContent: modalPosition }],
4316
+ style: [s8.keyboardAvoid, { justifyContent: modalPosition }],
1392
4317
  behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
1393
4318
  keyboardVerticalOffset: reactNative.Platform.OS === "ios" ? 0 : 20,
1394
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [s2.modalOverlay, { justifyContent: modalPosition }], children: /* @__PURE__ */ jsxRuntime.jsx(
4319
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [s8.modalOverlay, { justifyContent: modalPosition }], children: /* @__PURE__ */ jsxRuntime.jsx(
1395
4320
  reactNative.ScrollView,
1396
4321
  {
1397
4322
  contentContainerStyle: [
1398
- s2.scrollContent,
4323
+ s8.scrollContent,
1399
4324
  { justifyContent: modalPosition }
1400
4325
  ],
1401
4326
  showsVerticalScrollIndicator: false,
1402
4327
  keyboardShouldPersistTaps: "handled",
1403
- children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [s2.dialog, { width: DIALOG_MAX_WIDTH }], children: [
4328
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [s8.dialog, { width: DIALOG_MAX_WIDTH }], children: [
1404
4329
  /* @__PURE__ */ jsxRuntime.jsx(
1405
4330
  reactNative.Pressable,
1406
4331
  {
1407
4332
  onPress: handleReject,
1408
4333
  disabled: isSubmitting,
1409
- style: s2.closeBtn,
4334
+ style: s8.closeBtn,
1410
4335
  accessibilityLabel: "Close",
1411
4336
  hitSlop: 8,
1412
- children: ({ pressed }) => /* @__PURE__ */ jsxRuntime.jsx(
4337
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1413
4338
  lucideReactNative.X,
1414
4339
  {
1415
4340
  size: 16,
1416
- color: pressed && !isSubmitting ? PAYMAN.foreground : PAYMAN.mutedForeground,
4341
+ color: PAYMAN.mutedForeground,
1417
4342
  strokeWidth: 2.5
1418
4343
  }
1419
4344
  )
@@ -1422,19 +4347,19 @@ function UserActionModal({
1422
4347
  /* @__PURE__ */ jsxRuntime.jsx(
1423
4348
  reactNative.Text,
1424
4349
  {
1425
- style: s2.description,
4350
+ style: s8.description,
1426
4351
  accessibilityLabel: "payman-modal-desc",
1427
4352
  children: userActionRequest.message
1428
4353
  }
1429
4354
  ),
1430
- isPayment ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.transferLabel, children: "Pay" }) : null,
1431
- isPayment && userActionRequest.metadata?.amount ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.heroAmount, children: formatAmountForDisplay(userActionRequest.metadata.amount) }) : null,
1432
- isPayee ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.transferLabel, children: "Create Payee" }) : null,
1433
- isPayee && userActionRequest.metadata?.payeeName ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.heroPayeeWrap, children: [
1434
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.heroPayeeName, children: userActionRequest.metadata.payeeName }),
1435
- userActionRequest.metadata.payeeType ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.heroPayeeType, children: userActionRequest.metadata.payeeType }) : null
4355
+ isPayment ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s8.transferLabel, children: "Pay" }) : null,
4356
+ isPayment && userActionRequest.metadata?.amount ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s8.heroAmount, children: formatAmountForDisplay(userActionRequest.metadata.amount) }) : null,
4357
+ isPayee ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s8.transferLabel, children: "Create Payee" }) : null,
4358
+ isPayee && userActionRequest.metadata?.payeeName ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s8.heroPayeeWrap, children: [
4359
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s8.heroPayeeName, children: userActionRequest.metadata.payeeName }),
4360
+ userActionRequest.metadata.payeeType ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s8.heroPayeeType, children: userActionRequest.metadata.payeeType }) : null
1436
4361
  ] }) : null,
1437
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.otpWrap, accessibilityLabel: "payman-otp-wrap", children: [
4362
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s8.otpWrap, accessibilityLabel: "payman-otp-wrap", children: [
1438
4363
  /* @__PURE__ */ jsxRuntime.jsx(
1439
4364
  OtpInput,
1440
4365
  {
@@ -1445,7 +4370,7 @@ function UserActionModal({
1445
4370
  error: otpError
1446
4371
  }
1447
4372
  ),
1448
- isVerifying ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.verifyingRow, children: [
4373
+ isVerifying ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s8.verifyingRow, children: [
1449
4374
  /* @__PURE__ */ jsxRuntime.jsx(
1450
4375
  reactNative.ActivityIndicator,
1451
4376
  {
@@ -1453,10 +4378,10 @@ function UserActionModal({
1453
4378
  color: PAYMAN_BRAND_GREEN
1454
4379
  }
1455
4380
  ),
1456
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.verifyingText, children: MODAL_CONTENT.LOADING_APPROVE })
4381
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s8.verifyingText, children: MODAL_CONTENT.LOADING_APPROVE })
1457
4382
  ] }) : null
1458
4383
  ] }),
1459
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.linksCol, children: [
4384
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s8.linksCol, children: [
1460
4385
  /* @__PURE__ */ jsxRuntime.jsx(
1461
4386
  reactNative.Pressable,
1462
4387
  {
@@ -1464,15 +4389,14 @@ function UserActionModal({
1464
4389
  disabled: isSubmitting || resendCooldownRemaining > 0,
1465
4390
  accessibilityLabel: "payman-modal-btn-resend",
1466
4391
  testID: "payman-modal-btn-resend",
1467
- children: ({ pressed }) => /* @__PURE__ */ jsxRuntime.jsx(
4392
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1468
4393
  reactNative.Text,
1469
4394
  {
1470
4395
  style: [
1471
- s2.linkText,
1472
- pressed && { opacity: 0.6 },
1473
- (isSubmitting || resendCooldownRemaining > 0) && s2.linkDisabled
4396
+ s8.linkText,
4397
+ (isSubmitting || resendCooldownRemaining > 0) && s8.linkDisabled
1474
4398
  ],
1475
- children: actionType === "resend" ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: MODAL_CONTENT.LOADING_RESEND }) : resendCooldownRemaining > 0 ? `${MODAL_CONTENT.RESEND_AVAILABLE_IN} ${resendCooldownRemaining}s` : BUTTON_LABELS.RESEND_CODE
4399
+ children: actionType === "resend" ? MODAL_CONTENT.LOADING_RESEND : resendCooldownRemaining > 0 ? `${MODAL_CONTENT.RESEND_AVAILABLE_IN} ${resendCooldownRemaining}s` : BUTTON_LABELS.RESEND_CODE
1476
4400
  }
1477
4401
  )
1478
4402
  }
@@ -1484,7 +4408,7 @@ function UserActionModal({
1484
4408
  disabled: isSubmitting,
1485
4409
  accessibilityLabel: "payman-modal-btn-reject",
1486
4410
  testID: "payman-modal-btn-reject",
1487
- children: ({ pressed }) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 6 }, children: [
4411
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 6 }, children: [
1488
4412
  isCancelling ? /* @__PURE__ */ jsxRuntime.jsx(
1489
4413
  reactNative.ActivityIndicator,
1490
4414
  {
@@ -1496,11 +4420,8 @@ function UserActionModal({
1496
4420
  reactNative.Text,
1497
4421
  {
1498
4422
  style: [
1499
- s2.linkText,
1500
- pressed && !isSubmitting && {
1501
- color: PAYMAN.foreground
1502
- },
1503
- isSubmitting && !isCancelling && s2.linkDisabled
4423
+ s8.linkText,
4424
+ isSubmitting && !isCancelling && s8.linkDisabled
1504
4425
  ],
1505
4426
  children: isCancelling ? MODAL_CONTENT.LOADING_REJECT : isPayee ? BUTTON_LABELS.CANCEL : BUTTON_LABELS.CANCEL_TRANSFER
1506
4427
  }
@@ -1509,19 +4430,19 @@ function UserActionModal({
1509
4430
  }
1510
4431
  )
1511
4432
  ] }),
1512
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s2.footer, children: [
1513
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.footerPrefix, children: MODAL_CONTENT.SECURED_BY_PREFIX }),
4433
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: s8.footer, children: [
4434
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s8.footerPrefix, children: MODAL_CONTENT.SECURED_BY_PREFIX }),
1514
4435
  /* @__PURE__ */ jsxRuntime.jsx(
1515
4436
  reactNative.Image,
1516
4437
  {
1517
4438
  source: { uri: payman_mono_crop_blue_default },
1518
- style: s2.footerLogo,
4439
+ style: s8.footerLogo,
1519
4440
  resizeMode: "contain",
1520
4441
  accessibilityElementsHidden: true,
1521
4442
  importantForAccessibility: "no-hide-descendants"
1522
4443
  }
1523
4444
  ),
1524
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s2.footerBrand, children: MODAL_CONTENT.SECURED_BY_BRAND })
4445
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: s8.footerBrand, children: MODAL_CONTENT.SECURED_BY_BRAND })
1525
4446
  ] })
1526
4447
  ] })
1527
4448
  }
@@ -1531,7 +4452,7 @@ function UserActionModal({
1531
4452
  }
1532
4453
  );
1533
4454
  }
1534
- var s2 = reactNative.StyleSheet.create({
4455
+ var s8 = reactNative.StyleSheet.create({
1535
4456
  keyboardAvoid: {
1536
4457
  flex: 1,
1537
4458
  width: "100%"
@@ -1742,7 +4663,7 @@ function FloatingChat({
1742
4663
  defaultOpen = false,
1743
4664
  showNotificationBadge = false
1744
4665
  }) {
1745
- const [isOpen, setIsOpen] = react.useState(defaultOpen);
4666
+ const [isOpen, setIsOpen] = React.useState(defaultOpen);
1746
4667
  const toggleChat = () => setIsOpen(!isOpen);
1747
4668
  const buttonSizes = { sm: "w-12 h-12", md: "w-14 h-14", lg: "w-16 h-16" };
1748
4669
  const iconSizes = { sm: "w-5 h-5", md: "w-6 h-6", lg: "w-7 h-7" };
@@ -1843,9 +4764,9 @@ function FloatingChat({
1843
4764
  )
1844
4765
  ] });
1845
4766
  }
1846
- var PaymanChatContext = react.createContext(void 0);
4767
+ var PaymanChatContext = React.createContext(void 0);
1847
4768
  function usePaymanChat() {
1848
- const ctx = react.useContext(PaymanChatContext);
4769
+ const ctx = React.useContext(PaymanChatContext);
1849
4770
  if (!ctx) {
1850
4771
  throw new Error("usePaymanChat must be used within a PaymanChat component");
1851
4772
  }