@paymanai/payman-ask-sdk 1.0.4 → 1.1.0

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.
@@ -178,7 +178,7 @@ function AgentMessage({
178
178
  agentName = "Assistant",
179
179
  showAvatar = false,
180
180
  layout = "full-width",
181
- showTimestamp = false,
181
+ showTimestamp: _showTimestamp = false,
182
182
  showExecutionSteps = false,
183
183
  showStreamingDot = false,
184
184
  streamingStepsText,
@@ -186,7 +186,7 @@ function AgentMessage({
186
186
  onExecutionTraceClick
187
187
  }) {
188
188
  const isStreaming = message.isStreaming ?? false;
189
- const hasSteps = message.steps && message.steps.length > 0;
189
+ const hasSteps = !!message.steps && message.steps.length > 0;
190
190
  const hasTraceData = !!(message.tracingData || message.executionId) && !isStreaming;
191
191
  const isError = message.isError ?? (message.streamProgress === "error" || !!message.errorDetails);
192
192
  const isCancelled = message.isCancelled ?? false;
@@ -236,6 +236,13 @@ function AgentMessage({
236
236
  layout === "centered" && styles2.messageContainerCentered
237
237
  ],
238
238
  children: [
239
+ message.userActionResult && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.badgeContainer, children: message.userActionResult === "approved" ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles2.badge, styles2.badgeApproved], children: [
240
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.CheckCircle2, { size: 12, color: "#15803d" }),
241
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.badgeApprovedText, children: "OTP Verified" })
242
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles2.badge, styles2.badgeRejected], children: [
243
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.XCircle, { size: 12, color: "#b91c1c" }),
244
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.badgeRejectedText, children: "Rejected" })
245
+ ] }) }),
239
246
  /* @__PURE__ */ jsxRuntime.jsxs(
240
247
  reactNative.View,
241
248
  {
@@ -278,7 +285,7 @@ function AgentMessage({
278
285
  onPress: () => setIsStepsExpanded(!isStepsExpanded),
279
286
  style: styles2.stepsButton,
280
287
  children: [
281
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.stepsButtonText, children: getCompletedStepsText(isStepsExpanded) }),
288
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.stepsButtonText, children: getCompletedStepsText(!!isStepsExpanded) }),
282
289
  isStepsExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronUp, { size: 12, color: "#666" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronDown, { size: 12, color: "#666" })
283
290
  ]
284
291
  }
@@ -302,7 +309,13 @@ function AgentMessage({
302
309
  step.status === "pending" && isCancelled && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.XCircle, { size: 12, color: "#666" }),
303
310
  step.status === "pending" && !isCancelled && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
304
311
  step.status === "in_progress" && !isCurrentlyExecuting && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
305
- step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Check, { size: 12, color: "#007AFF" }),
312
+ step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(
313
+ lucideReactNative.Check,
314
+ {
315
+ size: 12,
316
+ color: step.eventType === "USER_ACTION_SUCCESS" ? "#16a34a" : "#007AFF"
317
+ }
318
+ ),
306
319
  step.status === "error" && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 12, color: "#FF3B30" }),
307
320
  /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.stepContent, children: [
308
321
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -310,7 +323,8 @@ function AgentMessage({
310
323
  {
311
324
  style: [
312
325
  styles2.stepText,
313
- step.status === "error" && styles2.stepTextError
326
+ step.status === "error" && styles2.stepTextError,
327
+ step.eventType === "USER_ACTION_SUCCESS" && styles2.stepTextSuccess
314
328
  ],
315
329
  children: step.message
316
330
  }
@@ -346,7 +360,7 @@ function AgentMessage({
346
360
  onPress: () => setIsStepsExpanded(!isStepsExpanded),
347
361
  style: styles2.stepsButton,
348
362
  children: [
349
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.stepsButtonText, children: getStreamingStepsText(isStepsExpanded) }),
363
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.stepsButtonText, children: getStreamingStepsText(!!isStepsExpanded) }),
350
364
  isStepsExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronUp, { size: 12, color: "#666" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.ChevronDown, { size: 12, color: "#666" })
351
365
  ]
352
366
  }
