braid-ui 1.0.49 → 1.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -8401,15 +8401,14 @@ var TRANSACTION_TYPES = [
8401
8401
  { value: "ach", label: "ACH", icon: lucideReact.Building2 },
8402
8402
  { value: "wire", label: "Wire", icon: lucideReact.Zap }
8403
8403
  ];
8404
- var CURRENCY_OPTIONS = [
8405
- { value: "USD", label: "USD - US Dollar" },
8406
- { value: "EUR", label: "EUR - Euro" },
8407
- { value: "GBP", label: "GBP - British Pound" },
8408
- { value: "JPY", label: "JPY - Japanese Yen" },
8409
- { value: "CAD", label: "CAD - Canadian Dollar" },
8410
- { value: "AUD", label: "AUD - Australian Dollar" },
8411
- { value: "CHF", label: "CHF - Swiss Franc" },
8412
- { value: "CNY", label: "CNY - Chinese Yuan" }
8404
+ var ADJUSTMENT_DIRECTION_OPTIONS = [
8405
+ { value: "debit", label: "Debit" },
8406
+ { value: "credit", label: "Credit" }
8407
+ ];
8408
+ var ADJUSTMENT_TYPE_OPTIONS = [
8409
+ { value: "collection", label: "Collection" },
8410
+ { value: "transaction_reversal", label: "Transaction Reversal" },
8411
+ { value: "transaction_adjustment", label: "Transaction Adjustment" }
8413
8412
  ];
8414
8413
  var NewTransactionView = ({
8415
8414
  form,
@@ -8421,19 +8420,39 @@ var NewTransactionView = ({
8421
8420
  submissionStatus,
8422
8421
  errorMessage,
8423
8422
  transactionId,
8423
+ isAccountLoading,
8424
+ isCounterpartyLoading,
8425
+ isSubmitting,
8426
+ counterpartySearchResults,
8427
+ isCounterpartySearching,
8428
+ showCounterpartyDropdown,
8424
8429
  onAccountLookup,
8425
- onCounterpartyLookup,
8426
8430
  onEditAccount,
8427
8431
  onEditCounterparty,
8432
+ onTransactionTypeChange,
8428
8433
  onSubmit,
8429
8434
  onCancel,
8430
8435
  onConfirmationClose,
8431
- onConfirmationOpenChange
8436
+ onConfirmationOpenChange,
8437
+ onCounterpartySearchChange,
8438
+ onCounterpartySelect,
8439
+ onCounterpartyDropdownClose,
8440
+ receiverAccountLookedUp,
8441
+ receiverAccountData,
8442
+ isReceiverAccountLoading,
8443
+ onReceiverAccountLookup,
8444
+ onEditReceiverAccount
8432
8445
  }) => {
8433
8446
  const transactionType = form.watch("transactionType");
8434
8447
  const accountNumber = form.watch("accountNumber");
8435
8448
  const counterpartyName = form.watch("counterpartyName");
8436
8449
  const amount = form.watch("amount");
8450
+ const receiverAccountNumber = form.watch("receiverAccountNumber");
8451
+ const adjustmentDirection = form.watch("adjustmentDirection");
8452
+ const adjustmentType = form.watch("adjustmentType");
8453
+ const requiresCounterparty = ["ach", "wire"].includes(transactionType);
8454
+ const isTransfer = transactionType === "transfer";
8455
+ const isAdjustment = transactionType === "adjustment";
8437
8456
  const accountDataGrid = accountData ? [
8438
8457
  {
8439
8458
  title: "Account Information",
@@ -8453,27 +8472,41 @@ var NewTransactionView = ({
8453
8472
  items: [
8454
8473
  { label: "Counterparty Name", value: counterpartyData.counterpartyName },
8455
8474
  { label: "Counterparty ID", value: counterpartyData.counterpartyId },
8456
- { label: "Type", value: counterpartyData.counterpartyType },
8457
- { label: "Status", value: counterpartyData.status },
8458
- { label: "Tax ID", value: counterpartyData.taxId },
8459
- { label: "Primary Contact", value: counterpartyData.primaryContact },
8475
+ { label: "Instrument Type", value: counterpartyData.paymentInstrumentType?.toUpperCase() || "-" },
8460
8476
  { label: "Contact Email", value: counterpartyData.contactEmail },
8461
- { label: "Contact Phone", value: counterpartyData.contactPhone },
8462
- { label: "Address", value: counterpartyData.address }
8477
+ { label: "Contact Phone", value: counterpartyData.contactPhone }
8463
8478
  ]
8464
8479
  }
8465
8480
  ] : [];
8466
- const reviewData = [
8481
+ const receiverAccountDataGrid = receiverAccountData ? [
8467
8482
  {
8468
- title: "Transaction Summary",
8483
+ title: "Receiver Account Information",
8469
8484
  items: [
8470
- { label: "Transaction Type", value: TRANSACTION_TYPES.find((t) => t.value === transactionType)?.label || "-" },
8471
- { label: "Account Number", value: accountNumber || "-" },
8472
- { label: "Counterparty", value: counterpartyName || "-" },
8473
- { label: "Amount", value: amount ? `$${amount}` : "-" },
8474
- { label: "Description", value: form.watch("description") || "N/A" }
8485
+ { label: "Account Number", value: receiverAccountData.accountNumber },
8486
+ { label: "Account Name", value: receiverAccountData.accountName },
8487
+ { label: "Account Type", value: receiverAccountData.accountType },
8488
+ { label: "Customer Name", value: receiverAccountData.customerName },
8489
+ { label: "Customer ID", value: receiverAccountData.customerId }
8475
8490
  ]
8476
8491
  }
8492
+ ] : [];
8493
+ const reviewItems = [
8494
+ { label: "Transaction Type", value: TRANSACTION_TYPES.find((t) => t.value === transactionType)?.label || "-" },
8495
+ { label: "Account Number", value: accountNumber || "-" },
8496
+ ...isAdjustment ? [
8497
+ { label: "Direction", value: adjustmentDirection === "debit" ? "Debit" : adjustmentDirection === "credit" ? "Credit" : "-" },
8498
+ { label: "Adjustment Type", value: ADJUSTMENT_TYPE_OPTIONS.find((t) => t.value === adjustmentType)?.label || "-" }
8499
+ ] : [],
8500
+ ...isTransfer ? [{ label: "Receiver Account", value: receiverAccountNumber || "-" }] : [],
8501
+ ...requiresCounterparty ? [{ label: "Counterparty", value: counterpartyName || "-" }] : [],
8502
+ { label: "Amount", value: amount ? `$${amount}` : "-" },
8503
+ { label: "Description", value: form.watch("description") || "N/A" }
8504
+ ];
8505
+ const reviewData = [
8506
+ {
8507
+ title: "Transaction Summary",
8508
+ items: reviewItems
8509
+ }
8477
8510
  ];
8478
8511
  return /* @__PURE__ */ jsxRuntime.jsx(PageLayout, { title: "New Transaction", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-4xl mx-auto space-y-6", children: [
8479
8512
  /* @__PURE__ */ jsxRuntime.jsx(FormProvider, { form, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => e.preventDefault(), children: [
@@ -8485,16 +8518,19 @@ var NewTransactionView = ({
8485
8518
  placeholder: "Enter account number"
8486
8519
  }
8487
8520
  ) }),
8488
- /* @__PURE__ */ jsxRuntime.jsxs(
8521
+ /* @__PURE__ */ jsxRuntime.jsx(
8489
8522
  Button,
8490
8523
  {
8491
8524
  onClick: onAccountLookup,
8492
- disabled: !accountNumber,
8525
+ disabled: !accountNumber || isAccountLoading,
8493
8526
  className: "shrink-0 mt-0 w-48",
8494
- children: [
8527
+ children: isAccountLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8528
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 mr-2 animate-spin" }),
8529
+ "Looking up..."
8530
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8495
8531
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "h-4 w-4 mr-2" }),
8496
8532
  "Lookup Account"
8497
- ]
8533
+ ] })
8498
8534
  }
8499
8535
  )
8500
8536
  ] }) }) : /* @__PURE__ */ jsxRuntime.jsx(
@@ -8525,7 +8561,7 @@ var NewTransactionView = ({
8525
8561
  "button",
8526
8562
  {
8527
8563
  type: "button",
8528
- onClick: () => form.setValue("transactionType", type.value),
8564
+ onClick: () => onTransactionTypeChange(type.value),
8529
8565
  disabled: !accountLookedUp,
8530
8566
  className: cn(
8531
8567
  "flex flex-col items-center justify-center p-4 lg:p-3 rounded-lg border-2 transition-all",
@@ -8548,31 +8584,99 @@ var NewTransactionView = ({
8548
8584
  }) })
8549
8585
  }
8550
8586
  ),
8551
- !counterpartyLookedUp ? /* @__PURE__ */ jsxRuntime.jsx(
8587
+ requiresCounterparty && (!counterpartyLookedUp ? /* @__PURE__ */ jsxRuntime.jsxs(
8552
8588
  FormCard,
8553
8589
  {
8554
- title: "Counterparty Lookup",
8590
+ title: "Counterparty Search",
8591
+ variant: "default",
8592
+ className: cn(!transactionType && "opacity-50 pointer-events-none"),
8593
+ children: [
8594
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
8595
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
8596
+ /* @__PURE__ */ jsxRuntime.jsx(
8597
+ "input",
8598
+ {
8599
+ type: "text",
8600
+ placeholder: "Start typing to search counterparties...",
8601
+ value: counterpartyName,
8602
+ onChange: (e) => onCounterpartySearchChange(e.target.value),
8603
+ disabled: !transactionType,
8604
+ className: cn(
8605
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
8606
+ "ring-offset-background placeholder:text-muted-foreground",
8607
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
8608
+ "disabled:cursor-not-allowed disabled:opacity-50",
8609
+ isCounterpartySearching && "pr-10"
8610
+ )
8611
+ }
8612
+ ),
8613
+ isCounterpartySearching && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-3 top-1/2 -translate-y-1/2", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) })
8614
+ ] }),
8615
+ showCounterpartyDropdown && counterpartySearchResults.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute z-50 w-full mt-1 bg-popover border border-border rounded-md shadow-lg max-h-60 overflow-auto", children: counterpartySearchResults.map((result) => /* @__PURE__ */ jsxRuntime.jsxs(
8616
+ "button",
8617
+ {
8618
+ type: "button",
8619
+ onClick: () => onCounterpartySelect(result),
8620
+ className: "w-full px-3 py-2 text-left hover:bg-accent transition-colors",
8621
+ children: [
8622
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-sm", children: result.name }),
8623
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: result.id })
8624
+ ]
8625
+ },
8626
+ result.id
8627
+ )) }),
8628
+ showCounterpartyDropdown && counterpartySearchResults.length === 0 && !isCounterpartySearching && counterpartyName.length >= 2 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute z-50 w-full mt-1 bg-popover border border-border rounded-md shadow-lg p-3", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
8629
+ 'No counterparties found matching "',
8630
+ counterpartyName,
8631
+ '"'
8632
+ ] }) })
8633
+ ] }),
8634
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-2", children: "Type at least 2 characters to search" })
8635
+ ]
8636
+ }
8637
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
8638
+ FormCard,
8639
+ {
8640
+ title: "Counterparty Information",
8641
+ variant: "subtle",
8642
+ headerActions: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8643
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-5 w-5 text-success" }),
8644
+ /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", onClick: onEditCounterparty, children: [
8645
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, { className: "h-4 w-4 mr-1" }),
8646
+ "Edit"
8647
+ ] })
8648
+ ] }),
8649
+ children: /* @__PURE__ */ jsxRuntime.jsx(DataGrid, { data: counterpartyDataGrid, columns: 2 })
8650
+ }
8651
+ )),
8652
+ isTransfer && (!receiverAccountLookedUp ? /* @__PURE__ */ jsxRuntime.jsx(
8653
+ FormCard,
8654
+ {
8655
+ title: "Receiver Account",
8555
8656
  variant: "default",
8556
8657
  className: cn(!transactionType && "opacity-50 pointer-events-none"),
8557
8658
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 items-start w-full", children: [
8558
8659
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
8559
8660
  FormInput,
8560
8661
  {
8561
- name: "counterpartyName",
8562
- placeholder: "Enter counterparty name",
8662
+ name: "receiverAccountNumber",
8663
+ placeholder: "Enter receiver account number",
8563
8664
  disabled: !transactionType
8564
8665
  }
8565
8666
  ) }),
