@ixo/editor 5.19.0 → 5.19.1

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.
@@ -32460,6 +32460,7 @@ function emptyPaymentRowFields() {
32460
32460
  accountName: "",
32461
32461
  accountNumber: "",
32462
32462
  accountType: "",
32463
+ bankName: "",
32463
32464
  networkId: "",
32464
32465
  country: "",
32465
32466
  bvn: "",
@@ -32483,7 +32484,9 @@ function emptyPaymentSender() {
32483
32484
  address: "",
32484
32485
  dob: "",
32485
32486
  idType: "",
32486
- idNumber: ""
32487
+ idNumber: "",
32488
+ additionalIdType: "",
32489
+ additionalIdNumber: ""
32487
32490
  };
32488
32491
  }
32489
32492
  function emptyPaymentFieldTemplate() {
@@ -32491,6 +32494,7 @@ function emptyPaymentFieldTemplate() {
32491
32494
  accountName: "",
32492
32495
  accountNumber: "",
32493
32496
  accountType: "",
32497
+ bankName: "",
32494
32498
  networkId: "",
32495
32499
  country: "",
32496
32500
  bvn: "",
@@ -32506,9 +32510,11 @@ var DEFAULT_REQUIRED_FIELDS = [
32506
32510
  "accountName",
32507
32511
  "accountNumber",
32508
32512
  "accountType",
32513
+ "bankName",
32509
32514
  "country",
32510
32515
  "amount",
32511
- "currency"
32516
+ "currency",
32517
+ "recipientDid"
32512
32518
  ];
32513
32519
  function emptyPaymentInputs() {
32514
32520
  return {
@@ -32552,7 +32558,9 @@ function parsePaymentInputs(json) {
32552
32558
  address: asString(parsed.sender?.address),
32553
32559
  dob: asString(parsed.sender?.dob),
32554
32560
  idType: asString(parsed.sender?.idType),
32555
- idNumber: asString(parsed.sender?.idNumber)
32561
+ idNumber: asString(parsed.sender?.idNumber),
32562
+ additionalIdType: asString(parsed.sender?.additionalIdType),
32563
+ additionalIdNumber: asString(parsed.sender?.additionalIdNumber)
32556
32564
  },
32557
32565
  defaultReason: asString(parsed.defaultReason, "other"),
32558
32566
  customerType: asString(parsed.customerType, "retail"),
@@ -32560,6 +32568,7 @@ function parsePaymentInputs(json) {
32560
32568
  accountName: asString(parsed.fieldTemplate?.accountName),
32561
32569
  accountNumber: asString(parsed.fieldTemplate?.accountNumber),
32562
32570
  accountType: asString(parsed.fieldTemplate?.accountType),
32571
+ bankName: asString(parsed.fieldTemplate?.bankName),
32563
32572
  networkId: asString(parsed.fieldTemplate?.networkId),
32564
32573
  country: asString(parsed.fieldTemplate?.country),
32565
32574
  bvn: asString(parsed.fieldTemplate?.bvn),
@@ -32589,21 +32598,31 @@ function parsePaymentInputs(json) {
32589
32598
  // intent. If a flow needs the old behaviour, surface it on the row UI
32590
32599
  // (e.g. ban empty networkId at propose time inside the action def
32591
32600
  // itself, not via requiredFields). For now no flow needs that.
32592
- requiredFields: Array.isArray(parsed.requiredFields) ? parsed.requiredFields.filter(
32593
- (f) => typeof f === "string" && // Drop the oracle-resolved fields from any persisted list.
32594
- f !== "networkId" && f !== "channelId" && [
32595
- "accountName",
32596
- "accountNumber",
32597
- "accountType",
32598
- "country",
32599
- "bvn",
32600
- "amount",
32601
- "currency",
32602
- "reason",
32603
- "recipientDid",
32604
- "outcomeCurrency"
32605
- ].includes(f)
32606
- ) : [...DEFAULT_REQUIRED_FIELDS]
32601
+ requiredFields: (() => {
32602
+ if (!Array.isArray(parsed.requiredFields)) {
32603
+ return [...DEFAULT_REQUIRED_FIELDS];
32604
+ }
32605
+ const cleaned = parsed.requiredFields.filter(
32606
+ (f) => typeof f === "string" && // Drop the oracle-resolved fields from any persisted list.
32607
+ f !== "networkId" && f !== "channelId" && [
32608
+ "accountName",
32609
+ "accountNumber",
32610
+ "accountType",
32611
+ "bankName",
32612
+ "country",
32613
+ "bvn",
32614
+ "amount",
32615
+ "currency",
32616
+ "reason",
32617
+ "recipientDid",
32618
+ "outcomeCurrency"
32619
+ ].includes(f)
32620
+ );
32621
+ if (!cleaned.includes("recipientDid")) {
32622
+ cleaned.push("recipientDid");
32623
+ }
32624
+ return cleaned;
32625
+ })()
32607
32626
  };
32608
32627
  }
32609
32628
  function serializePaymentInputs(inputs) {
@@ -32636,6 +32655,7 @@ function parsePaymentRows(raw) {
32636
32655
  accountName: asString(entry.fields?.accountName),
32637
32656
  accountNumber: asString(entry.fields?.accountNumber),
32638
32657
  accountType: asString(entry.fields?.accountType),
32658
+ bankName: asString(entry.fields?.bankName),
32639
32659
  networkId: asString(entry.fields?.networkId),
32640
32660
  country: asString(entry.fields?.country),
32641
32661
  bvn: asString(entry.fields?.bvn),
@@ -32692,6 +32712,10 @@ var FIELD_LABEL = {
32692
32712
  label: "Account type",
32693
32713
  hint: '"bank" or "momo" \u2014 usually fixed per flow, not from claim'
32694
32714
  },
32715
+ bankName: {
32716
+ label: "Recipient bank name (required)",
32717
+ hint: "e.g. {{claim.surveyAnswers.umuzi:bankName}} \u2014 must match a YellowCard network name (Capitec Bank, FNB, MTN, \u2026). The oracle resolves this to a networkId at propose time. WRONG-bank routes funds to the wrong clearing system, so this MUST be accurate."
32718
+ },
32695
32719
  networkId: {
32696
32720
  label: "Network / bank UUID (optional)",
32697
32721
  hint: "Leave empty \u2014 the oracle resolves the network UUID at propose time via the worker's `/channels` discovery. Only set this if you want to pin a specific bank."
@@ -32721,8 +32745,8 @@ var FIELD_LABEL = {
32721
32745
  hint: "Falls back to block-level Default Reason when empty"
32722
32746
  },
32723
32747
  recipientDid: {
32724
- label: "Recipient DID (optional)",
32725
- hint: "e.g. {{claim.agentDid}} \u2014 falls back to invoker DID server-side"
32748
+ label: "Recipient DID (required)",
32749
+ hint: "e.g. {{claim.agentDid}} \u2014 DID of the person being paid out to. Worker uses this as YC customerUID for per-user KYC tracking. NEVER falls back to invoker \u2014 that would attribute the payout to the operator, not the actual recipient."
32726
32750
  },
32727
32751
  outcomeCurrency: {
32728
32752
  label: "Outcome currency",
@@ -32733,6 +32757,7 @@ var REQUIRED_FIELD_OPTIONS = [
32733
32757
  { value: "accountName", label: "Recipient account name" },
32734
32758
  { value: "accountNumber", label: "Recipient account number" },
32735
32759
  { value: "accountType", label: "Account type" },
32760
+ { value: "bankName", label: "Bank name" },
32736
32761
  { value: "country", label: "Country" },
32737
32762
  { value: "bvn", label: "BVN" },
32738
32763
  { value: "amount", label: "Amount" },
@@ -32928,6 +32953,7 @@ function resolvePaymentRowFields(fieldTemplate, editorDocument, scope) {
32928
32953
  accountName: r(fieldTemplate.accountName),
32929
32954
  accountNumber: r(fieldTemplate.accountNumber),
32930
32955
  accountType: r(fieldTemplate.accountType),
32956
+ bankName: r(fieldTemplate.bankName),
32931
32957
  networkId: r(fieldTemplate.networkId),
32932
32958
  country: r(fieldTemplate.country),
32933
32959
  bvn: r(fieldTemplate.bvn),
@@ -33530,7 +33556,8 @@ var PaymentFlowDetail = ({
33530
33556
  }, [block, chainClaims, checkedClaimIds, editor, parsed.fieldTemplate]);
33531
33557
  const [setupOpen, setSetupOpen] = useState140(() => {
33532
33558
  const initial = parsePaymentInputs(inputs);
33533
- return !initial.workerBaseUrl.trim() || !initial.sender.name.trim() || !initial.sender.country.trim();
33559
+ const initialIsNG = initial.sender.country.trim().toUpperCase() === "NG";
33560
+ return !initial.workerBaseUrl.trim() || !initial.sender.name.trim() || !initial.sender.country.trim() || initialIsNG && (!initial.sender.idNumber.trim() || !initial.sender.additionalIdNumber.trim());
33534
33561
  });
33535
33562
  const [submitting, setSubmitting] = useState140(false);
33536
33563
  const [error, setError] = useState140(null);
@@ -33582,6 +33609,9 @@ var PaymentFlowDetail = ({
33582
33609
  if (!parsed.sender.name.trim() || !parsed.sender.country.trim()) {
33583
33610
  return "Sender name and country are required. Open Payout setup above and fill them in.";
33584
33611
  }
33612
+ if (parsed.sender.country.trim().toUpperCase() === "NG" && (!parsed.sender.idNumber.trim() || !parsed.sender.additionalIdNumber.trim())) {
33613
+ return "NG senders must supply both NIN (idNumber) and BVN (additionalIdNumber). Open Payout setup above and fill them in \u2014 the worker auto-stamps the type fields.";
33614
+ }
33585
33615
  if (oracleResolving) return "Resolving the oracle DID \u2014 try again in a moment.";
33586
33616
  if (!oracleDid) return "Cannot determine the chat oracle DID.";
33587
33617
  if (!selectedDelegationCid) return "Select a UCAN delegation (or create one).";
@@ -33602,6 +33632,8 @@ var PaymentFlowDetail = ({
33602
33632
  effectiveWorkerBaseUrl,
33603
33633
  parsed.sender.name,
33604
33634
  parsed.sender.country,
33635
+ parsed.sender.idNumber,
33636
+ parsed.sender.additionalIdNumber,
33605
33637
  oracleDid,
33606
33638
  oracleResolving,
33607
33639
  selectedDelegationCid,
@@ -33826,7 +33858,8 @@ var PaymentFlowDetail = ({
33826
33858
  }
33827
33859
  const oracleUnavailable = !oracleResolving && !oracleDid;
33828
33860
  const workerUrlMissing = !effectiveWorkerBaseUrl;
33829
- const senderIncomplete = !parsed.sender.name.trim() || !parsed.sender.country.trim();
33861
+ const senderIsNG = parsed.sender.country.trim().toUpperCase() === "NG";
33862
+ const senderIncomplete = !parsed.sender.name.trim() || !parsed.sender.country.trim() || senderIsNG && (!parsed.sender.idNumber.trim() || !parsed.sender.additionalIdNumber.trim());
33830
33863
  const setupIncomplete = workerUrlMissing || senderIncomplete;
33831
33864
  const noUsableDelegation = usableDelegations.length === 0;
33832
33865
  const delegationNotSelected = !selectedDelegationCid;
@@ -33885,7 +33918,7 @@ var PaymentFlowDetail = ({
33885
33918
  onChange: (e) => patchInputs({ workerBaseUrl: e.currentTarget.value }),
33886
33919
  error: workerUrlMissing ? "Required" : void 0
33887
33920
  }
33888
- ), /* @__PURE__ */ React289.createElement(Divider26, { variant: "dashed", my: 4 }), /* @__PURE__ */ React289.createElement(Text181, { size: "xs", fw: 600, c: "dimmed" }, "Sender (organisation paying out)"), /* @__PURE__ */ React289.createElement(Text181, { size: "xs", c: "dimmed" }, "These details go with every row you propose. YellowCard requires full KYC (address, dob, idType, idNumber) once cumulative payments per recipient cross $200 USD \u2014 set them now to avoid mid-batch rejections."), /* @__PURE__ */ React289.createElement(Group112, { grow: true }, /* @__PURE__ */ React289.createElement(
33921
+ ), /* @__PURE__ */ React289.createElement(Divider26, { variant: "dashed", my: 4 }), /* @__PURE__ */ React289.createElement(Text181, { size: "xs", fw: 600, c: "dimmed" }, "Sender (organisation paying out)"), /* @__PURE__ */ React289.createElement(Text181, { size: "xs", c: "dimmed" }, "These details go with every row you propose. YellowCard requires full KYC (address, dob, idType, idNumber) once cumulative payments per recipient cross $200 USD \u2014 set them now to avoid mid-batch rejections. NG senders additionally need NIN + BVN (extra fields appear when Country is set to NG)."), /* @__PURE__ */ React289.createElement(Group112, { grow: true }, /* @__PURE__ */ React289.createElement(
33889
33922
  TextInput10,
33890
33923
  {
33891
33924
  size: "xs",
@@ -33937,7 +33970,16 @@ var PaymentFlowDetail = ({
33937
33970
  value: parsed.sender.dob,
33938
33971
  onChange: (e) => patchSender({ dob: e.currentTarget.value })
33939
33972
  }
33940
- ), /* @__PURE__ */ React289.createElement(
33973
+ ), parsed.sender.country.trim().toUpperCase() === "NG" ? /* @__PURE__ */ React289.createElement(
33974
+ TextInput10,
33975
+ {
33976
+ size: "xs",
33977
+ label: "ID type",
33978
+ value: "NIN",
33979
+ readOnly: true,
33980
+ description: "Auto-set for NG senders"
33981
+ }
33982
+ ) : /* @__PURE__ */ React289.createElement(
33941
33983
  TextInput10,
33942
33984
  {
33943
33985
  size: "xs",
@@ -33950,9 +33992,21 @@ var PaymentFlowDetail = ({
33950
33992
  TextInput10,
33951
33993
  {
33952
33994
  size: "xs",
33953
- label: "ID number",
33995
+ label: parsed.sender.country.trim().toUpperCase() === "NG" ? "NIN (National Identification Number)" : "ID number",
33954
33996
  value: parsed.sender.idNumber,
33955
- onChange: (e) => patchSender({ idNumber: e.currentTarget.value })
33997
+ onChange: (e) => patchSender({ idNumber: e.currentTarget.value }),
33998
+ error: parsed.sender.country.trim().toUpperCase() === "NG" && !parsed.sender.idNumber.trim() ? "Required for NG" : void 0
33999
+ }
34000
+ )), parsed.sender.country.trim().toUpperCase() === "NG" && /* @__PURE__ */ React289.createElement(React289.Fragment, null, /* @__PURE__ */ React289.createElement(Text181, { size: "xs", c: "dimmed" }, "YellowCard requires NG senders to supply both NIN and BVN. The ID type is fixed by regulation \u2014 only fill in the BVN number below."), /* @__PURE__ */ React289.createElement(
34001
+ TextInput10,
34002
+ {
34003
+ size: "xs",
34004
+ label: "BVN (Bank Verification Number)",
34005
+ value: parsed.sender.additionalIdNumber,
34006
+ onChange: (e) => patchSender({
34007
+ additionalIdNumber: e.currentTarget.value
34008
+ }),
34009
+ error: !parsed.sender.additionalIdNumber.trim() ? "Required for NG" : void 0
33956
34010
  }
33957
34011
  ))))), /* @__PURE__ */ React289.createElement(Divider26, null), /* @__PURE__ */ React289.createElement(Stack206, { gap: "xs" }, /* @__PURE__ */ React289.createElement(Group112, { justify: "space-between", align: "flex-end" }, /* @__PURE__ */ React289.createElement(Stack206, { gap: 2, style: { flex: 1 } }, /* @__PURE__ */ React289.createElement(Text181, { size: "xs", fw: 600, c: "dimmed" }, "UCAN Authorization"), /* @__PURE__ */ React289.createElement(Text181, { size: "xs", c: "dimmed" }, "Sign once \u2014 the oracle mints per-call invocations against the worker for every row.")), /* @__PURE__ */ React289.createElement(
33958
34012
  Button62,
@@ -34200,10 +34254,16 @@ var FIELD_DISPLAY = [
34200
34254
  { key: "accountName", label: "Recipient account name" },
34201
34255
  { key: "accountNumber", label: "Account number" },
34202
34256
  { key: "accountType", label: "Account type", placeholder: "bank or momo" },
34257
+ {
34258
+ key: "bankName",
34259
+ label: "Bank name (required)",
34260
+ placeholder: "e.g. Capitec Bank, FNB, MTN",
34261
+ description: "Must match a YellowCard network name for the recipient's country. The oracle resolves this to a networkId \u2014 a wrong bank routes funds to the wrong clearing system."
34262
+ },
34203
34263
  {
34204
34264
  key: "networkId",
34205
- label: "Network / bank UUID (optional)",
34206
- description: "Leave empty \u2014 oracle resolves via /channels discovery."
34265
+ label: "Network / bank UUID (optional override)",
34266
+ description: "Leave empty \u2014 oracle resolves via /channels discovery using Bank name. Only set to override resolution."
34207
34267
  },
34208
34268
  { key: "country", label: "Country (ISO 3166-1 alpha-2)" },
34209
34269
  { key: "bvn", label: "BVN (NG, optional)" },
@@ -34225,7 +34285,11 @@ var FIELD_DISPLAY = [
34225
34285
  description: "Local currency the recipient receives \u2014 never USD."
34226
34286
  },
34227
34287
  { key: "reason", label: "Reason (optional)" },
34228
- { key: "recipientDid", label: "Recipient DID (optional)" }
34288
+ {
34289
+ key: "recipientDid",
34290
+ label: "Recipient DID (required)",
34291
+ description: "DID of the person being paid out to \u2014 used as YC customerUID for per-user KYC tracking. NEVER inferred from the operator: a missing value fails the row at propose time."
34292
+ }
34229
34293
  ];
34230
34294
  var PaymentRowDetail = ({
34231
34295
  row,
@@ -47523,4 +47587,4 @@ export {
47523
47587
  getExtraSlashMenuItems,
47524
47588
  useCreateIxoEditor
47525
47589
  };
47526
- //# sourceMappingURL=chunk-TZBRXBBJ.mjs.map
47590
+ //# sourceMappingURL=chunk-HDQKWNUR.mjs.map