@@ -370,7 +384,13 @@ function AgentMessage({
370
384
  step.status === "pending" && isCancelled && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.XCircle, { size: 12, color: "#666" }),
371
385
  step.status === "pending" && !isCancelled && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
372
386
  step.status === "in_progress" && !isCurrentlyExecuting && /* @__PURE__ */ jsxRuntime.jsx(AnimatedLoader, { size: 12, color: "#007AFF" }),
373
- step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Check, { size: 12, color: "#007AFF" }),
387
+ step.status === "completed" && /* @__PURE__ */ jsxRuntime.jsx(
388
+ lucideReactNative.Check,
389
+ {
390
+ size: 12,
391
+ color: step.eventType === "USER_ACTION_SUCCESS" ? "#16a34a" : "#007AFF"
392
+ }
393
+ ),
374
394
  step.status === "error" && /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.X, { size: 12, color: "#FF3B30" }),
375
395
  /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles2.stepContent, children: [
376
396
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -378,7 +398,8 @@ function AgentMessage({
378
398
  {
379
399
  style: [
380
400
  styles2.stepText,
381
- step.status === "error" && styles2.stepTextError
401
+ step.status === "error" && styles2.stepTextError,
402
+ step.eventType === "USER_ACTION_SUCCESS" && styles2.stepTextSuccess
382
403
  ],
383
404
  children: step.message
384
405
  }
@@ -410,7 +431,10 @@ function AgentMessage({
410
431
  tracingData: message.tracingData,
411
432
  executionId: message.executionId
412
433
  }),
413
- style: styles2.traceButton,
434
+ style: [
435
+ styles2.traceButton,
436
+ message.userActionResult ? styles2.traceButtonWithBadge : void 0
437
+ ],
414
438
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReactNative.Binoculars, { size: 16, color: "#007AFF" })
415
439
  }
416
440
  )