8566
- /* @__PURE__ */ jsxRuntime.jsxs(
8667
+ /* @__PURE__ */ jsxRuntime.jsx(
8567
8668
  Button,
8568
8669
  {
8569
- onClick: onCounterpartyLookup,
8570
- disabled: !transactionType || !counterpartyName,
8670
+ onClick: onReceiverAccountLookup,
8671
+ disabled: !receiverAccountNumber || isReceiverAccountLoading,
8571
8672
  className: "shrink-0 mt-0 w-48",
8572
- children: [
8673
+ children: isReceiverAccountLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8674
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 mr-2 animate-spin" }),
8675
+ "Looking up..."
8676
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8573
8677
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "h-4 w-4 mr-2" }),
8574
- "Lookup Counterparty"
8575
- ]
8678
+ "Lookup Receiver"
8679
+ ] })
8576
8680
  }
8577
8681
  )
8578
8682
  ] })
@@ -8580,54 +8684,66 @@ var NewTransactionView = ({
8580
8684
  ) : /* @__PURE__ */ jsxRuntime.jsx(
8581
8685
  FormCard,
8582
8686
  {
8583
- title: "Counterparty Information",
8687
+ title: "Receiver Account Information",
8584
8688
  variant: "subtle",
8585
8689
  headerActions: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8586
8690
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-5 w-5 text-success" }),
8587
- /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", onClick: onEditCounterparty, children: [
8691
+ /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", onClick: onEditReceiverAccount, children: [
8588
8692
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, { className: "h-4 w-4 mr-1" }),
8589
8693
  "Edit"
8590
8694
  ] })
8591
8695
  ] }),
8592
- children: /* @__PURE__ */ jsxRuntime.jsx(DataGrid, { data: counterpartyDataGrid, columns: 2 })
8696
+ children: /* @__PURE__ */ jsxRuntime.jsx(DataGrid, { data: receiverAccountDataGrid, columns: 2 })
8593
8697
  }
8594
- ),
8698
+ )),
8595
8699
  /* @__PURE__ */ jsxRuntime.jsx(
8596
8700
  FormCard,
8597
8701
  {
8598
8702
  title: "Transaction Details",
8599
8703
  variant: "default",
8600
- className: cn(!counterpartyLookedUp && "opacity-50 pointer-events-none"),
8704
+ className: cn(
8705
+ requiresCounterparty ? !counterpartyLookedUp && "opacity-50 pointer-events-none" : isTransfer ? !receiverAccountLookedUp && "opacity-50 pointer-events-none" : !transactionType && "opacity-50 pointer-events-none"
8706
+ ),
8601
8707
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
8602
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-[1fr_auto] gap-4", children: [
8708
+ isAdjustment && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
8603
8709
  /* @__PURE__ */ jsxRuntime.jsx(
8604
- FormInput,
8710
+ FormSelect,
8605
8711
  {
8606
- name: "amount",
8607
- label: "Amount",
8608
- placeholder: "0.00",
8609
- type: "number",
8610
- disabled: !counterpartyLookedUp
8712
+ name: "adjustmentDirection",
8713
+ label: "Direction",
8714
+ placeholder: "Select direction",
8715
+ options: ADJUSTMENT_DIRECTION_OPTIONS,
8716
+ disabled: !transactionType
8611
8717
  }
8612
8718
  ),
8613
8719
  /* @__PURE__ */ jsxRuntime.jsx(
8614
8720
  FormSelect,
8615
8721
  {
8616
- name: "currency",
8617
- label: "Currency",
8618
- options: CURRENCY_OPTIONS,
8619
- disabled: !counterpartyLookedUp,
8620
- className: "w-48"
8722
+ name: "adjustmentType",
8723
+ label: "Adjustment Type",
8724
+ placeholder: "Select type",
8725
+ options: ADJUSTMENT_TYPE_OPTIONS,
8726
+ disabled: !transactionType
8621
8727
  }
8622
8728
  )
8623
8729
  ] }),