@@ -560,6 +584,9 @@ var styles2 = reactNative.StyleSheet.create({
560
584
  stepTextError: {
561
585
  color: "#FF3B30"
562
586
  },
587
+ stepTextSuccess: {
588
+ color: "#16a34a"
589
+ },
563
590
  stepTime: {
564
591
  fontSize: 10,
565
592
  opacity: 0.5,
@@ -572,6 +599,37 @@ var styles2 = reactNative.StyleSheet.create({
572
599
  borderWidth: 1,
573
600
  borderColor: "rgba(255,255,255,0.2)",
574
601
  borderRadius: 8
602
+ },
603
+ traceButtonWithBadge: {
604
+ marginTop: 32
605
+ },
606
+ badgeContainer: {
607
+ marginBottom: 8
608
+ },
609
+ badge: {
610
+ flexDirection: "row",
611
+ alignItems: "center",
612
+ gap: 4,
613
+ paddingHorizontal: 8,
614
+ paddingVertical: 4,
615
+ borderRadius: 12,
616
+ alignSelf: "flex-start"
617
+ },
618
+ badgeApproved: {
619
+ backgroundColor: "#dcfce7"
620
+ },
621
+ badgeApprovedText: {
622
+ fontSize: 12,
623
+ fontWeight: "500",
624
+ color: "#15803d"
625
+ },
626
+ badgeRejected: {
627
+ backgroundColor: "#fee2e2"
628
+ },
629
+ badgeRejectedText: {
630
+ fontSize: 12,
631
+ fontWeight: "500",
632
+ color: "#b91c1c"
575
633
  }
576
634
  });
577
635
  var markdownStyles = {
@@ -1001,6 +1059,400 @@ var styles5 = reactNative.StyleSheet.create({
1001
1059
  width: "100%"
1002
1060
  }
1003
1061
  });
1062
+ var DEFAULT_MAX_LENGTH = 6;
1063
+ var MAX_SUPPORTED_LENGTH = 12;
1064
+ function OtpInput({ value, onChange, maxLength, disabled = false }) {
1065
+ const inputRefs = React.useRef([]);
1066
+ const safeMaxLength = Number.isInteger(maxLength) && maxLength > 0 ? Math.min(maxLength, MAX_SUPPORTED_LENGTH) : DEFAULT_MAX_LENGTH;
1067
+ const digits = value.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
1068
+ React.useEffect(() => {
1069
+ if (!disabled) {
1070
+ inputRefs.current[0]?.focus();
1071
+ }
1072
+ }, [disabled]);
1073
+ const focusInput = (index) => {
1074
+ if (index >= 0 && index < safeMaxLength) {
1075
+ inputRefs.current[index]?.focus();
1076
+ }
1077
+ };
1078
+ const updateValue = (newDigits) => {
1079
+ onChange(newDigits.join("").slice(0, safeMaxLength));
1080
+ };
1081
+ const handleChange = (index, text) => {
1082
+ const cleaned = text.replace(/\D/g, "");
1083
+ if (cleaned.length > 1) {
1084
+ const pasted = cleaned.slice(0, safeMaxLength);
1085
+ const newDigits2 = pasted.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
1086
+ updateValue(newDigits2);
1087
+ focusInput(Math.min(pasted.length, safeMaxLength - 1));
1088
+ return;
1089
+ }
1090
+ const char = cleaned.slice(-1);
1091
+ const newDigits = [...digits];
1092
+ newDigits[index] = char;
1093
+ updateValue(newDigits);
1094
+ if (char && index < safeMaxLength - 1) {
1095
+ focusInput(index + 1);
1096
+ }
1097
+ };
1098
+ const handleKeyPress = (index, key) => {
1099
+ if (key === "Backspace") {
1100
+ if (digits[index]) {
1101
+ const newDigits = [...digits];
1102
+ newDigits[index] = "";
1103
+ updateValue(newDigits);
1104
+ } else if (index > 0) {
1105
+ const newDigits = [...digits];
1106
+ newDigits[index - 1] = "";
1107
+ updateValue(newDigits);
1108
+ focusInput(index - 1);
1109
+ }
1110
+ }
1111
+ };
1112
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles6.container, children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
1113
+ reactNative.TextInput,
1114
+ {
1115
+ ref: (el) => {
1116
+ inputRefs.current[i] = el;
1117
+ },
1118
+ value: digit,
1119
+ editable: !disabled,
1120
+ keyboardType: "number-pad",
1121
+ maxLength: 1,
1122
+ onChangeText: (text) => handleChange(i, text),
1123
+ onKeyPress: ({ nativeEvent }) => handleKeyPress(i, nativeEvent.key),
1124
+ onFocus: () => inputRefs.current[i]?.setNativeProps({ selection: { start: 0, end: 1 } }),
1125
+ style: [styles6.input, disabled && styles6.inputDisabled],
1126
+ accessibilityLabel: `Digit ${i + 1}`
1127
+ },
1128
+ i
1129
+ )) });
1130
+ }
1131
+ var styles6 = reactNative.StyleSheet.create({
1132
+ container: {
1133
+ flexDirection: "row",
1134
+ gap: 8,
1135
+ justifyContent: "center"
1136
+ },
1137
+ input: {
1138
+ width: 40,
1139
+ height: 48,
1140
+ textAlign: "center",
1141
+ fontSize: 20,
1142
+ fontWeight: "600",
1143
+ borderWidth: 1,
1144
+ borderColor: "#E5E5E5",
1145
+ borderRadius: 8,
1146
+ color: "#000"
1147
+ },
1148
+ inputDisabled: {
1149
+ backgroundColor: "#F5F5F5",
1150
+ opacity: 0.5
1151
+ }
1152
+ });
1153
+
1154
+ // src/components/UserActionModal/constants.ts
1155
+ var BUTTON_LABELS = {
1156
+ APPROVE: "Verify",
1157
+ REJECT: "Reject",
1158
+ RESEND: "Resend OTP"
1159
+ };
1160
+ var RESEND_OTP_COOLDOWN_SECONDS = 30;
1161
+ var DEFAULT_OTP_MAX_LENGTH = 6;
1162
+ var MIN_OTP_MAX_LENGTH = 1;
1163
+ var MAX_OTP_MAX_LENGTH = 12;
1164
+ var ACTION_PENDING_TIMEOUT_MS = 15e3;
1165
+ var MODAL_CONTENT = {
1166
+ TITLE: "Verification Required",
1167
+ LOADING_APPROVE: "Verifying...",
1168
+ LOADING_REJECT: "Rejecting...",
1169
+ LOADING_RESEND: "Resending...",
1170
+ RESEND_AVAILABLE_IN: "Resend OTP in"
1171
+ };
1172
+
1173
+ // src/components/UserActionModal/utils.ts
1174
+ function getOtpSchemaFromRequest(schema) {
1175
+ const properties = schema?.properties;
1176
+ const otp = properties?.otp;
1177
+ const maxLengthRaw = otp?.maxLength;
1178
+ const parsedMaxLength = Number.isInteger(maxLengthRaw) ? Number(maxLengthRaw) : DEFAULT_OTP_MAX_LENGTH;
1179
+ const clampedMaxLength = Math.min(
1180
+ MAX_OTP_MAX_LENGTH,
1181
+ Math.max(MIN_OTP_MAX_LENGTH, parsedMaxLength)
1182
+ );
1183
+ return {
1184
+ maxLength: clampedMaxLength
1185
+ };
1186
+ }
1187
+ function UserActionModal({
1188
+ isOpen,
1189
+ userActionRequest,
1190
+ onApprove,
1191
+ onReject,
1192
+ onResend,
1193
+ clearOtpTrigger
1194
+ }) {
1195
+ const [otp, setOtp] = React.useState("");
1196
+ const [actionType, setActionType] = React.useState(null);
1197
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
1198
+ const [resendCooldownRemaining, setResendCooldownRemaining] = React.useState(0);
1199
+ const schema = getOtpSchemaFromRequest(userActionRequest?.requestedSchema);
1200
+ const resetActionState = React.useCallback(() => {
1201
+ setIsSubmitting(false);
1202
+ setActionType(null);
1203
+ }, []);
1204
+ React.useEffect(() => {
1205
+ if (isOpen) {
1206
+ setResendCooldownRemaining(RESEND_OTP_COOLDOWN_SECONDS);
1207
+ } else {
1208
+ setOtp("");
1209
+ resetActionState();
1210
+ setResendCooldownRemaining(0);
1211
+ }
1212
+ }, [isOpen, resetActionState]);
1213
+ React.useEffect(() => {
1214
+ if (resendCooldownRemaining <= 0) return;
1215
+ const timer = setTimeout(() => {
1216
+ setResendCooldownRemaining((prev) => prev - 1);
1217
+ }, 1e3);
1218
+ return () => clearTimeout(timer);
1219
+ }, [resendCooldownRemaining]);
1220
+ React.useEffect(() => {
1221
+ if (clearOtpTrigger > 0) {
1222
+ setOtp("");
1223
+ resetActionState();
1224
+ }
1225
+ }, [clearOtpTrigger, resetActionState]);
1226
+ React.useEffect(() => {
1227
+ if (!isOpen || !isSubmitting) return;
1228
+ if (actionType !== "approve" && actionType !== "reject") return;
1229
+ const timeout = setTimeout(() => {
1230
+ resetActionState();
1231
+ }, ACTION_PENDING_TIMEOUT_MS);
1232
+ return () => clearTimeout(timeout);
1233
+ }, [isOpen, isSubmitting, actionType, resetActionState]);
1234
+ const handleApprove = React.useCallback(async () => {
1235
+ if (otp.length !== schema.maxLength || !/^\d+$/.test(otp)) return;
1236
+ setIsSubmitting(true);
1237
+ setActionType("approve");
1238
+ try {
1239
+ await onApprove(otp);
1240
+ } catch {
1241
+ resetActionState();
1242
+ }
1243
+ }, [otp, schema.maxLength, onApprove, resetActionState]);
1244
+ const handleReject = React.useCallback(async () => {
1245
+ setIsSubmitting(true);
1246
+ setActionType("reject");
1247
+ try {
1248
+ await onReject();
1249
+ } catch {
1250
+ resetActionState();
1251
+ }
1252
+ }, [onReject, resetActionState]);
1253
+ const handleResend = React.useCallback(async () => {
1254
+ if (resendCooldownRemaining > 0) return;
1255
+ setIsSubmitting(true);
1256
+ setActionType("resend");
1257
+ try {
1258
+ await onResend();
1259
+ setResendCooldownRemaining(RESEND_OTP_COOLDOWN_SECONDS);
1260
+ } catch {
1261
+ } finally {
1262
+ setActionType(null);
1263
+ setIsSubmitting(false);
1264
+ }
1265
+ }, [resendCooldownRemaining, onResend]);
1266
+ if (!userActionRequest) return null;
1267
+ const isOtpValid = otp.length === schema.maxLength && /^\d+$/.test(otp);
1268
+ const getResendLabel = () => {
1269
+ if (actionType === "resend") return MODAL_CONTENT.LOADING_RESEND;
1270
+ if (resendCooldownRemaining > 0)
1271
+ return `${MODAL_CONTENT.RESEND_AVAILABLE_IN} ${resendCooldownRemaining}s`;
1272
+ return BUTTON_LABELS.RESEND;
1273
+ };
1274
+ return /* @__PURE__ */ jsxRuntime.jsx(
1275
+ reactNative.Modal,
1276
+ {
1277
+ visible: isOpen,
1278
+ transparent: true,
1279
+ animationType: "fade",
1280
+ onRequestClose: () => {
1281
+ },
1282
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.backdrop, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.dialog, children: [
1283
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.titleContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.title, children: MODAL_CONTENT.TITLE }) }),
1284
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.description, children: userActionRequest.message }),
1285
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.otpContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
1286
+ OtpInput,
1287
+ {
1288
+ value: otp,
1289
+ onChange: setOtp,
1290
+ maxLength: schema.maxLength,
1291
+ disabled: isSubmitting
1292
+ }
1293
+ ) }),
1294
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.buttonsColumn, children: [
1295
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.primaryButtonsRow, children: [
1296
+ /* @__PURE__ */ jsxRuntime.jsxs(
1297
+ reactNative.Pressable,
1298
+ {
1299
+ onPress: handleReject,
1300
+ disabled: isSubmitting,
1301
+ style: ({ pressed }) => [
1302
+ styles7.rejectButton,
1303
+ isSubmitting && styles7.buttonDisabled,
1304
+ pressed && styles7.rejectButtonPressed
1305
+ ],
1306
+ children: [
1307
+ actionType === "reject" && /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "small", color: "#DC2626", style: styles7.spinner }),
1308
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.rejectButtonText, children: actionType === "reject" ? MODAL_CONTENT.LOADING_REJECT : BUTTON_LABELS.REJECT })
1309
+ ]
1310
+ }
1311
+ ),
1312
+ /* @__PURE__ */ jsxRuntime.jsxs(
1313
+ reactNative.Pressable,
1314
+ {
1315
+ onPress: handleApprove,
1316
+ disabled: !isOtpValid || isSubmitting,
1317
+ style: ({ pressed }) => [
1318
+ styles7.approveButton,
1319
+ (!isOtpValid || isSubmitting) && styles7.buttonDisabled,
1320
+ pressed && styles7.approveButtonPressed
1321
+ ],
1322
+ children: [
1323
+ actionType === "approve" && /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "small", color: "#FFF", style: styles7.spinner }),
1324
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.approveButtonText, children: actionType === "approve" ? MODAL_CONTENT.LOADING_APPROVE : BUTTON_LABELS.APPROVE })
1325
+ ]
1326
+ }
1327
+ )
1328
+ ] }),
1329
+ /* @__PURE__ */ jsxRuntime.jsxs(
1330
+ reactNative.Pressable,
1331
+ {
1332
+ onPress: handleResend,
1333
+ disabled: isSubmitting || resendCooldownRemaining > 0,
1334
+ style: ({ pressed }) => [
1335
+ styles7.resendButton,
1336
+ (isSubmitting || resendCooldownRemaining > 0) && styles7.buttonDisabled,
1337
+ pressed && styles7.resendButtonPressed
1338
+ ],
1339
+ children: [
1340
+ actionType === "resend" && /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "small", color: "#666", style: styles7.spinner }),
1341
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.resendButtonText, children: getResendLabel() })
1342
+ ]
1343
+ }
1344
+ )
1345
+ ] })
1346
+ ] }) })
1347
+ }
1348
+ );
1349
+ }
1350
+ var styles7 = reactNative.StyleSheet.create({
1351
+ backdrop: {
1352
+ flex: 1,
1353
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
1354
+ justifyContent: "center",
1355
+ alignItems: "center"
1356
+ },
1357
+ dialog: {
1358
+ backgroundColor: "#FFF",
1359
+ borderRadius: 12,
1360
+ padding: 24,
1361
+ width: "90%",
1362
+ maxWidth: 420
1363
+ },
1364
+ titleContainer: {
1365
+ alignItems: "center",
1366
+ marginBottom: 16
1367
+ },
1368
+ title: {
1369
+ fontSize: 18,
1370
+ fontWeight: "600",
1371
+ color: "#000"
1372
+ },
1373
+ description: {
1374
+ fontSize: 14,
1375
+ color: "#666",
1376
+ textAlign: "center",
1377
+ marginBottom: 24,
1378
+ lineHeight: 21
1379
+ },
1380
+ otpContainer: {
1381
+ marginBottom: 24
1382
+ },
1383
+ buttonsColumn: {
1384
+ gap: 10
1385
+ },
1386
+ primaryButtonsRow: {
1387
+ flexDirection: "row",
1388
+ gap: 8
1389
+ },
1390
+ resendButton: {
1391
+ borderRadius: 8,
1392
+ paddingVertical: 8,
1393
+ paddingHorizontal: 16,
1394
+ flexDirection: "row",
1395
+ alignItems: "center",
1396
+ justifyContent: "center"
1397
+ },
1398
+ resendButtonPressed: {
1399
+ opacity: 0.7
1400
+ },
1401
+ resendButtonText: {
1402
+ color: "#666",
1403
+ fontSize: 12,
1404
+ fontWeight: "500"
1405
+ },
1406
+ rejectButton: {
1407
+ flex: 1,
1408
+ borderRadius: 8,
1409
+ paddingVertical: 12,
1410
+ paddingHorizontal: 16,
1411
+ backgroundColor: "rgba(220, 38, 38, 0.1)",
1412
+ flexDirection: "row",
1413
+ alignItems: "center",
1414
+ justifyContent: "center"
1415
+ },
1416
+ rejectButtonPressed: {
1417
+ backgroundColor: "rgba(220, 38, 38, 0.2)"
1418
+ },
1419
+ rejectButtonText: {
1420
+ color: "#DC2626",
1421
+ fontSize: 14,
1422
+ fontWeight: "500"
1423
+ },
1424
+ approveButton: {
1425
+ flex: 1,
1426
+ borderRadius: 8,
1427
+ paddingVertical: 12,
1428
+ paddingHorizontal: 16,
1429
+ backgroundColor: "#007AFF",
1430
+ flexDirection: "row",
1431
+ alignItems: "center",
1432
+ justifyContent: "center"
1433
+ },
1434
+ approveButtonPressed: {
1435
+ backgroundColor: "#0066D6",
1436
+ opacity: 1
1437
+ },
1438
+ approveButtonText: {
1439
+ color: "#FFF",
1440
+ fontSize: 14,
1441
+ fontWeight: "600"
1442
+ },
1443
+ buttonDisabled: {
1444
+ opacity: 0.5
1445
+ },
1446
+ spinner: {
1447
+ marginRight: 8
1448
+ }
1449
+ });
1450
+ var DEFAULT_USER_ACTION_STATE = {
1451
+ request: null,
1452
+ clearOtpTrigger: 0
1453
+ };
1454
+ var NOOP_ASYNC = async () => {
1455
+ };
1004
1456
  function PaymanChat({
1005
1457
  config,
1006
1458
  callbacks = {},
@@ -1009,6 +1461,7 @@ function PaymanChat({
1009
1461
  children
1010
1462
  }) {
1011
1463
  const [inputValue, setInputValue] = React.useState("");
1464
+ const chat = paymanTypescriptAskSdk.useChat(config, callbacks);
1012
1465
  const {
1013
1466
  messages,
1014
1467
  sendMessage,
@@ -1018,7 +1471,12 @@ function PaymanChat({
1018
1471
  cancelStream,
1019
1472
  getSessionId,
1020
1473
  getMessages
1021
- } = paymanTypescriptAskSdk.useChat(config, callbacks);
1474
+ } = chat;
1475
+ const userActionState = chat.userActionState ?? DEFAULT_USER_ACTION_STATE;
1476
+ const approveUserAction = chat.approveUserAction ?? NOOP_ASYNC;
1477
+ const rejectUserAction = chat.rejectUserAction ?? NOOP_ASYNC;
1478
+ const resendOtp = chat.resendOtp ?? NOOP_ASYNC;
1479
+ const isUserActionSupported = typeof chat.approveUserAction === "function" && typeof chat.rejectUserAction === "function" && typeof chat.resendOtp === "function";
1022
1480
  const contextValue = React.useMemo(
1023
1481
  () => ({
1024
1482
  resetSession,
@@ -1074,20 +1532,20 @@ function PaymanChat({
1074
1532
  const isInputDisabled = isWaitingForResponse || !isSessionParamsConfigured || disableInput;
1075
1533
  if (isChatDisabled) {
1076
1534
  if (disabledComponent) {
1077
- return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles6.container, style], children: [
1535
+ return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles8.container, style], children: [
1078
1536
  children,
1079
1537
  disabledComponent
1080
1538
  ] }) });
1081
1539
  }
1082
- return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles6.container, style], children: [
1540
+ return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles8.container, style], children: [
1083
1541
  children,
1084
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles6.disabledContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles6.disabledText, children: "Chat is currently disabled" }) })
1542
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.disabledContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.disabledText, children: "Chat is currently disabled" }) })
1085
1543
  ] }) });