8730
+ /* @__PURE__ */ jsxRuntime.jsx(
8731
+ FormInput,
8732
+ {
8733
+ name: "amount",
8734
+ label: "Amount",
8735
+ placeholder: "0.00",
8736
+ type: "number",
8737
+ disabled: requiresCounterparty ? !counterpartyLookedUp : isTransfer ? !receiverAccountLookedUp : !transactionType
8738
+ }
8739
+ ),
8624
8740
  /* @__PURE__ */ jsxRuntime.jsx(
8625
8741
  FormInput,
8626
8742
  {
8627
8743
  name: "description",
8628
8744
  label: "Description (Optional)",
8629
8745
  placeholder: "Enter transaction description",
8630
- disabled: !counterpartyLookedUp
8746
+ disabled: requiresCounterparty ? !counterpartyLookedUp : isTransfer ? !receiverAccountLookedUp : !transactionType
8631
8747
  }
8632
8748
  )
8633
8749
  ] })
@@ -8665,17 +8781,20 @@ var NewTransactionView = ({
8665
8781
  ) }),
8666
8782
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 justify-end pt-4 border-t border-border", children: [
8667
8783
  /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "outline", onClick: onCancel, className: "w-32", children: "Cancel" }),
8668
- /* @__PURE__ */ jsxRuntime.jsxs(
8784
+ /* @__PURE__ */ jsxRuntime.jsx(
8669
8785
  Button,
8670
8786
  {
8671
8787
  type: "button",
8672
8788
  onClick: onSubmit,
8673
8789
  className: "w-48",
8674
- disabled: !transactionType || !accountNumber || !counterpartyName || !amount || !form.watch("certifyInformation"),
8675
- children: [
8790
+ disabled: !transactionType || !accountNumber || requiresCounterparty && !counterpartyName || isTransfer && !receiverAccountLookedUp || isAdjustment && (!adjustmentDirection || !adjustmentType) || !amount || !form.watch("certifyInformation") || isSubmitting,
8791
+ children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8792
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 mr-2 animate-spin" }),
8793
+ "Submitting..."
8794
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8676
8795
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-4 w-4 mr-2" }),
8677
8796
  "Submit Transaction"
8678
- ]
8797
+ ] })
8679
8798
  }
8680
8799
  )
8681
8800
  ] })
@@ -8705,7 +8824,7 @@ var NewTransactionView = ({
8705
8824
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Type:" }),
8706
8825
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: TRANSACTION_TYPES.find((t) => t.value === transactionType)?.label })
8707
8826
  ] }),
8708
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between text-sm", children: [
8827
+ requiresCounterparty && counterpartyName && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between text-sm", children: [
8709
8828
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Counterparty:" }),
8710
8829
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: counterpartyName })
8711
8830
  ] })
@@ -14187,13 +14306,42 @@ var TransactionHistory_default = TransactionHistory;
14187
14306
  var newTransactionSchema = zod.z.object({
14188
14307
  transactionType: zod.z.string().min(1, "Transaction type is required"),
14189
14308
  accountNumber: zod.z.string().min(1, "Account number is required"),
14190
- counterpartyName: zod.z.string().min(1, "Counterparty name is required"),
14309
+ counterpartyName: zod.z.string().optional(),
14191
14310
  amount: zod.z.string().min(1, "Amount is required"),
14192
- currency: zod.z.string().min(1, "Currency is required"),
14193
14311
  description: zod.z.string().optional(),
14194
14312
  certifyInformation: zod.z.boolean().refine((val) => val === true, {
14195
14313
  message: "You must certify the information is correct"
14196
- })
14314
+ }),
14315
+ // Adjustment-specific fields
14316
+ adjustmentDirection: zod.z.string().optional(),
14317
+ adjustmentType: zod.z.string().optional(),
14318
+ // Transfer-specific fields
14319
+ receiverAccountNumber: zod.z.string().optional()
14320
+ }).refine((data) => {
14321
+ const requiresCounterparty = ["ach", "wire"].includes(data.transactionType);
14322
+ if (requiresCounterparty && !data.counterpartyName) {
14323
+ return false;
14324
+ }
14325
+ return true;
14326
+ }, {
14327
+ message: "Counterparty is required for ACH and Wire transactions",
14328
+ path: ["counterpartyName"]
14329
+ }).refine((data) => {
14330
+ if (data.transactionType === "adjustment") {
14331
+ if (!data.adjustmentDirection || !data.adjustmentType) return false;
14332
+ }
14333
+ return true;
14334
+ }, {
14335
+ message: "Direction and Type are required for Adjustment transactions",
14336
+ path: ["adjustmentDirection"]
14337
+ }).refine((data) => {
14338
+ if (data.transactionType === "transfer") {
14339
+ if (!data.receiverAccountNumber) return false;
14340
+ }
14341
+ return true;
14342
+ }, {
14343
+ message: "Receiver account number is required for Transfer transactions",
14344
+ path: ["receiverAccountNumber"]
14197
14345
  });