1086
1544
  }
1087
1545
  return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
1088
1546
  reactNative.KeyboardAvoidingView,
1089
1547
  {
1090
- style: [styles6.container, style],
1548
+ style: [styles8.container, style],
1091
1549
  behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
1092
1550
  keyboardVerticalOffset: reactNative.Platform.OS === "ios" ? 90 : 0,
1093
1551
  children: [
@@ -1130,12 +1588,23 @@ function PaymanChat({
1130
1588
  inputStyle,
1131
1589
  layout
1132
1590
  }
1591
+ ),
1592
+ /* @__PURE__ */ jsxRuntime.jsx(
1593
+ UserActionModal,
1594
+ {
1595
+ isOpen: isUserActionSupported && userActionState.request !== null,
1596
+ userActionRequest: userActionState.request,
1597
+ onApprove: approveUserAction,
1598
+ onReject: rejectUserAction,
1599
+ onResend: resendOtp,
1600
+ clearOtpTrigger: userActionState.clearOtpTrigger
1601
+ }
1133
1602
  )
1134
1603
  ]
1135
1604
  }
1136
1605
  ) });
1137
1606
  }
1138
- var styles6 = reactNative.StyleSheet.create({
1607
+ var styles8 = reactNative.StyleSheet.create({
1139
1608
  container: {
1140
1609
  flex: 1,
1141
1610
  backgroundColor: "#FFF",
@@ -1157,14 +1626,26 @@ var styles6 = reactNative.StyleSheet.create({
1157
1626
  }
1158
1627
  });
1159
1628
 
1629
+ Object.defineProperty(exports, "cancelUserAction", {
1630
+ enumerable: true,
1631
+ get: function () { return paymanTypescriptAskSdk.cancelUserAction; }
1632
+ });
1160
1633
  Object.defineProperty(exports, "generateId", {
1161
1634
  enumerable: true,
1162
1635
  get: function () { return paymanTypescriptAskSdk.generateId; }
1163
1636
  });
1637
+ Object.defineProperty(exports, "resendUserAction", {
1638
+ enumerable: true,
1639
+ get: function () { return paymanTypescriptAskSdk.resendUserAction; }
1640
+ });
1164
1641
  Object.defineProperty(exports, "streamWorkflowEvents", {
1165
1642
  enumerable: true,
1166
1643
  get: function () { return paymanTypescriptAskSdk.streamWorkflowEvents; }
1167
1644
  });
1645
+ Object.defineProperty(exports, "submitUserAction", {
1646
+ enumerable: true,
1647
+ get: function () { return paymanTypescriptAskSdk.submitUserAction; }
1648
+ });
1168
1649
  Object.defineProperty(exports, "useChat", {
1169
1650
  enumerable: true,
1170
1651
  get: function () { return paymanTypescriptAskSdk.useChat; }