14198
14346
  var mockAccountData = {
14199
14347
  accountNumber: "****1234",
@@ -14204,27 +14352,25 @@ var mockAccountData = {
14204
14352
  customerId: "CUST-001",
14205
14353
  customerType: "Business"
14206
14354
  };
14207
- var mockCounterpartyData = {
14208
- counterpartyName: "Global Tech Solutions Inc.",
14209
- counterpartyId: "CP-5678",
14210
- counterpartyType: "Business",
14211
- status: "Active",
14212
- taxId: "98-7654321",
14213
- primaryContact: "Sarah Johnson",
14214
- contactEmail: "sarah.johnson@globaltech.com",
14215
- contactPhone: "+1 (555) 987-6543",
14216
- address: "456 Innovation Drive, San Francisco, CA 94105"
14217
- };
14218
14355
  function NewTransaction() {
14219
14356
  const navigate = reactRouterDom.useNavigate();
14220
14357
  const [accountLookedUp, setAccountLookedUp] = React15.useState(false);
14221
14358
  const [accountData, setAccountData] = React15.useState(null);
14222
14359
  const [counterpartyLookedUp, setCounterpartyLookedUp] = React15.useState(false);
14223
14360
  const [counterpartyData, setCounterpartyData] = React15.useState(null);
14361
+ const [counterpartySearchResults, setCounterpartySearchResults] = React15.useState([]);
14362
+ const [isCounterpartySearching, setIsCounterpartySearching] = React15.useState(false);
14363
+ const [showCounterpartyDropdown, setShowCounterpartyDropdown] = React15.useState(false);
14224
14364
  const [confirmationOpen, setConfirmationOpen] = React15.useState(false);
14225
14365
  const [submissionStatus, setSubmissionStatus] = React15.useState(null);
14226
14366
  const [errorMessage, setErrorMessage] = React15.useState("");
14227
14367
  const [transactionId, setTransactionId] = React15.useState("");
14368
+ const [isAccountLoading, setIsAccountLoading] = React15.useState(false);
14369
+ const [isCounterpartyLoading, setIsCounterpartyLoading] = React15.useState(false);
14370
+ const [isSubmitting, setIsSubmitting] = React15.useState(false);
14371
+ const [receiverAccountLookedUp, setReceiverAccountLookedUp] = React15.useState(false);
14372
+ const [receiverAccountData, setReceiverAccountData] = React15.useState(null);
14373
+ const [isReceiverAccountLoading, setIsReceiverAccountLoading] = React15.useState(false);
14228
14374
  const form = reactHookForm.useForm({
14229
14375
  resolver: zod$1.zodResolver(newTransactionSchema),
14230
14376
  defaultValues: {
@@ -14232,30 +14378,131 @@ function NewTransaction() {
14232
14378
  accountNumber: "",
14233
14379
  counterpartyName: "",
14234
14380
  amount: "",
14235
- currency: "USD",
14236
14381
  description: "",
14237
- certifyInformation: false
14382
+ certifyInformation: false,
14383
+ adjustmentDirection: "",
14384
+ adjustmentType: "",
14385
+ receiverAccountNumber: ""
14238
14386
  }
14239
14387
  });
14240
- const handleAccountLookup = () => {
14388
+ const handleAccountLookup = async () => {
14241
14389
  const accNum = form.getValues("accountNumber");
14242
14390
  if (!accNum) {
14243
14391
  sonner.toast.error("Please enter an account number");
14244
14392
  return;
14245
14393
  }
14246
- setAccountData(mockAccountData);
14247
- setAccountLookedUp(true);
14248
- sonner.toast.success("Account found");
14394
+ setIsAccountLoading(true);
14395
+ try {
14396
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
14397
+ setAccountData(mockAccountData);
14398
+ setAccountLookedUp(true);
14399
+ sonner.toast.success("Account found");
14400
+ } catch (error) {
14401
+ sonner.toast.error("Failed to lookup account");
14402
+ } finally {
14403
+ setIsAccountLoading(false);
14404
+ }
14249
14405
  };
14250
- const handleCounterpartyLookup = () => {
14251
- const cpName = form.getValues("counterpartyName");
14252
- if (!cpName) {
14253
- sonner.toast.error("Please enter a counterparty name");
14254
- return;
14406
+ const mockSearchResults = [
14407
+ { id: "CP-5678", name: "Global Tech Solutions Inc.", type: "Business", paymentInstrumentType: "wire" },
14408
+ { id: "CP-1234", name: "Global Industries LLC", type: "Business", paymentInstrumentType: "ach" },
14409
+ { id: "CP-9012", name: "GlobalCorp Partners", type: "Business", paymentInstrumentType: "both" },
14410
+ { id: "CP-3456", name: "Acme Corporation", type: "Business", paymentInstrumentType: "wire" },
14411
+ { id: "CP-7890", name: "Tech Innovations Ltd", type: "Business", paymentInstrumentType: "ach" }
14412
+ ];
14413
+ const isCounterpartyCompatible = (instrumentType, transactionType) => {
14414
+ if (instrumentType === "both") return true;
14415
+ if (transactionType === "ach" && instrumentType === "ach") return true;
14416
+ if (transactionType === "wire" && instrumentType === "wire") return true;
14417
+ return false;
14418
+ };
14419
+ const debouncedSearch = React15.useMemo(
14420
+ () => lodash.debounce(async (query, txType) => {
14421
+ if (query.length < 2) {
14422
+ setCounterpartySearchResults([]);
14423
+ setShowCounterpartyDropdown(false);
14424
+ return;
14425
+ }
14426
+ setIsCounterpartySearching(true);
14427
+ try {
14428
+ await new Promise((resolve) => setTimeout(resolve, 350));
14429
+ let results = mockSearchResults.filter(
14430
+ (cp) => cp.name.toLowerCase().includes(query.toLowerCase())
14431
+ );
14432
+ if (txType === "ach") {
14433
+ results = results.filter(
14434
+ (cp) => cp.paymentInstrumentType === "ach" || cp.paymentInstrumentType === "both"
14435
+ );
14436
+ } else if (txType === "wire") {
14437
+ results = results.filter(
14438
+ (cp) => cp.paymentInstrumentType === "wire" || cp.paymentInstrumentType === "both"
14439
+ );
14440
+ }
14441
+ setCounterpartySearchResults(results);
14442
+ setShowCounterpartyDropdown(true);
14443
+ } finally {
14444
+ setIsCounterpartySearching(false);
14445
+ }
14446
+ }, 350),
14447
+ []
14448
+ );
14449
+ React15.useEffect(() => {
14450
+ return () => {
14451
+ debouncedSearch.cancel();
14452
+ };
14453
+ }, [debouncedSearch]);
14454
+ const handleCounterpartySearchChange = (value) => {
14455
+ form.setValue("counterpartyName", value);
14456
+ if (counterpartyLookedUp) {
14457
+ setCounterpartyLookedUp(false);
14458
+ setCounterpartyData(null);
14255
14459
  }
14256
- setCounterpartyData(mockCounterpartyData);
14257
- setCounterpartyLookedUp(true);
14258
- sonner.toast.success("Counterparty found");
14460
+ debouncedSearch(value, form.getValues("transactionType"));
14461
+ };
14462
+ const handleTransactionTypeChange = (newType) => {
14463
+ form.setValue("transactionType", newType);
14464
+ if (counterpartyData && counterpartyLookedUp) {
14465
+ const requiresCounterparty = ["ach", "wire"].includes(newType);
14466
+ if (requiresCounterparty) {
14467
+ const isCompatible = isCounterpartyCompatible(
14468
+ counterpartyData.paymentInstrumentType,
14469
+ newType
14470
+ );
14471
+ if (!isCompatible) {
14472
+ setCounterpartyLookedUp(false);
14473
+ setCounterpartyData(null);
14474
+ setCounterpartySearchResults([]);
14475
+ form.setValue("counterpartyName", "");
14476
+ const typeLabel = newType === "ach" ? "ACH" : "Wire";
14477
+ sonner.toast.warning(
14478
+ `${counterpartyData.counterpartyName} doesn't support ${typeLabel} transactions. Please select a different counterparty.`
14479
+ );
14480
+ }
14481
+ }
14482
+ }
14483
+ };
14484
+ const handleCounterpartySelect = (result) => {
14485
+ form.setValue("counterpartyName", result.name);
14486
+ setShowCounterpartyDropdown(false);
14487
+ setCounterpartySearchResults([]);
14488
+ setIsCounterpartyLoading(true);
14489
+ setTimeout(() => {
14490
+ setCounterpartyData({
14491
+ counterpartyName: result.name,
14492
+ counterpartyId: result.id,
14493
+ counterpartyType: result.type,
14494
+ status: "Active",
14495
+ taxId: "XX-XXXXXXX",
14496
+ primaryContact: "Contact Name",
14497
+ contactEmail: "contact@example.com",
14498
+ contactPhone: "+1 (555) 123-4567",
14499
+ address: "123 Business Ave, City, ST 12345",
14500
+ paymentInstrumentType: result.paymentInstrumentType
14501
+ });
14502
+ setCounterpartyLookedUp(true);
14503
+ setIsCounterpartyLoading(false);
14504
+ sonner.toast.success("Counterparty selected");
14505
+ }, 500);
14259
14506
  };
14260
14507
  const handleEditAccount = () => {
14261
14508
  setAccountLookedUp(false);
@@ -14266,39 +14513,100 @@ function NewTransaction() {
14266
14513
  form.setValue("counterpartyName", "");
14267
14514
  form.setValue("amount", "");
14268
14515
  form.setValue("description", "");
14516
+ form.setValue("adjustmentDirection", "");
14517
+ form.setValue("adjustmentType", "");
14518
+ setReceiverAccountLookedUp(false);
14519
+ setReceiverAccountData(null);
14520
+ form.setValue("receiverAccountNumber", "");
14521
+ };
14522
+ const handleReceiverAccountLookup = async () => {
14523
+ const receiverNum = form.getValues("receiverAccountNumber");
14524
+ if (!receiverNum) {
14525
+ sonner.toast.error("Please enter a receiver account number");
14526
+ return;
14527
+ }
14528
+ setIsReceiverAccountLoading(true);
14529
+ try {
14530
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
14531
+ setReceiverAccountData({
14532
+ accountNumber: "****" + receiverNum.slice(-4),
14533
+ accountName: "Receiver Account",
14534
+ accountType: "Checking",
14535
+ balance: "$45,230.00",
14536
+ customerName: "Receiver Corp",
14537
+ customerId: "CUST-RCV-001",
14538
+ customerType: "Business"
14539
+ });
14540
+ setReceiverAccountLookedUp(true);
14541
+ sonner.toast.success("Receiver account found");
14542
+ } catch (error) {
14543
+ sonner.toast.error("Failed to lookup receiver account");
14544
+ } finally {
14545
+ setIsReceiverAccountLoading(false);
14546
+ }
14547
+ };
14548
+ const handleEditReceiverAccount = () => {
14549
+ setReceiverAccountLookedUp(false);
14550
+ setReceiverAccountData(null);
14551
+ form.setValue("receiverAccountNumber", "");
14269
14552
  };
14270
14553
  const handleEditCounterparty = () => {
14271
14554
  setCounterpartyLookedUp(false);
14272
14555
  setCounterpartyData(null);
14556
+ setCounterpartySearchResults([]);
14557
+ setShowCounterpartyDropdown(false);
14558
+ form.setValue("counterpartyName", "");
14273
14559
  form.setValue("amount", "");
14274
14560
  form.setValue("description", "");
14275
14561
  };
14276
- const handleSubmit = () => {
14562
+ const handleSubmit = async () => {
14277
14563
  const data = form.getValues();
14278
- if (!data.transactionType || !data.accountNumber || !data.counterpartyName || !data.amount) {
14564
+ const requiresCounterparty = ["ach", "wire"].includes(data.transactionType);
14565
+ if (!data.transactionType || !data.accountNumber || !data.amount) {
14279
14566
  sonner.toast.error("Please complete all required fields");
14280
14567
  return;
14281
14568
  }
14282
- if (!accountLookedUp || !counterpartyLookedUp) {
14283
- sonner.toast.error("Please lookup both account and counterparty");
14569
+ if (requiresCounterparty && (!data.counterpartyName || !counterpartyLookedUp)) {
14570
+ sonner.toast.error("Please lookup counterparty for this transaction type");
14284
14571
  return;
14285
14572
  }
14286
- const hasError = Math.random() > 0.7;
14287
- if (hasError) {
14288
- const errorScenarios = [
14289
- "Insufficient funds. Current balance: $125,450.00, Required: $" + parseFloat(data.amount).toFixed(2),
14290
- "Transaction limit exceeded. Daily limit: $50,000.00",
14291
- "Counterparty account is temporarily unavailable. Please try again later.",
14292
- "Invalid routing number for the selected transaction type."
14293
- ];
14294
- setSubmissionStatus("error");
14295
- setErrorMessage(errorScenarios[Math.floor(Math.random() * errorScenarios.length)]);
14296
- setConfirmationOpen(true);
14297
- } else {
14298
- const txId = "TXN-" + Math.random().toString(36).substr(2, 9).toUpperCase();
14299
- setTransactionId(txId);
14300
- setSubmissionStatus("success");
14573
+ if (!accountLookedUp) {
14574
+ sonner.toast.error("Please lookup account");
14575
+ return;
14576
+ }
14577
+ if (data.transactionType === "adjustment") {
14578
+ if (!data.adjustmentDirection || !data.adjustmentType) {
14579
+ sonner.toast.error("Please select direction and type for adjustment");
14580
+ return;
14581
+ }
14582
+ }
14583
+ if (data.transactionType === "transfer") {
14584
+ if (!data.receiverAccountNumber || !receiverAccountLookedUp) {
14585
+ sonner.toast.error("Please lookup receiver account for transfer");
14586
+ return;
14587
+ }
14588
+ }
14589
+ setIsSubmitting(true);
14590
+ try {
14591
+ await new Promise((resolve) => setTimeout(resolve, 1500));
14592
+ const hasError = Math.random() > 0.7;
14593
+ if (hasError) {
14594
+ const errorScenarios = [
14595
+ "Insufficient funds. Current balance: $125,450.00, Required: $" + parseFloat(data.amount).toFixed(2),
14596
+ "Transaction limit exceeded. Daily limit: $50,000.00",
14597
+ "Counterparty account is temporarily unavailable. Please try again later.",
14598
+ "Invalid routing number for the selected transaction type."
14599
+ ];
14600
+ setSubmissionStatus("error");
14601
+ setErrorMessage(errorScenarios[Math.floor(Math.random() * errorScenarios.length)]);
14602
+ } else {
14603
+ const txId = "TXN-" + Math.random().toString(36).substr(2, 9).toUpperCase();
14604
+ setTransactionId(txId);
14605
+ setSubmissionStatus("success");
14606
+ }
14301
14607
  setConfirmationOpen(true);
14608
+ } finally {
14609
+ setIsSubmitting(false);
14302
14610
  }
14303
14611
  };
14304
14612
  const handleConfirmationClose = () => {
@@ -14322,14 +14630,28 @@ function NewTransaction() {
14322
14630
  submissionStatus,
14323
14631
  errorMessage,
14324
14632
  transactionId,
14633
+ isAccountLoading,
14634
+ isCounterpartyLoading,
14635
+ isSubmitting,
14325
14636
  onAccountLookup: handleAccountLookup,
14326
- onCounterpartyLookup: handleCounterpartyLookup,
14327
14637
  onEditAccount: handleEditAccount,
14638
+ counterpartySearchResults,
14639
+ isCounterpartySearching,
14640
+ showCounterpartyDropdown,
14641
+ onCounterpartySearchChange: handleCounterpartySearchChange,
14642
+ onCounterpartySelect: handleCounterpartySelect,
14643
+ onCounterpartyDropdownClose: () => setShowCounterpartyDropdown(false),
14328
14644
  onEditCounterparty: handleEditCounterparty,
14645
+ onTransactionTypeChange: handleTransactionTypeChange,
14329
14646
  onSubmit: handleSubmit,
14330
14647
  onCancel: handleCancel,
14331
14648
  onConfirmationClose: handleConfirmationClose,
14332
- onConfirmationOpenChange: setConfirmationOpen
14649
+ onConfirmationOpenChange: setConfirmationOpen,
14650
+ receiverAccountLookedUp,
14651
+ receiverAccountData,
14652
+ isReceiverAccountLoading,
14653
+ onReceiverAccountLookup: handleReceiverAccountLookup,
14654
+ onEditReceiverAccount: handleEditReceiverAccount
14333
14655
  }
14334
14656
  );
14335
14657
  }
@@ -16366,6 +16688,8 @@ exports.ACHBankCard = ACHBankCard;
16366
16688
  exports.ACHBasicInfoCard = ACHBasicInfoCard;
16367
16689
  exports.ACHDetailsSection = ACHDetailsSection;
16368
16690
  exports.ACHTransferSection = ACHTransferSection;
16691
+ exports.ADJUSTMENT_DIRECTION_OPTIONS = ADJUSTMENT_DIRECTION_OPTIONS;
16692
+ exports.ADJUSTMENT_TYPE_OPTIONS = ADJUSTMENT_TYPE_OPTIONS;
16369
16693
  exports.AccountCard = AccountCard;
16370
16694
  exports.AccountDetail = AccountDetail_default;
16371
16695
  exports.Accounts = Accounts_default;
@@ -16396,7 +16720,6 @@ exports.BusinessTypeBadge = BusinessTypeBadge;
16396
16720
  exports.Businesses = Businesses_default;
16397
16721
  exports.Button = Button;
16398
16722
  exports.CIPStatusBadge = CIPStatusBadge;
16399
- exports.CURRENCY_OPTIONS = CURRENCY_OPTIONS;
16400
16723
  exports.Calendar = Calendar;
16401
16724
  exports.Card = Card;
16402
16725
  exports.CardContent = CardContent;