@miden-npm/react 0.1.0 → 1.0.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.
package/dist/index.js CHANGED
@@ -71,10 +71,18 @@ var checkObjectTruthy = (obj) => {
71
71
  if (obj == null || typeof obj !== "object") return false;
72
72
  return Object.values(obj).every(Boolean);
73
73
  };
74
+ var getQueryParams = (url) => {
75
+ const params = {};
76
+ const searchParams = new URL(url).searchParams;
77
+ searchParams.forEach((value, key) => {
78
+ params[key] = value;
79
+ });
80
+ return params;
81
+ };
74
82
 
75
83
  // src/utils/api.util.ts
76
84
  var getBaseUrl = (mode) => {
77
- return mode === "sandbox" ? "https://sandbox-api.midencards.io/payment-gateway-api" : "";
85
+ return mode === "sandbox" ? "https://sandbox-api.buzapay.com/payment-gateway-api" : "";
78
86
  };
79
87
 
80
88
  // src/utils/string.util.ts
@@ -126,6 +134,246 @@ var restrictToNumericKeys = (event) => {
126
134
  }
127
135
  };
128
136
 
137
+ // src/utils/error.util.ts
138
+ var validateRegex = (value, regex) => regex.test(value);
139
+ function parseRules(rules) {
140
+ if (!rules) return [];
141
+ return rules.split("|").map((chunk) => {
142
+ const [rule, val] = chunk.split(":");
143
+ return { rule, value: val };
144
+ });
145
+ }
146
+ function getValidationErrorMessage(rulesStr, inputValue, label) {
147
+ const errors = [];
148
+ const rules = parseRules(rulesStr);
149
+ const lowerLabel = (label || "This field").toLowerCase();
150
+ const v = inputValue ?? "";
151
+ const num = Number(v);
152
+ const hasNum = !Number.isNaN(num);
153
+ for (const r of rules) {
154
+ switch (r.rule) {
155
+ case "required":
156
+ if (!v) errors.push(`The ${lowerLabel} field is required`);
157
+ break;
158
+ case "alpha":
159
+ if (!validateRegex(v, /^[a-zA-Z]+$/))
160
+ errors.push(
161
+ `The ${lowerLabel} field must only contain alphabetic characters`
162
+ );
163
+ break;
164
+ case "at_least_one_uppercase":
165
+ if (!validateRegex(v, /.*[A-Z].*/))
166
+ errors.push(
167
+ `The ${lowerLabel} field must contain at least one uppercase character`
168
+ );
169
+ break;
170
+ case "at_least_one_lowercase":
171
+ if (!validateRegex(v, /.*[a-z].*/))
172
+ errors.push(
173
+ `The ${lowerLabel} field must contain at least one lowercase character`
174
+ );
175
+ break;
176
+ case "at_least_one_number":
177
+ if (!validateRegex(v, /.*\d.*/))
178
+ errors.push(
179
+ `The ${lowerLabel} field must contain at least one number`
180
+ );
181
+ break;
182
+ case "alpha_num":
183
+ if (!validateRegex(v, /^[a-z0-9]+$/i))
184
+ errors.push(
185
+ `The ${lowerLabel} field must only contain alphabetic characters and numbers`
186
+ );
187
+ break;
188
+ case "num_spaces":
189
+ if (!validateRegex(v, /^[0-9\s]+$/i))
190
+ errors.push(
191
+ `The ${lowerLabel} field must only contain space and numbers`
192
+ );
193
+ break;
194
+ case "alpha_spaces":
195
+ if (!validateRegex(v, /^[A-Za-z\s]*$/))
196
+ errors.push(
197
+ `The ${lowerLabel} field must only contain alphabetic characters and spaces`
198
+ );
199
+ break;
200
+ case "numeric":
201
+ if (!validateRegex(v, /^\d+$/))
202
+ errors.push(`The ${lowerLabel} field must only contain numbers`);
203
+ break;
204
+ case "no_special":
205
+ if (validateRegex(v, /[^a-zA-Z0-9\s]/))
206
+ errors.push(
207
+ `The ${lowerLabel} field must not contain special characters`
208
+ );
209
+ break;
210
+ case "at_least_one_special":
211
+ if (!validateRegex(v, /[^a-zA-Z0-9\s]/))
212
+ errors.push(
213
+ `The ${lowerLabel} field must contain at least one special character`
214
+ );
215
+ break;
216
+ case "email":
217
+ if (!validateRegex(v, /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,})+$/)) {
218
+ errors.push("Please enter a valid email address");
219
+ }
220
+ break;
221
+ case "is":
222
+ if (r.value !== v) errors.push(`Value entered must be ${r.value}`);
223
+ break;
224
+ case "is_not":
225
+ if (r.value === v) errors.push(`Value entered must not be ${r.value}`);
226
+ break;
227
+ case "char_length":
228
+ if (v.length !== Number(r.value))
229
+ errors.push(
230
+ `The ${lowerLabel} field must be ${r.value} characters long`
231
+ );
232
+ break;
233
+ case "min_char_length":
234
+ if (v.length < Number(r.value))
235
+ errors.push(
236
+ `The ${lowerLabel} field must not be less than ${r.value} characters long`
237
+ );
238
+ break;
239
+ case "max_char_length":
240
+ if (v.length > Number(r.value))
241
+ errors.push(
242
+ `The ${lowerLabel} field must not be greater than ${r.value} characters long`
243
+ );
244
+ break;
245
+ // Age rules treat the value as a number (strict numeric compare)
246
+ case "age":
247
+ if (!hasNum || num !== Number(r.value))
248
+ errors.push(`Age entered must be ${r.value}`);
249
+ break;
250
+ case "min_age":
251
+ if (!hasNum || num < Number(r.value))
252
+ errors.push(`Age entered must not be less than ${r.value}`);
253
+ break;
254
+ case "max_age":
255
+ if (!hasNum || num > Number(r.value))
256
+ errors.push(`Age entered must not be greater than ${r.value}`);
257
+ break;
258
+ // Numeric value rules (general numbers)
259
+ case "num_is":
260
+ if (!hasNum || num !== Number(r.value))
261
+ errors.push(`Number entered must be ${r.value}`);
262
+ break;
263
+ case "num_is_not":
264
+ if (hasNum && num === Number(r.value))
265
+ errors.push(`Number entered must not be ${r.value}`);
266
+ break;
267
+ case "min_number":
268
+ if (!hasNum || num < Number(r.value))
269
+ errors.push(`Number entered must not be less than ${r.value}`);
270
+ break;
271
+ case "max_number":
272
+ if (!hasNum || num > Number(r.value))
273
+ errors.push(`Number entered must not be greater than ${r.value}`);
274
+ break;
275
+ default:
276
+ break;
277
+ }
278
+ }
279
+ return errors.length > 0 ? errors[0] : null;
280
+ }
281
+ var validateGroup = (values, rulesMap, prettyLabels) => {
282
+ const out = {};
283
+ for (const [field, rules] of Object.entries(rulesMap)) {
284
+ if (!rules) continue;
285
+ const label = prettyLabels?.[field] ?? field;
286
+ const err = getValidationErrorMessage(rules, values[field] ?? "", label);
287
+ if (err) out[field] = err;
288
+ }
289
+ return out;
290
+ };
291
+
292
+ // src/utils/card-scheme.util.ts
293
+ var CardSchemes = /* @__PURE__ */ ((CardSchemes2) => {
294
+ CardSchemes2[CardSchemes2["Visa"] = 1] = "Visa";
295
+ CardSchemes2[CardSchemes2["MasterCard"] = 2] = "MasterCard";
296
+ CardSchemes2[CardSchemes2["Verve"] = 3] = "Verve";
297
+ CardSchemes2[CardSchemes2["MastercardAndVisa"] = 4] = "MastercardAndVisa";
298
+ CardSchemes2[CardSchemes2["AmericanExpress"] = 5] = "AmericanExpress";
299
+ CardSchemes2[CardSchemes2["Discover"] = 6] = "Discover";
300
+ CardSchemes2[CardSchemes2["JCB"] = 7] = "JCB";
301
+ CardSchemes2[CardSchemes2["DinersClub"] = 8] = "DinersClub";
302
+ CardSchemes2[CardSchemes2["Maestro"] = 9] = "Maestro";
303
+ CardSchemes2[CardSchemes2["UnionPay"] = 10] = "UnionPay";
304
+ CardSchemes2[CardSchemes2["UnionPay3DS"] = 11] = "UnionPay3DS";
305
+ CardSchemes2[CardSchemes2["UnionPayNon3DS"] = 12] = "UnionPayNon3DS";
306
+ CardSchemes2[CardSchemes2["UATP"] = 13] = "UATP";
307
+ CardSchemes2[CardSchemes2["PayPak"] = 14] = "PayPak";
308
+ CardSchemes2[CardSchemes2["Jaywan"] = 15] = "Jaywan";
309
+ CardSchemes2[CardSchemes2["Mada"] = 16] = "Mada";
310
+ CardSchemes2[CardSchemes2["MadaVisa"] = 17] = "MadaVisa";
311
+ CardSchemes2[CardSchemes2["MadaMastercard"] = 18] = "MadaMastercard";
312
+ CardSchemes2[CardSchemes2["Unknown"] = 19] = "Unknown";
313
+ return CardSchemes2;
314
+ })(CardSchemes || {});
315
+ var VISA_RE = /^4\d{12}(\d{3}){0,2}$/;
316
+ var MC_RE = /^(?:5[1-5]\d{14}|2(?:2(?:2[1-9]|[3-9]\d)|[3-6]\d{2}|7(?:[01]\d|20))\d{12})(?:\d{0,3})?$/;
317
+ var AMEX_RE = /^(34|37)\d{13}$/;
318
+ var DISCOVER_RE = /^(?:6011|65|64[4-9]|622(?:12[6-9]|1[3-9]\d|[2-8]\d{2}|9(?:0\d|1\d|2[0-5])))\d{12,15}$/;
319
+ var JCB_RE = /^(?:35(?:2[8-9]|[3-8]\d))\d{12,15}$/;
320
+ var DINERS_RE = /^(?:3(?:0[0-5]\d|095|6\d|[89]\d))\d{11,13}$/;
321
+ var MAESTRO_RE = /^(?:50|5[6-9]|6[0-9])\d{10,17}$/;
322
+ var UNIONPAY_RE = /^62\d{14,17}$/;
323
+ var UATP_RE = /^1\d{14}$/;
324
+ var VERVE_BIN6_RANGES = [
325
+ [506099, 506198],
326
+ [650002, 650027]
327
+ ];
328
+ var VERVE_BIN6_SINGLES = /* @__PURE__ */ new Set([507865, 507866]);
329
+ var PAYPAK_BIN6 = /* @__PURE__ */ new Set([220545, 220543]);
330
+ var JAYWAN_BIN7 = /* @__PURE__ */ new Set([6690109]);
331
+ var MADA_ONLY_BIN6 = /* @__PURE__ */ new Set([968209, 873646]);
332
+ var MADA_VISA_BIN6 = /* @__PURE__ */ new Set([422818, 486094]);
333
+ var MADA_MC_BIN6 = /* @__PURE__ */ new Set([529741, 543357]);
334
+ var UNIONPAY_3DS_BIN6 = /* @__PURE__ */ new Set([620108]);
335
+ var UNIONPAY_NON3DS_BIN6 = /* @__PURE__ */ new Set([621423]);
336
+ function cardTypeHandler(cardNumber) {
337
+ const scheme = detect(cardNumber);
338
+ return CardSchemes[scheme];
339
+ }
340
+ function detect(cardNumber) {
341
+ if (!cardNumber || !cardNumber.trim()) return 19 /* Unknown */;
342
+ const digits = cardNumber.replace(/\D/g, "");
343
+ if (digits.length < 12 || digits.length > 19) return 19 /* Unknown */;
344
+ if (digits.length >= 6) {
345
+ const bin6 = parseInt(digits.slice(0, 6), 10);
346
+ if (MADA_ONLY_BIN6.has(bin6) && digits.length >= 16 && digits.length <= 19)
347
+ return 16 /* Mada */;
348
+ if (MADA_VISA_BIN6.has(bin6) && VISA_RE.test(digits)) return 17 /* MadaVisa */;
349
+ if (MADA_MC_BIN6.has(bin6) && MC_RE.test(digits)) return 18 /* MadaMastercard */;
350
+ if (PAYPAK_BIN6.has(bin6) && digits.length === 16) return 14 /* PayPak */;
351
+ if (UNIONPAY_3DS_BIN6.has(bin6) && UNIONPAY_RE.test(digits)) return 11 /* UnionPay3DS */;
352
+ if (UNIONPAY_NON3DS_BIN6.has(bin6) && UNIONPAY_RE.test(digits))
353
+ return 12 /* UnionPayNon3DS */;
354
+ if (isVerve(bin6, digits.length)) return 3 /* Verve */;
355
+ }
356
+ if (digits.length >= 7) {
357
+ const bin7 = parseInt(digits.slice(0, 7), 10);
358
+ if (JAYWAN_BIN7.has(bin7) && digits.length === 16) return 15 /* Jaywan */;
359
+ }
360
+ if (UATP_RE.test(digits)) return 13 /* UATP */;
361
+ if (AMEX_RE.test(digits)) return 5 /* AmericanExpress */;
362
+ if (DISCOVER_RE.test(digits)) return 6 /* Discover */;
363
+ if (JCB_RE.test(digits)) return 7 /* JCB */;
364
+ if (DINERS_RE.test(digits)) return 8 /* DinersClub */;
365
+ if (MC_RE.test(digits)) return 2 /* MasterCard */;
366
+ if (VISA_RE.test(digits)) return 1 /* Visa */;
367
+ if (UNIONPAY_RE.test(digits)) return 10 /* UnionPay */;
368
+ if (MAESTRO_RE.test(digits)) return 9 /* Maestro */;
369
+ return 19 /* Unknown */;
370
+ }
371
+ function isVerve(bin6, length) {
372
+ if (length < 16 || length > 19) return false;
373
+ const inRange = VERVE_BIN6_RANGES.some(([start, end]) => bin6 >= start && bin6 <= end);
374
+ return inRange || VERVE_BIN6_SINGLES.has(bin6);
375
+ }
376
+
129
377
  // src/apis/checkout.api.ts
130
378
  async function createPaymentLink(paymentObject, environment, secretKey) {
131
379
  try {
@@ -139,7 +387,189 @@ async function createPaymentLink(paymentObject, environment, secretKey) {
139
387
  Accept: "application/json",
140
388
  merchantId: secretKey
141
389
  },
142
- body: JSON.stringify(paymentObject)
390
+ body: JSON.stringify({
391
+ ...paymentObject,
392
+ LinkName: `${Date.now()}-Link`
393
+ })
394
+ }
395
+ );
396
+ return await res.json();
397
+ } catch (error) {
398
+ }
399
+ }
400
+ async function authorizeCardPayment(environment, { merchantId, ...rest }) {
401
+ try {
402
+ const baseUrl = getBaseUrl(environment);
403
+ const res = await fetch(
404
+ `${baseUrl}/api/v1/checkout/authorize-card-3ds-payment-sdk`,
405
+ {
406
+ method: "POST",
407
+ headers: {
408
+ "Content-Type": "application/json",
409
+ Accept: "application/json",
410
+ merchantId
411
+ },
412
+ body: JSON.stringify(rest)
413
+ }
414
+ );
415
+ return await res.json();
416
+ } catch (error) {
417
+ }
418
+ }
419
+ async function getPaymentReferenceDetails(environment, paymentReference) {
420
+ try {
421
+ const baseUrl = getBaseUrl(environment);
422
+ const res = await fetch(
423
+ `${baseUrl}/api/v1/checkout/details/${paymentReference}`,
424
+ {
425
+ method: "GET",
426
+ headers: {
427
+ "Content-Type": "application/json",
428
+ Accept: "application/json"
429
+ }
430
+ }
431
+ );
432
+ return await res.json();
433
+ } catch (error) {
434
+ }
435
+ }
436
+ async function generatePaymentAccount(environment, { merchantId, ...rest }) {
437
+ try {
438
+ const baseUrl = getBaseUrl(environment);
439
+ const res = await fetch(
440
+ `${baseUrl}/api/v1/checkout/generate-payment-account`,
441
+ {
442
+ method: "POST",
443
+ headers: {
444
+ "Content-Type": "application/json",
445
+ Accept: "application/json",
446
+ merchantId
447
+ },
448
+ body: JSON.stringify(rest)
449
+ }
450
+ );
451
+ return await res.json();
452
+ } catch (error) {
453
+ }
454
+ }
455
+ async function generateStableCoinAddress(environment, { merchantId, ...rest }) {
456
+ try {
457
+ const baseUrl = getBaseUrl(environment);
458
+ const res = await fetch(
459
+ `${baseUrl}/api/v1/checkout/generate-payment-walletaddress`,
460
+ {
461
+ method: "POST",
462
+ headers: {
463
+ "Content-Type": "application/json",
464
+ Accept: "application/json",
465
+ merchantId
466
+ },
467
+ body: JSON.stringify(rest)
468
+ }
469
+ );
470
+ return await res.json();
471
+ } catch (error) {
472
+ }
473
+ }
474
+
475
+ // src/apis/encrypt.api.ts
476
+ import CryptoJS from "crypto-js";
477
+ function encryptPayload(merchantId, formData = {}) {
478
+ const merchId = merchantId.replace(/-/g, "");
479
+ const first16Key = merchId.slice(0, 16);
480
+ const last16Iv = merchId.slice(-16);
481
+ const key = CryptoJS.enc.Utf8.parse(first16Key);
482
+ const iv = CryptoJS.enc.Utf8.parse(last16Iv);
483
+ const postDataObj = JSON.stringify(formData);
484
+ const encryptedData = CryptoJS.AES.encrypt(
485
+ CryptoJS.enc.Utf8.parse(postDataObj),
486
+ key,
487
+ {
488
+ keySize: 128 / 8,
489
+ iv,
490
+ mode: CryptoJS.mode.CBC,
491
+ padding: CryptoJS.pad.Pkcs7
492
+ }
493
+ );
494
+ return {
495
+ requestParam: encryptedData.toString()
496
+ };
497
+ }
498
+ function decryptPayload(merchantId, payload) {
499
+ const merchId = merchantId.replace(/-/g, "");
500
+ const first16Key = merchId.slice(0, 16);
501
+ const last16Iv = merchId.slice(-16);
502
+ const key = CryptoJS.enc.Utf8.parse(first16Key);
503
+ const iv = CryptoJS.enc.Utf8.parse(last16Iv);
504
+ const decryptedData = CryptoJS.AES.decrypt(payload, key, {
505
+ keySize: 128 / 8,
506
+ iv,
507
+ mode: CryptoJS.mode.CBC,
508
+ padding: CryptoJS.pad.Pkcs7
509
+ });
510
+ const decryptedText = decryptedData.toString(CryptoJS.enc.Utf8);
511
+ return JSON.parse(decryptedText);
512
+ }
513
+
514
+ // src/apis/resources.api.ts
515
+ async function getCountries(environment, secretKey) {
516
+ try {
517
+ const baseUrl = getBaseUrl(environment);
518
+ const res = await fetch(`${baseUrl}/api/v1/countries-iso`, {
519
+ method: "GET",
520
+ headers: {
521
+ "Content-Type": "application/json",
522
+ Accept: "application/json",
523
+ merchantId: secretKey
524
+ }
525
+ });
526
+ return await res.json();
527
+ } catch (error) {
528
+ }
529
+ }
530
+ async function getCountryStates(countryIso3, environment, secretKey) {
531
+ try {
532
+ const baseUrl = getBaseUrl(environment);
533
+ const res = await fetch(
534
+ `${baseUrl}/api/v1/state-by-country/${countryIso3}`,
535
+ {
536
+ method: "GET",
537
+ headers: {
538
+ "Content-Type": "application/json",
539
+ Accept: "application/json",
540
+ merchantId: secretKey
541
+ }
542
+ }
543
+ );
544
+ return await res.json();
545
+ } catch (error) {
546
+ }
547
+ }
548
+ async function getStableCoins(environment) {
549
+ try {
550
+ const baseUrl = getBaseUrl(environment);
551
+ const res = await fetch(`${baseUrl}/api/v1/checkout/stable-coin`, {
552
+ method: "GET",
553
+ headers: {
554
+ "Content-Type": "application/json",
555
+ Accept: "application/json"
556
+ }
557
+ });
558
+ return await res.json();
559
+ } catch (error) {
560
+ }
561
+ }
562
+ async function getStableCoinNetworks(environment, stableCoin) {
563
+ try {
564
+ const baseUrl = getBaseUrl(environment);
565
+ const res = await fetch(
566
+ `${baseUrl}/api/v1/checkout/networks/${stableCoin}`,
567
+ {
568
+ method: "GET",
569
+ headers: {
570
+ "Content-Type": "application/json",
571
+ Accept: "application/json"
572
+ }
143
573
  }
144
574
  );
145
575
  return await res.json();
@@ -797,13 +1227,33 @@ var BaseLabelInfo = ({
797
1227
 
798
1228
  // src/components/base/success.tsx
799
1229
  import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
800
- var BaseSuccess = ({}) => {
1230
+ var BaseSuccess = ({
1231
+ amount,
1232
+ currency,
1233
+ redirectUrl,
1234
+ successObject = {
1235
+ paymentDate: "",
1236
+ paymentId: "",
1237
+ paymentStatus: ""
1238
+ }
1239
+ }) => {
1240
+ const formatAmountHandler = formatAmount(amount, currency);
1241
+ const goToRedirectUrl = () => {
1242
+ window.open(redirectUrl, "_self", "noopener,noreferrer");
1243
+ };
1244
+ const paymentDate = new Date(
1245
+ successObject.paymentDate ?? ""
1246
+ ).toLocaleDateString("en-US", {
1247
+ year: "numeric",
1248
+ month: "long",
1249
+ day: "2-digit"
1250
+ });
801
1251
  return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-8 p-16", children: [
802
1252
  /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-8", children: [
803
1253
  /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-8", children: [
804
1254
  /* @__PURE__ */ jsx20(IconCheckCircle, { color: "#F47A1F", className: "mx-auto" }),
805
1255
  /* @__PURE__ */ jsxs11("div", { className: "flex flex-col text-center", style: { gap: "2px" }, children: [
806
- /* @__PURE__ */ jsx20("p", { className: "text-heading-text font-medium text-header-2xl", children: "\u20A62,500.00" }),
1256
+ /* @__PURE__ */ jsx20("p", { className: "text-heading-text font-medium text-header-2xl", children: formatAmountHandler }),
807
1257
  /* @__PURE__ */ jsx20("p", { className: "text-sub-copy font-regular text-body-3xs", children: "Has been paid successfully" })
808
1258
  ] })
809
1259
  ] }),
@@ -813,7 +1263,7 @@ var BaseSuccess = ({}) => {
813
1263
  {
814
1264
  type: "horizontal",
815
1265
  label: "Order ID",
816
- value: "9900009000-8890-8829hd7"
1266
+ value: successObject.paymentId
817
1267
  }
818
1268
  ) }),
819
1269
  /* @__PURE__ */ jsx20("div", { className: "py-4", children: /* @__PURE__ */ jsx20(
@@ -821,7 +1271,7 @@ var BaseSuccess = ({}) => {
821
1271
  {
822
1272
  type: "horizontal",
823
1273
  label: "Payment date",
824
- value: "July 24, 2025"
1274
+ value: paymentDate
825
1275
  }
826
1276
  ) })
827
1277
  ] })
@@ -831,7 +1281,8 @@ var BaseSuccess = ({}) => {
831
1281
  {
832
1282
  label: "Return to Merchant Website",
833
1283
  type: "secondary",
834
- customClass: "w-full"
1284
+ customClass: "w-full",
1285
+ onClick: goToRedirectUrl
835
1286
  }
836
1287
  ) })
837
1288
  ] });
@@ -851,6 +1302,7 @@ var BaseSelect = ({
851
1302
  value,
852
1303
  defaultValue,
853
1304
  onChange,
1305
+ onBlur,
854
1306
  placeholder = "Select an option",
855
1307
  hasSearch = true,
856
1308
  disabled = false,
@@ -923,6 +1375,7 @@ var BaseSelect = ({
923
1375
  const commit = (val) => {
924
1376
  if (!isControlled) setInternalValue(val);
925
1377
  onChange?.(val);
1378
+ onBlur?.(val);
926
1379
  closeMenu();
927
1380
  };
928
1381
  const onSearchInput = (e) => {
@@ -1073,6 +1526,7 @@ var BaseSelect = ({
1073
1526
  ref: searchRef,
1074
1527
  type: "text",
1075
1528
  onChange: onSearchInput,
1529
+ onBlur: onSearchInput,
1076
1530
  placeholder: `Search ${label || "options"}`,
1077
1531
  className: "bg-transparent outline-none border-b pb-2 w-full focus:outline-none focus:ring-0 text-body-2xs text-light-copy font-normal"
1078
1532
  }
@@ -1147,104 +1601,239 @@ var BaseCurrencyAmount = ({
1147
1601
  ] });
1148
1602
  };
1149
1603
 
1150
- // src/buzapay-checkout/checkout-iframe.tsx
1151
- import { useCallback as useCallback2, useEffect as useEffect2, useRef, useState as useState2 } from "react";
1152
- import { jsx as jsx24 } from "react/jsx-runtime";
1153
- function BzpCheckoutIframe({
1154
- style = {
1155
- width: "100%",
1156
- height: "100vh",
1157
- border: "0",
1158
- borderRadius: "6px",
1159
- overflow: "hidden"
1160
- },
1161
- url,
1162
- secretKey,
1163
- environment = "sandbox",
1164
- paymentObject = {
1165
- amount: 0,
1166
- currency: "",
1167
- email: "",
1168
- phoneNumber: "",
1169
- narration: "",
1170
- redirectUrl: ""
1171
- }
1172
- }) {
1173
- const containerRef = useRef(null);
1174
- const iframeRef = useRef(null);
1175
- const [message, setMessage] = useState2("");
1176
- const [launchUrl, setLaunchUrl] = useState2("");
1177
- const [loading, setLoading] = useState2(false);
1178
- const launchIframe = useCallback2(
1179
- (url2) => {
1180
- if (!containerRef.current) return;
1181
- if (iframeRef.current && iframeRef.current.parentNode) {
1182
- iframeRef.current.parentNode.removeChild(iframeRef.current);
1183
- }
1184
- const iframe = document.createElement("iframe");
1185
- iframe.src = url2;
1186
- if (style.width) iframe.style.width = style.width;
1187
- if (style.height) iframe.style.height = style.height;
1188
- if (style.border) iframe.style.border = style.border;
1189
- if (style.borderRadius) iframe.style.borderRadius = style.borderRadius;
1190
- if (style.overflow) iframe.style.overflow = style.overflow;
1191
- containerRef.current.appendChild(iframe);
1192
- iframeRef.current = iframe;
1193
- },
1194
- [style]
1604
+ // src/components/base/input.tsx
1605
+ import React4 from "react";
1606
+ import { IMaskInput } from "react-imask";
1607
+ import { Fragment as Fragment2, jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
1608
+ var BaseInput = ({
1609
+ label = "",
1610
+ type = "text",
1611
+ mask,
1612
+ placeholder,
1613
+ validationError = "",
1614
+ hint = "",
1615
+ rules = [],
1616
+ isAmountInput = false,
1617
+ required = false,
1618
+ disabled = false,
1619
+ loading = false,
1620
+ showCopyIcon = false,
1621
+ preventPaste = false,
1622
+ value,
1623
+ defaultValue,
1624
+ onChange,
1625
+ onBlur,
1626
+ prefix,
1627
+ suffix,
1628
+ className = ""
1629
+ }) => {
1630
+ const isControlled = value !== void 0;
1631
+ const [rawValue, setRawValue] = React4.useState(
1632
+ defaultValue ?? value ?? ""
1195
1633
  );
1196
- const generatePaymentLinkHandler = async () => {
1197
- if (url) {
1198
- launchIframe(url);
1199
- return;
1200
- }
1201
- if (!secretKey) {
1202
- return setMessage("Secret key is required.");
1634
+ const [localHint, setLocalHint] = React4.useState("");
1635
+ const [localError, setLocalError] = React4.useState("");
1636
+ React4.useEffect(() => {
1637
+ if (isControlled) setRawValue(value ?? "");
1638
+ }, [isControlled, value]);
1639
+ const formattedValue = isAmountInput ? formatAmount(rawValue.replace(/,/g, "")) : rawValue;
1640
+ const handleChange = (e) => {
1641
+ const incoming = e.target.value.replace(/,/g, "");
1642
+ if (!isControlled) setRawValue(incoming);
1643
+ onChange?.(incoming);
1644
+ setTimeout(() => {
1645
+ const el = e.target;
1646
+ el.selectionStart = el.selectionEnd = el.value.length;
1647
+ });
1648
+ };
1649
+ const handleBlur = () => {
1650
+ onBlur?.(rawValue);
1651
+ };
1652
+ const handleKeyDown = (e) => {
1653
+ if (rules.includes("numeric")) restrictToNumericKeys(e);
1654
+ };
1655
+ const handlePaste = (e) => {
1656
+ if (preventPaste) {
1657
+ e.preventDefault();
1658
+ setLocalError("Pasting is disabled for this input");
1203
1659
  }
1204
- if (!checkObjectTruthy(paymentObject)) {
1660
+ };
1661
+ const containerBg = disabled ? "bg-grey-50 cursor-not-allowed" : "bg-white";
1662
+ const containerBorder = validationError || localError ? "border-red-300 bg-red-50" : "border-grey-100";
1663
+ const copyToClipboard = (text) => {
1664
+ return navigator.clipboard.writeText(text);
1665
+ };
1666
+ const copyHandler = () => {
1667
+ copyToClipboard(rawValue).then(() => {
1668
+ setLocalHint("Text copied to clipboard");
1669
+ }).catch(() => {
1670
+ setLocalError("Failed to copy text to clipboard");
1671
+ });
1672
+ };
1673
+ return /* @__PURE__ */ jsxs14("div", { className: `flex flex-col gap-2 ${className}`, children: [
1674
+ label ? /* @__PURE__ */ jsxs14("p", { className: "mb-0 text-body-2xs font-normal text-heading-text", children: [
1675
+ label,
1676
+ required && /* @__PURE__ */ jsx24("span", { className: "text-orange-required", children: " *" })
1677
+ ] }) : null,
1678
+ /* @__PURE__ */ jsxs14(
1679
+ "div",
1680
+ {
1681
+ className: `border-c px-3 py-2 flex items-center justify-between rounded-md h-12 ${containerBg} ${containerBorder}`,
1682
+ children: [
1683
+ prefix,
1684
+ /* @__PURE__ */ jsx24(
1685
+ IMaskInput,
1686
+ {
1687
+ type,
1688
+ mask,
1689
+ value: formattedValue,
1690
+ onChange: handleChange,
1691
+ onBlur: handleBlur,
1692
+ onKeyDown: handleKeyDown,
1693
+ onPaste: handlePaste,
1694
+ disabled,
1695
+ placeholder: placeholder ?? (label ? `Enter ${label.toLowerCase()}` : void 0),
1696
+ inputMode: isAmountInput ? "decimal" : void 0,
1697
+ className: "search-input bg-transparent outline-none border-none focus:outline-none focus:ring-0 text-body-2xs text-light-copy font-normal w-full"
1698
+ }
1699
+ ),
1700
+ !loading ? /* @__PURE__ */ jsxs14(Fragment2, { children: [
1701
+ suffix,
1702
+ showCopyIcon && rawValue && rawValue.trim() !== "" && /* @__PURE__ */ jsx24(
1703
+ BaseImage,
1704
+ {
1705
+ src: "assets/images/copyIcon.svg",
1706
+ alt: "copy",
1707
+ width: 16,
1708
+ height: 16,
1709
+ customClass: "cursor-pointer hover:opacity-70 transition-opacity",
1710
+ onClick: copyHandler
1711
+ }
1712
+ )
1713
+ ] }) : /* @__PURE__ */ jsx24("div", { className: "animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full" })
1714
+ ]
1715
+ }
1716
+ ),
1717
+ (hint || localHint) && /* @__PURE__ */ jsx24("p", { className: "text-body-3xs text-light-copy", children: localHint || hint }),
1718
+ (validationError || localError) && /* @__PURE__ */ jsx24("p", { className: "text-body-3xs text-red-500", children: localError || validationError })
1719
+ ] });
1720
+ };
1721
+
1722
+ // src/buzapay-checkout/checkout-iframe.tsx
1723
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef, useState as useState2 } from "react";
1724
+ import { jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
1725
+ function BzpCheckoutIframe({
1726
+ style = {
1727
+ width: "100%",
1728
+ height: "100vh",
1729
+ border: "0",
1730
+ borderRadius: "6px",
1731
+ overflow: "hidden"
1732
+ },
1733
+ url,
1734
+ secretKey,
1735
+ environment = "sandbox",
1736
+ paymentObject = {
1737
+ merchantName: "",
1738
+ amount: 0,
1739
+ currency: "",
1740
+ email: "",
1741
+ phoneNumber: "",
1742
+ narration: "",
1743
+ redirectUrl: "https://sandbox-merchant.buzapay.com/account/three-ds-status"
1744
+ },
1745
+ onError
1746
+ }) {
1747
+ const containerRef = useRef(null);
1748
+ const iframeRef = useRef(null);
1749
+ const [message, setMessage] = useState2("");
1750
+ const [launchUrl, setLaunchUrl] = useState2("");
1751
+ const [loading, setLoading] = useState2(false);
1752
+ const launchIframe = useCallback2(
1753
+ (url2) => {
1754
+ if (iframeRef.current && iframeRef.current.parentNode) {
1755
+ iframeRef.current.parentNode.removeChild(iframeRef.current);
1756
+ }
1757
+ const iframe = document.createElement("iframe");
1758
+ iframe.src = url2;
1759
+ if (style.width) iframe.style.width = style.width;
1760
+ if (style.height) iframe.style.height = style.height;
1761
+ if (style.border) iframe.style.border = style.border;
1762
+ if (style.borderRadius) iframe.style.borderRadius = style.borderRadius;
1763
+ if (style.overflow) iframe.style.overflow = style.overflow;
1764
+ containerRef.current?.appendChild(iframe);
1765
+ iframeRef.current = iframe;
1766
+ },
1767
+ [style]
1768
+ );
1769
+ const generatePaymentLinkHandler = async () => {
1770
+ if (url) {
1771
+ launchIframe(url);
1772
+ return;
1773
+ }
1774
+ if (!secretKey) {
1775
+ return setMessage("Secret key is required.");
1776
+ }
1777
+ if (!checkObjectTruthy(paymentObject)) {
1205
1778
  return setMessage("Secret key is required.");
1206
1779
  }
1207
1780
  setLoading(true);
1208
- const response = await createPaymentLink(
1209
- paymentObject,
1210
- environment,
1211
- secretKey
1212
- );
1213
- if (response?.isSuccessful) {
1214
- setLaunchUrl(response.launchUrl ?? "");
1215
- setMessage("Payment link created successfully");
1216
- if (launchUrl) {
1217
- launchIframe(launchUrl);
1781
+ try {
1782
+ const response = await createPaymentLink(
1783
+ paymentObject,
1784
+ environment,
1785
+ secretKey
1786
+ );
1787
+ if (response?.isSuccessful) {
1788
+ setLaunchUrl(response.launchUrl ?? "");
1789
+ setMessage("Payment link created successfully");
1790
+ if (response.launchUrl) {
1791
+ setLoading(false);
1792
+ launchIframe(`${response.launchUrl}&merchantId=${btoa(secretKey)}`);
1793
+ }
1794
+ } else {
1795
+ setLoading(false);
1796
+ setMessage("Failed to create payment link");
1218
1797
  }
1219
- } else {
1220
- setMessage("Failed to create payment link");
1798
+ } catch (e) {
1799
+ setMessage(e?.message || "Failed to create payment link");
1800
+ onError?.({
1801
+ errorMessage: message
1802
+ });
1803
+ } finally {
1804
+ setLoading(false);
1221
1805
  }
1222
1806
  };
1223
1807
  useEffect2(() => {
1224
- (async () => {
1225
- await generatePaymentLinkHandler();
1226
- })();
1808
+ if (!containerRef.current) return;
1809
+ generatePaymentLinkHandler();
1227
1810
  }, []);
1228
- return loading ? /* @__PURE__ */ jsx24("div", { className: "w-full h-48 flex flex-col justify-center items-center", children: /* @__PURE__ */ jsx24(IconLoader, {}) }) : /* @__PURE__ */ jsx24("div", { ref: containerRef, style });
1811
+ return /* @__PURE__ */ jsxs15("div", { className: "relative", style, children: [
1812
+ /* @__PURE__ */ jsx25("div", { ref: containerRef, className: "w-full h-full" }),
1813
+ loading && /* @__PURE__ */ jsx25("div", { className: "absolute inset-0 grid place-items-center bg-white/60", children: /* @__PURE__ */ jsx25(IconLoader, {}) })
1814
+ ] });
1229
1815
  }
1230
1816
 
1231
1817
  // src/buzapay-checkout/checkout-button.tsx
1232
- import { jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
1818
+ import { jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
1233
1819
  function BzpCheckoutButton({
1234
1820
  secretKey,
1235
1821
  environment = "sandbox",
1236
1822
  paymentObject = {
1823
+ merchantName: "",
1237
1824
  amount: 0,
1238
1825
  currency: "",
1239
1826
  email: "",
1240
1827
  phoneNumber: "",
1241
1828
  narration: "",
1242
- redirectUrl: ""
1829
+ redirectUrl: "https://sandbox-merchant.buzapay.com/account/three-ds-status"
1243
1830
  },
1244
- mode = "redirect"
1831
+ mode = "redirect",
1832
+ onError
1245
1833
  }) {
1246
1834
  const [message, setMessage] = useState3("");
1247
1835
  const [launchUrl, setLaunchUrl] = useState3("");
1836
+ const [urlLaunchUrl, setUrlLaunchUrl] = useState3("");
1248
1837
  const [loading, setLoading] = useState3(false);
1249
1838
  const generatePaymentLinkHandler = async () => {
1250
1839
  if (!secretKey) {
@@ -1265,6 +1854,7 @@ function BzpCheckoutButton({
1265
1854
  );
1266
1855
  if (response?.isSuccessful && response.launchUrl) {
1267
1856
  setLaunchUrl(response.launchUrl);
1857
+ setUrlLaunchUrl(`${response.launchUrl}&merchantId=${btoa(secretKey)}`);
1268
1858
  setMessage("Payment link created successfully");
1269
1859
  if (mode === "redirect") {
1270
1860
  window.open(response.launchUrl, "_blank", "noopener,noreferrer");
@@ -1274,19 +1864,22 @@ function BzpCheckoutButton({
1274
1864
  }
1275
1865
  } catch (e) {
1276
1866
  setMessage(e?.message || "Failed to create payment link");
1867
+ onError?.({
1868
+ errorMessage: message
1869
+ });
1277
1870
  } finally {
1278
1871
  setLoading(false);
1279
1872
  }
1280
1873
  };
1281
- return launchUrl && mode === "iframe" ? /* @__PURE__ */ jsx25(
1874
+ return urlLaunchUrl && mode === "iframe" ? /* @__PURE__ */ jsx26(
1282
1875
  BzpCheckoutIframe,
1283
1876
  {
1284
- url: launchUrl,
1877
+ url: urlLaunchUrl,
1285
1878
  secretKey,
1286
1879
  environment
1287
1880
  }
1288
- ) : /* @__PURE__ */ jsxs14("div", { children: [
1289
- /* @__PURE__ */ jsx25(
1881
+ ) : /* @__PURE__ */ jsxs16("div", { children: [
1882
+ /* @__PURE__ */ jsx26(
1290
1883
  BaseButton,
1291
1884
  {
1292
1885
  label: "Pay",
@@ -1296,146 +1889,376 @@ function BzpCheckoutButton({
1296
1889
  onClick: generatePaymentLinkHandler
1297
1890
  }
1298
1891
  ),
1299
- /* @__PURE__ */ jsx25(BaseInputError, { errorMessage: message })
1892
+ /* @__PURE__ */ jsx26(BaseInputError, { errorMessage: message })
1300
1893
  ] });
1301
1894
  }
1302
1895
 
1303
1896
  // src/buzapay-checkout/checkout-card.tsx
1304
- import { useEffect as useEffect4, useState as useState7 } from "react";
1897
+ import { useEffect as useEffect6, useState as useState7 } from "react";
1305
1898
 
1306
1899
  // src/components/pay-by-card.tsx
1307
- import { useState as useState4 } from "react";
1308
-
1309
- // src/components/base/input.tsx
1310
- import React4 from "react";
1311
- import { Fragment as Fragment2, jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
1312
- var BaseInput = ({
1313
- label = "",
1314
- type = "text",
1315
- placeholder,
1316
- validationError = "",
1317
- hint = "",
1318
- rules = [],
1319
- isAmountInput = false,
1320
- required = false,
1321
- disabled = false,
1322
- loading = false,
1323
- showCopyIcon = false,
1324
- value,
1325
- defaultValue,
1326
- onChange,
1327
- onBlur,
1328
- prefix,
1329
- suffix,
1330
- className = ""
1331
- }) => {
1332
- const isControlled = value !== void 0;
1333
- const [rawValue, setRawValue] = React4.useState(
1334
- defaultValue ?? value ?? ""
1900
+ import { useEffect as useEffect3, useState as useState4 } from "react";
1901
+ import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
1902
+ function PayByCard({
1903
+ secretKey,
1904
+ paymentObject,
1905
+ environment = "sandbox",
1906
+ onPaymentAuthorized,
1907
+ onError
1908
+ }) {
1909
+ const [formIndex, setFormIndex] = useState4(0);
1910
+ const [message, setMessage] = useState4("");
1911
+ const [isMakingPayment, setIsMakingPayment] = useState4(false);
1912
+ const [loading, setLoading] = useState4(false);
1913
+ const [cardType, setCardType] = useState4("");
1914
+ const [transactionReference, setTransactionReference] = useState4("");
1915
+ const [loadingCountries, setLoadingCountries] = useState4(false);
1916
+ const [loadingStates, setLoadingStates] = useState4(false);
1917
+ const [rawCountries, setRawCountries] = useState4([]);
1918
+ const [countries, setCountries] = useState4([]);
1919
+ const [countryStates, setCountryStates] = useState4([]);
1920
+ const [billingForm, setBillingForm] = useState4({
1921
+ address1: "",
1922
+ address2: "",
1923
+ postalCode: "",
1924
+ state: "",
1925
+ city: "",
1926
+ country: "",
1927
+ emailAddress: "",
1928
+ phoneNumber: ""
1929
+ });
1930
+ const [payForm, setPayForm] = useState4({
1931
+ customerName: "",
1932
+ cardNo: "",
1933
+ expireDate: "",
1934
+ cvv: "",
1935
+ cardPin: ""
1936
+ // Only required for Verve cards
1937
+ });
1938
+ const [billingErrors, setBillingErrors] = useState4(
1939
+ {}
1335
1940
  );
1336
- const [localHint, setLocalHint] = React4.useState("");
1337
- const [localError, setLocalError] = React4.useState("");
1338
- React4.useEffect(() => {
1339
- if (isControlled) setRawValue(value ?? "");
1340
- }, [isControlled, value]);
1341
- const formattedValue = isAmountInput ? formatAmount(rawValue.replace(/,/g, "")) : rawValue;
1342
- const handleChange = (e) => {
1343
- const incoming = e.target.value.replace(/,/g, "");
1344
- if (!isControlled) setRawValue(incoming);
1345
- onChange?.(incoming);
1346
- setTimeout(() => {
1347
- const el = e.target;
1348
- el.selectionStart = el.selectionEnd = el.value.length;
1349
- });
1941
+ const [payErrors, setPayErrors] = useState4({});
1942
+ const billingRules = {
1943
+ address1: "required",
1944
+ address2: "",
1945
+ // optional
1946
+ country: "required",
1947
+ state: "required",
1948
+ city: "required",
1949
+ postalCode: "required|no_special|char_length:6",
1950
+ emailAddress: "required|email",
1951
+ phoneNumber: "required"
1350
1952
  };
1351
- const handleBlur = () => {
1352
- onBlur?.(rawValue);
1953
+ const payRules = {
1954
+ customerName: "required",
1955
+ cardNo: "required|num_spaces",
1956
+ expireDate: "required",
1957
+ cvv: "required|numeric",
1958
+ cardPin: ""
1959
+ // optional unless Verve
1353
1960
  };
1354
- const handleKeyDown = (e) => {
1355
- if (rules.includes("numeric")) restrictToNumericKeys(e);
1961
+ const formatAmountHandler = formatAmount(
1962
+ paymentObject.amount,
1963
+ paymentObject.currency
1964
+ );
1965
+ const billingLabels = {
1966
+ address1: "Address Line 1",
1967
+ address2: "Address Line 2",
1968
+ postalCode: "Postal Code",
1969
+ state: "State",
1970
+ city: "City",
1971
+ country: "Country",
1972
+ emailAddress: "Email",
1973
+ phoneNumber: "Phone Number"
1356
1974
  };
1357
- const containerBg = disabled ? "bg-grey-50 cursor-not-allowed" : "bg-white";
1358
- const containerBorder = validationError || localError ? "border-red-300 bg-red-50" : "border-grey-100";
1359
- const copyToClipboard = (text) => {
1360
- return navigator.clipboard.writeText(text);
1975
+ const payLabels = {
1976
+ customerName: "Card Name",
1977
+ cardNo: "Card Number",
1978
+ expireDate: "Expiry Date",
1979
+ cvv: "CVV",
1980
+ cardPin: "Card PIN"
1361
1981
  };
1362
- const copyHandler = () => {
1363
- copyToClipboard(rawValue).then(() => {
1364
- setLocalHint("Text copied to clipboard");
1365
- }).catch((err) => {
1366
- setLocalError("Failed to copy text to clipboard");
1367
- });
1982
+ const proceedHandler = async () => {
1983
+ if (formIndex === 0) {
1984
+ const errs = validateGroup(billingForm, billingRules, billingLabels);
1985
+ setBillingErrors(errs);
1986
+ if (Object.keys(errs).length === 0) {
1987
+ setFormIndex(1);
1988
+ }
1989
+ return;
1990
+ }
1991
+ if (formIndex === 1) {
1992
+ const errs = validateGroup(payForm, payRules, payLabels);
1993
+ setPayErrors(errs);
1994
+ if (Object.keys(errs).length > 0) {
1995
+ return;
1996
+ }
1997
+ try {
1998
+ setIsMakingPayment(true);
1999
+ setMessage("");
2000
+ const cardDetails = {
2001
+ pan: payForm.cardNo ?? "",
2002
+ expiryDate: payForm.expireDate ?? "",
2003
+ cvv: payForm.cvv ?? "",
2004
+ cardScheme: cardType,
2005
+ nameOnCard: payForm.customerName ?? "",
2006
+ ...cardType === "Verve" && { pin: payForm.cardPin ?? "" }
2007
+ };
2008
+ const billingDetails = {
2009
+ address1: billingForm.address1 ?? "",
2010
+ address2: billingForm.address2 ?? "",
2011
+ postalCode: billingForm.postalCode ?? "",
2012
+ state: billingForm.state ?? "",
2013
+ city: billingForm.city ?? "",
2014
+ country: billingForm.country ?? "",
2015
+ emailAddress: billingForm.emailAddress ?? "",
2016
+ phoneNumber: billingForm.phoneNumber ?? ""
2017
+ };
2018
+ const encryptedCardDetails = encryptPayload(secretKey, cardDetails);
2019
+ const payload = {
2020
+ customerId: paymentObject?.email || payForm.customerName || "",
2021
+ amount: String(paymentObject?.amount ?? ""),
2022
+ currency: paymentObject?.currency || "USD",
2023
+ narration: paymentObject?.narration || "Test transaction",
2024
+ encryptedCardDetails: encryptedCardDetails.requestParam,
2025
+ billingDetails,
2026
+ redirectUrl: paymentObject?.redirectUrl || "",
2027
+ paymentReference: transactionReference,
2028
+ isCheckout: true
2029
+ };
2030
+ const request = { ...payload, merchantId: secretKey };
2031
+ let response = await authorizeCardPayment(environment, request);
2032
+ if (response?.responseParam) {
2033
+ response = decryptPayload(environment, response.responseParam);
2034
+ }
2035
+ if (response?.isSuccessful) {
2036
+ if (response.threeDsInteractionRequired === true) {
2037
+ const threeDsData = {
2038
+ transactionReference: response.transactionReference,
2039
+ threeDsHtml: response.threeDsHtml,
2040
+ amount: response.amount,
2041
+ responseMessage: response.responseMessage,
2042
+ paReq: response.threeDsHtml?.paReq,
2043
+ termUrl: response.threeDsHtml?.termUrl,
2044
+ action: response.threeDsHtml?.action,
2045
+ acsUrl: response.threeDsHtml?.acsUrl,
2046
+ md: response.threeDsHtml?.md
2047
+ };
2048
+ const stringifiedThreeDsData = btoa(JSON.stringify(threeDsData));
2049
+ const threeDsUrl = `https://sandbox-merchant.buzapay.com/account/three-ds-confirm?threeDsData=${encodeURIComponent(
2050
+ stringifiedThreeDsData
2051
+ )}&paymentReference=${response.transactionReference}`;
2052
+ window.open(threeDsUrl, "_self", "noopener,noreferrer");
2053
+ setMessage(
2054
+ "3D Secure authentication opened in new tab. Please complete the verification"
2055
+ );
2056
+ setIsMakingPayment(false);
2057
+ return;
2058
+ }
2059
+ if (response.responseMessage === "Payer Interaction Required" && response.threeDsHtml) {
2060
+ const threeDsData = {
2061
+ transactionReference: response.transactionReference,
2062
+ threeDsHtml: response.threeDsHtml,
2063
+ amount: response.amount,
2064
+ responseMessage: response.responseMessage,
2065
+ paReq: response.threeDsHtml?.paReq,
2066
+ termUrl: response.threeDsHtml?.termUrl,
2067
+ action: response.threeDsHtml?.action,
2068
+ acsUrl: response.threeDsHtml?.acsUrl,
2069
+ md: response.threeDsHtml?.md
2070
+ };
2071
+ const stringifiedThreeDsData = btoa(JSON.stringify(threeDsData));
2072
+ const threeDsUrl = `https://sandbox-merchant.buzapay.com/account/three-ds-confirm?threeDsData=${encodeURIComponent(
2073
+ stringifiedThreeDsData
2074
+ )}&paymentReference=${response.transactionReference}`;
2075
+ window.open(threeDsUrl, "_self", "noopener,noreferrer");
2076
+ setMessage(
2077
+ "3D Secure authentication opened in new tab. Please complete the verification"
2078
+ );
2079
+ setIsMakingPayment(false);
2080
+ return;
2081
+ }
2082
+ if (response.transactionReference?.trim()) {
2083
+ onPaymentAuthorized?.({
2084
+ paymentId: response.transactionReference,
2085
+ paymentDate: response?.data?.updatedAt,
2086
+ // optional if present
2087
+ paymentStatus: "authorized",
2088
+ message
2089
+ });
2090
+ }
2091
+ setMessage("Card payment authorized successfully");
2092
+ setIsMakingPayment(false);
2093
+ return;
2094
+ }
2095
+ setMessage(response?.responseMessage || "Payment failed");
2096
+ onPaymentAuthorized?.({
2097
+ paymentId: response?.transactionReference,
2098
+ paymentDate: response?.data?.updatedAt,
2099
+ paymentStatus: "payment failed",
2100
+ message
2101
+ });
2102
+ setIsMakingPayment(false);
2103
+ } catch (err) {
2104
+ let friendly = "Payment failed";
2105
+ if (err?.error?.responseParam) {
2106
+ try {
2107
+ const decryptedError = decryptPayload(
2108
+ environment,
2109
+ err.error.responseParam
2110
+ );
2111
+ friendly = decryptedError?.responseMessage || friendly;
2112
+ } catch {
2113
+ friendly = err?.error?.responseMessage || err?.error?.message || friendly;
2114
+ }
2115
+ } else {
2116
+ friendly = err?.error?.responseMessage || err?.error?.message || "Payment failed";
2117
+ }
2118
+ setMessage(friendly);
2119
+ setIsMakingPayment(false);
2120
+ onError?.({
2121
+ errorMessage: message
2122
+ });
2123
+ }
2124
+ }
1368
2125
  };
1369
- return /* @__PURE__ */ jsxs15("div", { className: `flex flex-col gap-2 ${className}`, children: [
1370
- label ? /* @__PURE__ */ jsxs15("p", { className: "mb-0 text-body-2xs font-normal text-heading-text", children: [
1371
- label,
1372
- required && /* @__PURE__ */ jsx26("span", { className: "text-orange-required", children: " *" })
1373
- ] }) : null,
1374
- /* @__PURE__ */ jsxs15(
1375
- "div",
1376
- {
1377
- className: `border-c px-3 py-2 flex items-center justify-between rounded-md h-12 ${containerBg} ${containerBorder}`,
1378
- children: [
1379
- prefix,
1380
- /* @__PURE__ */ jsx26(
1381
- "input",
1382
- {
1383
- type,
1384
- value: formattedValue,
1385
- onChange: handleChange,
1386
- onBlur: handleBlur,
1387
- onKeyDown: handleKeyDown,
1388
- disabled,
1389
- placeholder: placeholder ?? (label ? `Enter ${label.toLowerCase()}` : void 0),
1390
- inputMode: isAmountInput ? "decimal" : void 0,
1391
- className: "search-input bg-transparent outline-none border-none focus:outline-none focus:ring-0 text-body-2xs text-light-copy font-normal w-full"
1392
- }
1393
- ),
1394
- !loading ? /* @__PURE__ */ jsxs15(Fragment2, { children: [
1395
- suffix,
1396
- showCopyIcon && rawValue && rawValue.trim() !== "" && /* @__PURE__ */ jsx26(
1397
- BaseImage,
1398
- {
1399
- src: "assets/images/copyIcon.svg",
1400
- alt: "copy",
1401
- width: 16,
1402
- height: 16,
1403
- customClass: "cursor-pointer hover:opacity-70 transition-opacity",
1404
- onClick: copyHandler
1405
- }
1406
- )
1407
- ] }) : (
1408
- // Simple loader placeholder; swap for your icon component if desired
1409
- /* @__PURE__ */ jsx26("div", { className: "animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full" })
1410
- )
1411
- ]
2126
+ const generatePaymentLinkHandler = async () => {
2127
+ if (!secretKey) {
2128
+ setMessage("Secret key is required.");
2129
+ return;
2130
+ }
2131
+ if (!checkObjectTruthy(paymentObject)) {
2132
+ setMessage("Kindly ensure you are passing all the required data.");
2133
+ return;
2134
+ }
2135
+ setLoading(true);
2136
+ setMessage("");
2137
+ try {
2138
+ const response = await createPaymentLink(
2139
+ paymentObject,
2140
+ environment,
2141
+ secretKey
2142
+ );
2143
+ if (response?.isSuccessful && response.launchUrl) {
2144
+ const queryParams = getQueryParams(response.launchUrl);
2145
+ setTransactionReference(queryParams["paymentReference"]);
2146
+ setMessage("Payment link created successfully");
2147
+ } else {
2148
+ setMessage("Failed to create payment link");
1412
2149
  }
1413
- ),
1414
- (hint || localHint) && /* @__PURE__ */ jsx26("p", { className: "text-body-3xs text-light-copy", children: localHint || hint }),
1415
- (validationError || localError) && /* @__PURE__ */ jsx26("p", { className: "text-body-3xs text-red-500", children: localError || validationError })
1416
- ] });
1417
- };
1418
-
1419
- // src/components/pay-by-card.tsx
1420
- import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
1421
- function PayByCard({}) {
1422
- const [formIndex, setFormIndex] = useState4(0);
1423
- return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-6", children: [
1424
- formIndex === 0 && /* @__PURE__ */ jsxs16("div", { className: "grid grid-cols-2 gap-6 overflow-y-auto", children: [
1425
- /* @__PURE__ */ jsx27(BaseInput, { label: "First Name", required: true }),
1426
- /* @__PURE__ */ jsx27(BaseInput, { label: "Last Name", required: true }),
1427
- /* @__PURE__ */ jsx27(BaseInput, { label: "Email", required: true }),
1428
- /* @__PURE__ */ jsx27(BaseInput, { label: "Phone Number", required: true }),
2150
+ } catch (e) {
2151
+ setMessage(e?.message || "Failed to create payment link");
2152
+ onError?.({
2153
+ errorMessage: message
2154
+ });
2155
+ } finally {
2156
+ setLoading(false);
2157
+ }
2158
+ };
2159
+ const getAllCountries = async () => {
2160
+ setLoadingCountries(true);
2161
+ try {
2162
+ const response = await getCountries(
2163
+ environment,
2164
+ secretKey
2165
+ );
2166
+ if (response?.isSuccessful) {
2167
+ setRawCountries(response.data);
2168
+ setCountries(
2169
+ (response.data ?? []).map((c) => {
2170
+ return { label: c.countryName, value: c.iso2 };
2171
+ })
2172
+ );
2173
+ }
2174
+ } catch (e) {
2175
+ setMessage(e?.message || "Failed to get countries");
2176
+ onError?.({
2177
+ errorMessage: message
2178
+ });
2179
+ } finally {
2180
+ setLoadingCountries(false);
2181
+ }
2182
+ };
2183
+ const getStates = async (countryIso2) => {
2184
+ const country = rawCountries.find((c) => c.iso2 === countryIso2);
2185
+ if (!country) return;
2186
+ setLoadingStates(true);
2187
+ try {
2188
+ const response = await getCountryStates(
2189
+ country.iso3,
2190
+ environment,
2191
+ secretKey
2192
+ );
2193
+ if (response?.isSuccessful) {
2194
+ setCountryStates(
2195
+ (response.data ?? []).map((s) => ({
2196
+ label: s.name,
2197
+ value: s.name
2198
+ }))
2199
+ );
2200
+ }
2201
+ } catch (e) {
2202
+ setMessage(e?.message || "Failed to get country states");
2203
+ onError?.({
2204
+ errorMessage: message
2205
+ });
2206
+ } finally {
2207
+ setLoadingStates(false);
2208
+ }
2209
+ };
2210
+ const cardNumberInputHandler = (event) => {
2211
+ setCardType(cardTypeHandler(event));
2212
+ payRules.cardPin = cardType === "Verve" ? "required|numeric" : "";
2213
+ };
2214
+ useEffect3(() => {
2215
+ (async () => {
2216
+ await generatePaymentLinkHandler();
2217
+ await getAllCountries();
2218
+ })();
2219
+ }, []);
2220
+ return /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-6", children: [
2221
+ formIndex === 0 && /* @__PURE__ */ jsxs17("div", { className: "grid grid-cols-2 gap-6 overflow-y-auto", children: [
2222
+ /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(
2223
+ BaseInput,
2224
+ {
2225
+ label: "Address Line 1",
2226
+ required: true,
2227
+ value: billingForm.address1,
2228
+ onChange: (e) => {
2229
+ setBillingForm({ ...billingForm, address1: e });
2230
+ if (billingErrors.address1) {
2231
+ setBillingErrors((er) => ({ ...er, address1: "" }));
2232
+ }
2233
+ },
2234
+ validationError: billingErrors.address1 ?? ""
2235
+ }
2236
+ ) }),
2237
+ /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(
2238
+ BaseInput,
2239
+ {
2240
+ label: "Address Line 2",
2241
+ value: billingForm.address2,
2242
+ onChange: (e) => setBillingForm({ ...billingForm, address2: e }),
2243
+ validationError: billingErrors.address2 ?? ""
2244
+ }
2245
+ ) }),
1429
2246
  /* @__PURE__ */ jsx27(
1430
2247
  BaseSelect,
1431
2248
  {
1432
2249
  label: "Select Country",
1433
2250
  required: true,
1434
- options: [
1435
- { label: "United States", value: "US" },
1436
- { label: "Canada", value: "CA" },
1437
- { label: "United Kingdom", value: "UK" }
1438
- ]
2251
+ options: countries,
2252
+ loading: loadingCountries,
2253
+ value: billingForm.country,
2254
+ onChange: (e) => {
2255
+ setBillingForm({ ...billingForm, country: e, state: "" });
2256
+ getStates(e);
2257
+ if (billingErrors.country) {
2258
+ setBillingErrors((er) => ({ ...er, country: "" }));
2259
+ }
2260
+ },
2261
+ validationError: billingErrors.country ?? ""
1439
2262
  }
1440
2263
  ),
1441
2264
  /* @__PURE__ */ jsx27(
@@ -1443,158 +2266,729 @@ function PayByCard({}) {
1443
2266
  {
1444
2267
  label: "Select State",
1445
2268
  required: true,
1446
- options: [
1447
- { label: "California", value: "CA" },
1448
- { label: "Texas", value: "TX" },
1449
- { label: "New York", value: "NY" }
1450
- ]
2269
+ options: countryStates,
2270
+ loading: loadingStates,
2271
+ value: billingForm.state,
2272
+ onChange: (e) => {
2273
+ setBillingForm({ ...billingForm, state: e });
2274
+ if (billingErrors.state) {
2275
+ setBillingErrors((er) => ({ ...er, state: "" }));
2276
+ }
2277
+ },
2278
+ validationError: billingErrors.state ?? ""
2279
+ }
2280
+ ),
2281
+ /* @__PURE__ */ jsx27(
2282
+ BaseInput,
2283
+ {
2284
+ label: "City",
2285
+ required: true,
2286
+ value: billingForm.city,
2287
+ onChange: (e) => {
2288
+ setBillingForm({ ...billingForm, city: e });
2289
+ if (billingErrors.city) {
2290
+ setBillingErrors((er) => ({ ...er, city: "" }));
2291
+ }
2292
+ },
2293
+ validationError: billingErrors.city ?? ""
2294
+ }
2295
+ ),
2296
+ /* @__PURE__ */ jsx27(
2297
+ BaseInput,
2298
+ {
2299
+ label: "Postal Code",
2300
+ required: true,
2301
+ value: billingForm.postalCode,
2302
+ onChange: (e) => {
2303
+ setBillingForm({ ...billingForm, postalCode: e });
2304
+ if (billingErrors.postalCode) {
2305
+ setBillingErrors((er) => ({ ...er, postalCode: "" }));
2306
+ }
2307
+ },
2308
+ validationError: billingErrors.postalCode ?? ""
1451
2309
  }
1452
2310
  ),
1453
- /* @__PURE__ */ jsx27(BaseInput, { label: "City", required: true }),
1454
- /* @__PURE__ */ jsx27(BaseInput, { label: "Postal Code", required: true }),
1455
- /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(BaseInput, { label: "Street Address", required: true }) })
2311
+ /* @__PURE__ */ jsx27(
2312
+ BaseInput,
2313
+ {
2314
+ label: "Email",
2315
+ required: true,
2316
+ value: billingForm.emailAddress,
2317
+ onChange: (e) => {
2318
+ setBillingForm({ ...billingForm, emailAddress: e });
2319
+ if (billingErrors.emailAddress) {
2320
+ setBillingErrors((er) => ({ ...er, emailAddress: "" }));
2321
+ }
2322
+ },
2323
+ validationError: billingErrors.emailAddress ?? ""
2324
+ }
2325
+ ),
2326
+ /* @__PURE__ */ jsx27(
2327
+ BaseInput,
2328
+ {
2329
+ label: "Phone Number",
2330
+ required: true,
2331
+ value: billingForm.phoneNumber,
2332
+ onChange: (e) => {
2333
+ setBillingForm({ ...billingForm, phoneNumber: e });
2334
+ if (billingErrors.phoneNumber) {
2335
+ setBillingErrors((er) => ({ ...er, phoneNumber: "" }));
2336
+ }
2337
+ },
2338
+ validationError: billingErrors.phoneNumber ?? ""
2339
+ }
2340
+ )
1456
2341
  ] }),
1457
- formIndex === 1 && /* @__PURE__ */ jsxs16(
2342
+ formIndex === 1 && /* @__PURE__ */ jsxs17(
1458
2343
  "div",
1459
2344
  {
1460
2345
  className: "grid grid-cols-2 gap-6 overflow-y-auto",
1461
- style: { maxHeight: "320px" },
2346
+ style: { maxHeight: 320 },
1462
2347
  children: [
1463
- /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(BaseInput, { label: "Card Name", required: true }) }),
1464
- /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(BaseInput, { label: "Card Number", required: true }) }),
1465
- /* @__PURE__ */ jsx27(BaseInput, { label: "Expiry Date", required: true }),
1466
- /* @__PURE__ */ jsx27(BaseInput, { label: "CVV", required: true })
2348
+ /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(
2349
+ BaseInput,
2350
+ {
2351
+ label: "Card Name",
2352
+ required: true,
2353
+ value: payForm.customerName,
2354
+ onChange: (e) => {
2355
+ setPayForm({ ...payForm, customerName: e });
2356
+ if (payErrors.customerName) {
2357
+ setPayErrors((er) => ({ ...er, customerName: "" }));
2358
+ }
2359
+ },
2360
+ validationError: payErrors.customerName ?? ""
2361
+ }
2362
+ ) }),
2363
+ /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(
2364
+ BaseInput,
2365
+ {
2366
+ label: "Card Number",
2367
+ required: true,
2368
+ rules: ["numeric"],
2369
+ mask: "0000 0000 0000 0000",
2370
+ placeholder: "0000 0000 0000 0000",
2371
+ value: payForm.cardNo,
2372
+ preventPaste: true,
2373
+ onChange: (e) => {
2374
+ setPayForm({ ...payForm, cardNo: e });
2375
+ if (payErrors.cardNo)
2376
+ setPayErrors((er) => ({ ...er, cardNo: "" }));
2377
+ cardNumberInputHandler(e);
2378
+ },
2379
+ validationError: payErrors.cardNo ?? ""
2380
+ }
2381
+ ) }),
2382
+ /* @__PURE__ */ jsx27(
2383
+ BaseInput,
2384
+ {
2385
+ label: "Expiry Date",
2386
+ required: true,
2387
+ value: payForm.expireDate,
2388
+ mask: "00/00",
2389
+ placeholder: "00/00",
2390
+ onChange: (e) => {
2391
+ setPayForm({ ...payForm, expireDate: e });
2392
+ if (payErrors.expireDate)
2393
+ setPayErrors((er) => ({ ...er, expireDate: "" }));
2394
+ },
2395
+ validationError: payErrors.expireDate ?? ""
2396
+ }
2397
+ ),
2398
+ /* @__PURE__ */ jsx27(
2399
+ BaseInput,
2400
+ {
2401
+ label: "CVV",
2402
+ required: true,
2403
+ rules: ["numeric"],
2404
+ value: payForm.cvv,
2405
+ mask: "000",
2406
+ placeholder: "000",
2407
+ onChange: (e) => {
2408
+ setPayForm({ ...payForm, cvv: e });
2409
+ if (payErrors.cvv) setPayErrors((er) => ({ ...er, cvv: "" }));
2410
+ },
2411
+ validationError: payErrors.cvv ?? ""
2412
+ }
2413
+ ),
2414
+ cardType === "Verve" && /* @__PURE__ */ jsx27(
2415
+ BaseInput,
2416
+ {
2417
+ label: "Card Pin",
2418
+ required: true,
2419
+ rules: ["numeric"],
2420
+ value: payForm.cardPin,
2421
+ mask: "0000",
2422
+ placeholder: "0000",
2423
+ onChange: (e) => {
2424
+ setPayForm({ ...payForm, cardPin: e });
2425
+ if (payErrors.cardPin)
2426
+ setPayErrors((er) => ({ ...er, cardPin: "" }));
2427
+ },
2428
+ validationError: payErrors.cardPin ?? ""
2429
+ }
2430
+ )
1467
2431
  ]
1468
2432
  }
1469
2433
  ),
1470
2434
  /* @__PURE__ */ jsx27(
1471
2435
  BaseButton,
1472
2436
  {
1473
- label: formIndex === 0 ? "Proceed" : "Pay",
2437
+ label: formIndex === 0 ? "Proceed" : `Pay ${formatAmountHandler}`,
1474
2438
  type: "primary",
1475
2439
  customClass: "w-full",
1476
- onClick: formIndex === 0 ? () => setFormIndex(1) : void 0
2440
+ loading: isMakingPayment,
2441
+ onClick: proceedHandler,
2442
+ disabled: isMakingPayment
1477
2443
  }
1478
2444
  )
1479
2445
  ] });
1480
2446
  }
1481
2447
 
1482
2448
  // src/components/pay-by-transfer.tsx
1483
- import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState5 } from "react";
1484
- import { jsx as jsx28, jsxs as jsxs17 } from "react/jsx-runtime";
2449
+ import {
2450
+ useCallback as useCallback3,
2451
+ useEffect as useEffect4,
2452
+ useRef as useRef2,
2453
+ useState as useState5
2454
+ } from "react";
2455
+ import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
1485
2456
  var PayByTransfer = ({
1486
- amountDisplay = "NGN 200,500.00",
1487
- bankName = "Teerus MFB",
1488
- accountNumber = "0001928940",
1489
- initialSeconds = 30 * 60,
1490
- onConfirmPaid,
1491
- onCancel
2457
+ secretKey,
2458
+ paymentObject,
2459
+ environment = "sandbox",
2460
+ onPaymentAuthorized,
2461
+ onCancel,
2462
+ onError
1492
2463
  }) => {
1493
- const [remaining, setRemaining] = useState5(initialSeconds);
2464
+ const [formIndex, setFormIndex] = useState5(0);
2465
+ const [isMakingPayment, setIsMakingPayment] = useState5(false);
2466
+ const [isConfirmCall, setIsConfirmCall] = useState5(false);
2467
+ const [isPaymentConfirmed, setIsPaymentConfirmed] = useState5(false);
2468
+ const [transactionReference, setTransactionReference] = useState5("");
2469
+ const [paymentReferenceStatus, setPaymentReferenceStatus] = useState5("");
2470
+ const [isFetchingPaymentDetails, setIsFetchingPaymentDetails] = useState5(false);
2471
+ const [paymentReferenceDetails, setPaymentReferenceDetails] = useState5(null);
2472
+ const [paymentAccountDetails, setPaymentAccountDetails] = useState5(null);
2473
+ const [paymentMade, setPaymentMade] = useState5(false);
2474
+ const [loading, setLoading] = useState5(false);
2475
+ const [message, setMessage] = useState5("");
2476
+ const [remainingSeconds, setRemainingSeconds] = useState5(60);
2477
+ const [countDownTime, setCountDownTime] = useState5("00:00");
1494
2478
  const intervalRef = useRef2(null);
1495
- const countDownTime = useMemo2(() => {
1496
- const clamped = Math.max(0, remaining);
1497
- const m = Math.floor(clamped / 60);
1498
- const s = clamped % 60;
1499
- return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
1500
- }, [remaining]);
1501
- useEffect3(() => {
1502
- intervalRef.current = window.setInterval(() => {
1503
- setRemaining((prev) => prev - 1);
1504
- }, 1e3);
1505
- return () => {
1506
- if (intervalRef.current) {
1507
- clearInterval(intervalRef.current);
1508
- intervalRef.current = null;
2479
+ const [transferForm, setTransferForm] = useState5({
2480
+ customerName: ""
2481
+ });
2482
+ const [transferErrors, setTransferErrors] = useState5(
2483
+ {}
2484
+ );
2485
+ const transferRules = {
2486
+ customerName: "required"
2487
+ };
2488
+ const transferLabels = {
2489
+ customerName: "Customer Name"
2490
+ };
2491
+ const formatAmountHandler = formatAmount(
2492
+ paymentObject.amount,
2493
+ paymentObject.currency
2494
+ );
2495
+ const payHandler = async () => {
2496
+ if (formIndex === 0) {
2497
+ const errs = validateGroup(transferForm, transferRules, transferLabels);
2498
+ setTransferErrors(errs);
2499
+ if (Object.keys(errs).length === 0) {
2500
+ const payload = {
2501
+ paymentReference: transactionReference,
2502
+ channel: "virtual_account",
2503
+ customerName: transferForm.customerName ?? "",
2504
+ merchantId: secretKey
2505
+ };
2506
+ setIsMakingPayment(true);
2507
+ try {
2508
+ const response = await generatePaymentAccount(environment, payload);
2509
+ if (response?.isSuccessful) {
2510
+ setPaymentAccountDetails(response.data);
2511
+ startTimer();
2512
+ setMessage("Virtual account generated successfully for payment.");
2513
+ setIsMakingPayment(true);
2514
+ setFormIndex(1);
2515
+ }
2516
+ } catch (err) {
2517
+ setIsMakingPayment(false);
2518
+ setMessage(err.error.responseMessage || err.error.message);
2519
+ onError?.({
2520
+ errorMessage: message
2521
+ });
2522
+ }
1509
2523
  }
1510
- };
2524
+ return;
2525
+ }
2526
+ };
2527
+ const getReferenceDetails = async () => {
2528
+ setIsFetchingPaymentDetails(true);
2529
+ try {
2530
+ const response = await getPaymentReferenceDetails(
2531
+ environment,
2532
+ transactionReference
2533
+ );
2534
+ if (response?.isSuccessful) {
2535
+ setPaymentReferenceDetails(response.data);
2536
+ const made = response.data?.paymentStatus === "Payment Received";
2537
+ setPaymentMade(made);
2538
+ const noServerStatus = response.data?.finalTransactionStatus == null || response.data?.paymentStatus == null;
2539
+ if (noServerStatus) {
2540
+ if (isConfirmCall) {
2541
+ setMessage("Transaction not confirmed !!");
2542
+ }
2543
+ if (!isPaymentConfirmed && !made) {
2544
+ setPaymentReferenceStatus("pending");
2545
+ onPaymentAuthorized?.({
2546
+ paymentId: transactionReference,
2547
+ paymentDate: response.data?.updatedAt,
2548
+ paymentStatus: "pending",
2549
+ message
2550
+ });
2551
+ } else {
2552
+ setPaymentReferenceStatus("confirmed");
2553
+ onPaymentAuthorized?.({
2554
+ paymentId: transactionReference,
2555
+ paymentDate: response.data?.updatedAt,
2556
+ paymentStatus: "confirmed",
2557
+ message
2558
+ });
2559
+ }
2560
+ } else if (response.data?.finalTransactionStatus === "Success" || response.data?.paymentStatus === "Received" || response.data?.paymentStatus === "Payment Received") {
2561
+ setPaymentReferenceStatus("confirmed");
2562
+ setIsPaymentConfirmed(true);
2563
+ setMessage("Transaction confirmed !!");
2564
+ onPaymentAuthorized?.({
2565
+ paymentId: transactionReference,
2566
+ paymentDate: response.data?.updatedAt,
2567
+ paymentStatus: "confirmed",
2568
+ message
2569
+ });
2570
+ }
2571
+ } else if (!response?.isSuccessful && response?.responseCode === "119") {
2572
+ setPaymentReferenceStatus("used");
2573
+ setMessage(response.responseMessage || "");
2574
+ onPaymentAuthorized?.({
2575
+ paymentId: transactionReference,
2576
+ paymentDate: null,
2577
+ paymentStatus: "used",
2578
+ message
2579
+ });
2580
+ }
2581
+ } catch (err) {
2582
+ setPaymentReferenceStatus("");
2583
+ setMessage(
2584
+ err?.error?.responseMessage || err?.error?.message || "Something went wrong"
2585
+ );
2586
+ onError?.({
2587
+ errorMessage: message
2588
+ });
2589
+ } finally {
2590
+ setIsFetchingPaymentDetails(false);
2591
+ }
2592
+ };
2593
+ const generatePaymentLinkHandler = async () => {
2594
+ if (!secretKey) {
2595
+ setMessage("Secret key is required.");
2596
+ return;
2597
+ }
2598
+ if (!checkObjectTruthy(paymentObject)) {
2599
+ setMessage("Kindly ensure you are passing all the required data.");
2600
+ return;
2601
+ }
2602
+ setLoading(true);
2603
+ setMessage("");
2604
+ try {
2605
+ const response = await createPaymentLink(
2606
+ paymentObject,
2607
+ environment,
2608
+ secretKey
2609
+ );
2610
+ if (response?.isSuccessful && response.launchUrl) {
2611
+ const queryParams = getQueryParams(response.launchUrl);
2612
+ setTransactionReference(queryParams["paymentReference"]);
2613
+ setMessage("Payment link created successfully");
2614
+ } else {
2615
+ setMessage("Failed to create payment link");
2616
+ }
2617
+ } catch (e) {
2618
+ setMessage(e?.message || "Failed to create payment link");
2619
+ onError?.({
2620
+ errorMessage: message
2621
+ });
2622
+ } finally {
2623
+ setLoading(false);
2624
+ }
2625
+ };
2626
+ const updateDisplay = useCallback3((secs) => {
2627
+ const minutes = String(Math.floor(secs / 60)).padStart(2, "0");
2628
+ const seconds = String(secs % 60).padStart(2, "0");
2629
+ setCountDownTime(`${minutes}:${seconds}`);
1511
2630
  }, []);
1512
- useEffect3(() => {
1513
- if (remaining < 0 && intervalRef.current) {
2631
+ const startTimer = useCallback3(() => {
2632
+ if (intervalRef.current) {
2633
+ clearInterval(intervalRef.current);
2634
+ intervalRef.current = null;
2635
+ }
2636
+ updateDisplay(remainingSeconds);
2637
+ intervalRef.current = setInterval(() => {
2638
+ setRemainingSeconds((prev) => {
2639
+ const next = prev - 1;
2640
+ if (next < 0) {
2641
+ if (intervalRef.current) {
2642
+ clearInterval(intervalRef.current);
2643
+ intervalRef.current = null;
2644
+ }
2645
+ setCountDownTime("00:00");
2646
+ return 0;
2647
+ }
2648
+ updateDisplay(next);
2649
+ return next;
2650
+ });
2651
+ }, 1e3);
2652
+ }, [remainingSeconds, updateDisplay]);
2653
+ const stopTimer = () => {
2654
+ if (intervalRef.current) {
1514
2655
  clearInterval(intervalRef.current);
1515
2656
  intervalRef.current = null;
1516
2657
  }
1517
- }, [remaining]);
1518
- return /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-10", children: [
1519
- /* @__PURE__ */ jsxs17("p", { className: "text-sub-copy text-sm font-semibold text-center", children: [
1520
- "Amount to Pay ",
1521
- amountDisplay
2658
+ };
2659
+ useEffect4(() => {
2660
+ (async () => {
2661
+ await generatePaymentLinkHandler();
2662
+ })();
2663
+ }, []);
2664
+ useEffect4(() => {
2665
+ if (remainingSeconds < 0 && intervalRef.current) {
2666
+ stopTimer();
2667
+ }
2668
+ }, [remainingSeconds]);
2669
+ return /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-10", children: [
2670
+ formIndex === 0 && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-10", children: [
2671
+ /* @__PURE__ */ jsx28(
2672
+ BaseInput,
2673
+ {
2674
+ label: "Customer Name",
2675
+ required: true,
2676
+ value: transferForm.customerName,
2677
+ onChange: (e) => {
2678
+ setTransferForm({ ...transferForm, customerName: e });
2679
+ if (transferForm.customerName) {
2680
+ setTransferErrors((er) => ({ ...er, customerName: "" }));
2681
+ }
2682
+ },
2683
+ validationError: transferErrors.customerName ?? ""
2684
+ }
2685
+ ),
2686
+ /* @__PURE__ */ jsx28(
2687
+ BaseButton,
2688
+ {
2689
+ label: `Pay ${formatAmountHandler}`,
2690
+ type: "primary",
2691
+ customClass: "w-full",
2692
+ loading: isMakingPayment,
2693
+ onClick: payHandler
2694
+ }
2695
+ )
1522
2696
  ] }),
1523
- /* @__PURE__ */ jsxs17("div", { className: "bg-[#EFF7FF] p-4 rounded-lg flex flex-col gap-6", children: [
1524
- /* @__PURE__ */ jsx28(BaseLabelInfo, { label: "Bank Name", value: bankName, type: "horizontal" }),
1525
- /* @__PURE__ */ jsxs17("div", { className: "flex items-center justify-between", children: [
2697
+ formIndex === 1 && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-10", children: [
2698
+ /* @__PURE__ */ jsxs18("div", { className: "bg-[#EFF7FF] p-4 rounded-lg flex flex-col gap-6", children: [
1526
2699
  /* @__PURE__ */ jsx28(
1527
2700
  BaseLabelInfo,
1528
2701
  {
1529
- label: "Account Number",
1530
- value: accountNumber,
1531
- type: "horizontal"
2702
+ label: "Bank Name",
2703
+ value: `${paymentAccountDetails?.bank} ${paymentAccountDetails?.accountName}`
1532
2704
  }
1533
2705
  ),
1534
- /* @__PURE__ */ jsx28(BaseCopy, { color: "#9DBFDE", copyText: accountNumber })
2706
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between", children: [
2707
+ /* @__PURE__ */ jsx28(
2708
+ BaseLabelInfo,
2709
+ {
2710
+ label: "Account Number",
2711
+ value: paymentAccountDetails?.accountNumber
2712
+ }
2713
+ ),
2714
+ /* @__PURE__ */ jsx28(
2715
+ BaseCopy,
2716
+ {
2717
+ color: "#9DBFDE",
2718
+ copyText: paymentAccountDetails?.accountNumber ?? ""
2719
+ }
2720
+ )
2721
+ ] }),
2722
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between", children: [
2723
+ /* @__PURE__ */ jsx28(BaseLabelInfo, { label: "Amount", value: formatAmountHandler }),
2724
+ /* @__PURE__ */ jsx28(BaseCopy, { color: "#9DBFDE", copyText: formatAmountHandler })
2725
+ ] })
2726
+ ] }),
2727
+ /* @__PURE__ */ jsxs18("p", { className: "w-2/3 mx-auto text-center text-body-2xs font-medium text-sub-copy", children: [
2728
+ "This account is for this transaction only and expires in",
2729
+ " ",
2730
+ /* @__PURE__ */ jsx28("span", { className: "text-orange-500", children: remainingSeconds >= 0 ? countDownTime : "00:00" })
1535
2731
  ] }),
1536
- /* @__PURE__ */ jsxs17("div", { className: "flex items-center justify-between", children: [
2732
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-4", children: [
1537
2733
  /* @__PURE__ */ jsx28(
1538
- BaseLabelInfo,
2734
+ BaseButton,
1539
2735
  {
1540
- label: "Amount",
1541
- value: amountDisplay,
1542
- type: "horizontal"
2736
+ label: "I have paid the money",
2737
+ type: "primary",
2738
+ customClass: "w-full",
2739
+ loading: isFetchingPaymentDetails,
2740
+ onClick: getReferenceDetails
1543
2741
  }
1544
2742
  ),
1545
- /* @__PURE__ */ jsx28(BaseCopy, { color: "#9DBFDE", copyText: amountDisplay })
2743
+ /* @__PURE__ */ jsx28(
2744
+ "button",
2745
+ {
2746
+ type: "button",
2747
+ onClick: onCancel,
2748
+ className: "text-heading-text text-body-2xs font-medium text-center py-2 cursor-pointer",
2749
+ children: "Cancel Payment"
2750
+ }
2751
+ )
1546
2752
  ] })
1547
- ] }),
1548
- /* @__PURE__ */ jsxs17("p", { className: "w-2/3 mx-auto text-center text-body-2xs font-medium text-sub-copy", children: [
1549
- "This account is for this transaction only and expires in",
1550
- " ",
1551
- /* @__PURE__ */ jsx28("span", { className: "text-orange-500", children: remaining >= 0 ? countDownTime : "00:00" })
1552
- ] }),
1553
- /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-4", children: [
1554
- /* @__PURE__ */ jsx28(
1555
- BaseButton,
1556
- {
1557
- label: "I have paid the money",
1558
- type: "primary",
1559
- customClass: "w-full",
1560
- onClick: onConfirmPaid
1561
- }
1562
- ),
1563
- /* @__PURE__ */ jsx28(
1564
- "button",
1565
- {
1566
- type: "button",
1567
- onClick: onCancel,
1568
- className: "text-heading-text text-body-2xs font-medium text-center py-2 cursor-pointer",
1569
- children: "Cancel Payment"
1570
- }
1571
- )
1572
2753
  ] })
1573
2754
  ] });
1574
2755
  };
1575
2756
 
1576
2757
  // src/components/pay-by-stable-coin.tsx
1577
- import { useState as useState6 } from "react";
1578
- import { Fragment as Fragment3, jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
1579
- var PayByStableCoin = ({ onProceedToPay }) => {
2758
+ import { useEffect as useEffect5, useState as useState6 } from "react";
2759
+ import { Fragment as Fragment3, jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
2760
+ var PayByStableCoin = ({
2761
+ secretKey,
2762
+ paymentObject,
2763
+ environment = "sandbox",
2764
+ onPaymentAuthorized,
2765
+ onError
2766
+ }) => {
1580
2767
  const [formIndex, setFormIndex] = useState6(0);
1581
- const payHandler = () => {
1582
- setFormIndex(1);
1583
- onProceedToPay?.();
2768
+ const [message, setMessage] = useState6("");
2769
+ const [loading, setLoading] = useState6(false);
2770
+ const [generatingAddress, setGeneratingAddress] = useState6(false);
2771
+ const [loadingStableCoins, setLoadingStableCoins] = useState6(false);
2772
+ const [loadingStableCoinNetworks, setLoadingStableCoinNetworks] = useState6(false);
2773
+ const [transactionReference, setTransactionReference] = useState6("");
2774
+ const [stableCoins, setStableCoins] = useState6([]);
2775
+ const [networkList, setNetworkList] = useState6([]);
2776
+ const [addressDetails, setAddressDetails] = useState6(null);
2777
+ const [generateAddressPayload, setGenerateAddressPayload] = useState6(null);
2778
+ const [isConfirmingPayment, setIsConfirmingPayment] = useState6(false);
2779
+ const [paymentReferenceDetails, setPaymentReferenceDetails] = useState6(null);
2780
+ const [paymentReferenceStatus, setPaymentReferenceStatus] = useState6("");
2781
+ const [stableCoinForm, setStableCoinForm] = useState6({
2782
+ stableCoin: "",
2783
+ network: ""
2784
+ });
2785
+ const [stableCoinErrors, setStableCoinErrors] = useState6({});
2786
+ const stableCoinRules = {
2787
+ stableCoin: "required",
2788
+ network: "required"
2789
+ };
2790
+ const stableCoinLabels = {
2791
+ stableCoin: "Stable Coin",
2792
+ network: "Network"
2793
+ };
2794
+ const generatePaymentLinkHandler = async () => {
2795
+ if (!secretKey) {
2796
+ setMessage("Secret key is required.");
2797
+ return;
2798
+ }
2799
+ if (!checkObjectTruthy(paymentObject)) {
2800
+ setMessage("Kindly ensure you are passing all the required data.");
2801
+ return;
2802
+ }
2803
+ setLoading(true);
2804
+ setMessage("");
2805
+ try {
2806
+ const response = await createPaymentLink(
2807
+ paymentObject,
2808
+ environment,
2809
+ secretKey
2810
+ );
2811
+ if (response?.isSuccessful && response.launchUrl) {
2812
+ const queryParams = getQueryParams(response.launchUrl);
2813
+ setTransactionReference(queryParams["paymentReference"]);
2814
+ setMessage("Payment link created successfully");
2815
+ } else {
2816
+ setMessage("Failed to create payment link");
2817
+ }
2818
+ } catch (e) {
2819
+ setMessage(e?.message || "Failed to create payment link");
2820
+ onError?.({
2821
+ errorMessage: message
2822
+ });
2823
+ } finally {
2824
+ setLoading(false);
2825
+ }
2826
+ };
2827
+ const generateAddress = async (payload) => {
2828
+ if (!payload) return;
2829
+ setGeneratingAddress(true);
2830
+ try {
2831
+ const response = await generateStableCoinAddress(
2832
+ environment,
2833
+ payload
2834
+ );
2835
+ if (response?.isSuccessful) {
2836
+ setAddressDetails(response.data);
2837
+ setFormIndex(1);
2838
+ }
2839
+ } catch (e) {
2840
+ setMessage(e?.message || "Failed to generate address");
2841
+ onError?.({
2842
+ errorMessage: message
2843
+ });
2844
+ } finally {
2845
+ setGeneratingAddress(false);
2846
+ }
2847
+ };
2848
+ const getAllStableCoins = async () => {
2849
+ setLoadingStableCoins(true);
2850
+ try {
2851
+ const response = await getStableCoins(environment);
2852
+ if (response?.isSuccessful) {
2853
+ setStableCoins(
2854
+ response.data?.map((c) => ({
2855
+ label: c.name,
2856
+ value: c.name
2857
+ })) ?? []
2858
+ );
2859
+ }
2860
+ } catch (e) {
2861
+ setMessage(e?.message || "Failed to get stable coins");
2862
+ onError?.({
2863
+ errorMessage: message
2864
+ });
2865
+ } finally {
2866
+ setLoadingStableCoins(false);
2867
+ }
2868
+ };
2869
+ const getAllStableCoinNetworks = async (stableCoin) => {
2870
+ setLoadingStableCoinNetworks(true);
2871
+ try {
2872
+ const response = await getStableCoinNetworks(
2873
+ environment,
2874
+ stableCoin
2875
+ );
2876
+ if (response?.isSuccessful) {
2877
+ setNetworkList(
2878
+ response.networks?.map((n) => ({
2879
+ label: n,
2880
+ value: n
2881
+ })) ?? []
2882
+ );
2883
+ }
2884
+ } catch (e) {
2885
+ setMessage(e?.message || "Failed to get stable coin networks");
2886
+ onError?.({
2887
+ errorMessage: message
2888
+ });
2889
+ } finally {
2890
+ setLoadingStableCoinNetworks(false);
2891
+ }
2892
+ };
2893
+ const confirmPaymentHandler = async () => {
2894
+ setIsConfirmingPayment(true);
2895
+ try {
2896
+ const response = await getPaymentReferenceDetails(environment, transactionReference);
2897
+ if (response?.isSuccessful) {
2898
+ setPaymentReferenceDetails(response.data);
2899
+ const needsConfirm = response.data?.finalTransactionStatus == null || response.data?.paymentStatus == null;
2900
+ if (needsConfirm) {
2901
+ setMessage("Transaction not confirmed !!");
2902
+ setPaymentReferenceStatus("pending");
2903
+ onPaymentAuthorized?.({
2904
+ paymentId: transactionReference,
2905
+ paymentDate: response.data?.updatedAt ?? "",
2906
+ paymentStatus: "pending",
2907
+ message
2908
+ });
2909
+ } else if (response.data?.finalTransactionStatus === "Success" || response.data?.paymentStatus === "Payment Received") {
2910
+ setMessage("Transaction confirmed !!");
2911
+ setPaymentReferenceStatus("confirmed");
2912
+ onPaymentAuthorized?.({
2913
+ paymentId: transactionReference,
2914
+ paymentDate: response.data?.updatedAt,
2915
+ paymentStatus: "confirmed",
2916
+ message
2917
+ });
2918
+ }
2919
+ } else if (!response?.isSuccessful && response?.responseCode === "119") {
2920
+ setPaymentReferenceStatus("used");
2921
+ setMessage(response.responseMessage || "");
2922
+ onPaymentAuthorized?.({
2923
+ paymentId: transactionReference,
2924
+ paymentDate: null,
2925
+ paymentStatus: "used",
2926
+ message
2927
+ });
2928
+ }
2929
+ } catch (err) {
2930
+ setPaymentReferenceStatus("");
2931
+ setMessage(
2932
+ err?.error?.responseMessage || err?.error?.message || "Something went wrong"
2933
+ );
2934
+ onError?.({
2935
+ errorMessage: message
2936
+ });
2937
+ } finally {
2938
+ setIsConfirmingPayment(false);
2939
+ }
2940
+ };
2941
+ const formatAmountHandler = formatAmount(
2942
+ paymentObject.amount,
2943
+ paymentObject.currency
2944
+ );
2945
+ const payHandler = async () => {
2946
+ const errs = validateGroup(
2947
+ stableCoinForm,
2948
+ stableCoinRules,
2949
+ stableCoinLabels
2950
+ );
2951
+ setStableCoinErrors(errs);
2952
+ if (Object.keys(errs).length === 0) {
2953
+ const payload = {
2954
+ paymentReference: transactionReference,
2955
+ currency: stableCoinForm.stableCoin,
2956
+ chain: stableCoinForm.network,
2957
+ transactionAmount: paymentObject.amount,
2958
+ merchantId: secretKey
2959
+ };
2960
+ setGenerateAddressPayload(payload);
2961
+ await generateAddress(payload);
2962
+ } else {
2963
+ return;
2964
+ }
1584
2965
  };
1585
- return /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-6", children: [
1586
- formIndex === 0 && /* @__PURE__ */ jsxs18(Fragment3, { children: [
1587
- /* @__PURE__ */ jsxs18("div", { className: "grid grid-cols-1 gap-6", children: [
2966
+ const amountPlusNetworkFee = addressDetails ? Number(addressDetails.transactionAmount) + addressDetails.networkFee : 0;
2967
+ useEffect5(() => {
2968
+ (async () => {
2969
+ await generatePaymentLinkHandler();
2970
+ await getAllStableCoins();
2971
+ })();
2972
+ }, []);
2973
+ return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-6", children: [
2974
+ formIndex === 0 && /* @__PURE__ */ jsxs19(Fragment3, { children: [
2975
+ /* @__PURE__ */ jsxs19("div", { className: "grid grid-cols-1 gap-6", children: [
1588
2976
  /* @__PURE__ */ jsx29(
1589
2977
  BaseSelect,
1590
2978
  {
1591
2979
  label: "Select Crypto",
1592
2980
  required: true,
1593
- options: [
1594
- { label: "USDT", value: "USDT" },
1595
- { label: "USDC", value: "USDC" },
1596
- { label: "BUSD", value: "BUSD" }
1597
- ]
2981
+ options: stableCoins,
2982
+ loading: loadingStableCoins,
2983
+ value: stableCoinForm.stableCoin,
2984
+ onChange: (e) => {
2985
+ setStableCoinForm({ ...stableCoinForm, stableCoin: e });
2986
+ getAllStableCoinNetworks(e);
2987
+ if (stableCoinErrors.stableCoin) {
2988
+ setStableCoinErrors((er) => ({ ...er, stableCoin: "" }));
2989
+ }
2990
+ },
2991
+ validationError: stableCoinErrors.stableCoin ?? ""
1598
2992
  }
1599
2993
  ),
1600
2994
  /* @__PURE__ */ jsx29(
@@ -1602,52 +2996,46 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1602
2996
  {
1603
2997
  label: "Select Network",
1604
2998
  required: true,
1605
- options: [
1606
- { label: "Ethereum", value: "ETH" },
1607
- { label: "Binance Smart Chain", value: "BSC" },
1608
- { label: "Polygon", value: "MATIC" }
1609
- ]
2999
+ options: networkList,
3000
+ loading: loadingStableCoinNetworks,
3001
+ value: stableCoinForm.network,
3002
+ onChange: (e) => {
3003
+ setStableCoinForm({ ...stableCoinForm, network: e });
3004
+ if (stableCoinErrors.network) {
3005
+ setStableCoinErrors((er) => ({ ...er, network: "" }));
3006
+ }
3007
+ },
3008
+ validationError: stableCoinErrors.network ?? ""
1610
3009
  }
1611
3010
  )
1612
3011
  ] }),
1613
3012
  /* @__PURE__ */ jsx29(
1614
3013
  BaseButton,
1615
3014
  {
1616
- label: "Pay",
3015
+ label: `Pay ${formatAmountHandler}`,
1617
3016
  type: "primary",
1618
3017
  customClass: "w-full",
3018
+ loading: generatingAddress,
1619
3019
  onClick: payHandler
1620
3020
  }
1621
3021
  )
1622
3022
  ] }),
1623
- formIndex === 1 && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-6", children: [
1624
- /* @__PURE__ */ jsxs18("div", { className: "mx-auto", children: [
1625
- /* @__PURE__ */ jsx29(
1626
- BaseImage,
1627
- {
1628
- src: "../../../assets/images/stable-coin-qr-code.png",
1629
- alt: "QR Code",
1630
- width: 122,
1631
- height: 122,
1632
- customClass: "mb-1"
1633
- }
1634
- ),
1635
- /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-4xs text-light-copy font-normal text-center", children: "USDC" })
1636
- ] }),
1637
- /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-6 border-c border-grey-100 p-4 rounded-2xl bg-light-white-50", children: [
1638
- /* @__PURE__ */ jsxs18("div", { className: "border-b border-grey-border pb-4 flex flex-col gap-2", children: [
3023
+ formIndex === 1 && /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-6", children: [
3024
+ /* @__PURE__ */ jsx29("div", { className: "mx-auto", children: /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-4xs text-light-copy font-normal text-center", children: generateAddressPayload?.currency }) }),
3025
+ /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-6 border-c border-grey-100 p-4 rounded-2xl bg-light-white-50", children: [
3026
+ /* @__PURE__ */ jsxs19("div", { className: "border-b border-grey-border pb-4 flex flex-col gap-2", children: [
1639
3027
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-3xs text-light-copy font-normal", children: "Network" }),
1640
- /* @__PURE__ */ jsxs18("div", { className: "flex justify-between", children: [
1641
- /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-1", children: [
1642
- /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-2xs font-medium text-sub-copy", children: "BNB Smart Chain (BEP20)" }),
1643
- /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-2", children: [
3028
+ /* @__PURE__ */ jsxs19("div", { className: "flex justify-between", children: [
3029
+ /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-1", children: [
3030
+ /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-2xs font-medium text-sub-copy", children: addressDetails?.chain }),
3031
+ /* @__PURE__ */ jsxs19("div", { className: "flex items-center gap-2", children: [
1644
3032
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-3xs text-light-copy font-normal", children: "*Est. arrival = 3 mins" }),
1645
3033
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-3xs text-light-copy font-normal", children: "|" }),
1646
3034
  /* @__PURE__ */ jsx29(
1647
3035
  BaseCurrencyAmount,
1648
3036
  {
1649
- currency: "USDC",
1650
- amount: 10,
3037
+ currency: generateAddressPayload?.currency ?? "",
3038
+ amount: addressDetails?.networkFee ?? 0,
1651
3039
  textClass: "mb-0 text-body-3xs text-light-copy font-normal",
1652
3040
  iconColorClass: "#557591",
1653
3041
  iconWidth: 12,
@@ -1659,34 +3047,34 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1659
3047
  /* @__PURE__ */ jsx29(IconArrowSwap, {})
1660
3048
  ] })
1661
3049
  ] }),
1662
- /* @__PURE__ */ jsxs18("div", { className: "pb-4 flex flex-col gap-2", children: [
3050
+ /* @__PURE__ */ jsxs19("div", { className: "pb-4 flex flex-col gap-2", children: [
1663
3051
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-3xs text-light-copy font-normal", children: "Deposit Address >" }),
1664
- /* @__PURE__ */ jsxs18("div", { className: "flex justify-between", children: [
1665
- /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-2xs font-medium text-sub-copy w-2/3 break-words", children: "0j8938ysheeee8333c162883a4d4f5g6t111nhk8uey37777yt6" }),
1666
- /* @__PURE__ */ jsx29(BaseCopy, { copyText: "0j8938ysheeee8333c162883a4d4f5g6t111nhk8uey37777yt6" })
3052
+ /* @__PURE__ */ jsxs19("div", { className: "flex justify-between", children: [
3053
+ /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-2xs font-medium text-sub-copy w-2/3 break-words", children: addressDetails?.walletAddress }),
3054
+ /* @__PURE__ */ jsx29(BaseCopy, { copyText: addressDetails?.walletAddress ?? "" })
1667
3055
  ] })
1668
3056
  ] })
1669
3057
  ] }),
1670
- /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-2", children: [
1671
- /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between border-b border-grey-border py-3", children: [
3058
+ /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-2", children: [
3059
+ /* @__PURE__ */ jsxs19("div", { className: "flex items-center justify-between border-b border-grey-border py-3", children: [
1672
3060
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-2xs font-medium text-primary-black", children: "Network fee" }),
1673
3061
  /* @__PURE__ */ jsx29(
1674
3062
  BaseCurrencyAmount,
1675
3063
  {
1676
- currency: "USDC",
1677
- amount: 12,
3064
+ currency: generateAddressPayload?.currency ?? "",
3065
+ amount: addressDetails?.networkFee ?? 0,
1678
3066
  textClass: "mb-0 text-body-2xs font-extrabold text-primary-black",
1679
3067
  iconColorClass: "#231F20"
1680
3068
  }
1681
3069
  )
1682
3070
  ] }),
1683
- /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between py-4", children: [
3071
+ /* @__PURE__ */ jsxs19("div", { className: "flex items-center justify-between py-4", children: [
1684
3072
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-lg font-semibold text-primary-black", children: "Pay" }),
1685
3073
  /* @__PURE__ */ jsx29(
1686
3074
  BaseCurrencyAmount,
1687
3075
  {
1688
- currency: "USDC",
1689
- amount: 15,
3076
+ currency: generateAddressPayload?.currency ?? "",
3077
+ amount: amountPlusNetworkFee,
1690
3078
  textClass: "mb-0 text-body-lg font-extrabold text-primary-black",
1691
3079
  iconColorClass: "#231F20",
1692
3080
  iconWidth: 20,
@@ -1700,7 +3088,9 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1700
3088
  {
1701
3089
  label: "Confirm Payment",
1702
3090
  type: "primary",
1703
- customClass: "w-full"
3091
+ customClass: "w-full",
3092
+ loading: isConfirmingPayment,
3093
+ onClick: confirmPaymentHandler
1704
3094
  }
1705
3095
  ) })
1706
3096
  ] })
@@ -1708,97 +3098,159 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1708
3098
  };
1709
3099
 
1710
3100
  // src/buzapay-checkout/checkout-card.tsx
1711
- import { jsx as jsx30, jsxs as jsxs19 } from "react/jsx-runtime";
3101
+ import { jsx as jsx30, jsxs as jsxs20 } from "react/jsx-runtime";
1712
3102
  function BzpCheckoutCard({
3103
+ secretKey,
1713
3104
  options,
1714
3105
  environment = "sandbox",
1715
3106
  paymentObject = {
3107
+ merchantName: "",
1716
3108
  amount: 0,
1717
3109
  currency: "",
1718
3110
  email: "",
1719
3111
  phoneNumber: "",
1720
3112
  narration: "",
1721
- redirectUrl: ""
1722
- }
3113
+ redirectUrl: "https://sandbox-merchant.buzapay.com/account/three-ds-status"
3114
+ },
3115
+ onPaymentAuthorized,
3116
+ onError
1723
3117
  }) {
1724
- const [checkoutState, setCheckoutState] = useState7("PAYMENT");
3118
+ const [checkoutState, setCheckoutState] = useState7("PENDING");
1725
3119
  const paymentTypeOptions = [
1726
3120
  { label: "Card", value: "CARD" },
1727
3121
  { label: "Bank Transfer", value: "BANK_TRANSFER" },
1728
3122
  { label: "Stable Coin", value: "STABLE_COIN" }
1729
3123
  ];
1730
3124
  const [filteredPaymentTypeOptions, setFilteredPaymentTypeOptions] = useState7([]);
1731
- const [paymentType, setPaymentType] = useState7(
1732
- filteredPaymentTypeOptions[0].value
1733
- );
3125
+ const [paymentType, setPaymentType] = useState7("");
3126
+ const [successObject, setSuccessObject] = useState7({
3127
+ paymentDate: "",
3128
+ paymentId: "",
3129
+ paymentStatus: ""
3130
+ });
1734
3131
  const paymentTypeHandler = (event) => {
1735
3132
  setPaymentType(event);
1736
3133
  };
1737
- useEffect4(() => {
3134
+ const setSuccess = (event) => {
3135
+ setSuccessObject({ ...event });
3136
+ if (event.paymentStatus === "Authorized") {
3137
+ setCheckoutState("SUCCESS");
3138
+ } else if (event.paymentStatus === "Payment failed") {
3139
+ setCheckoutState("PENDING");
3140
+ } else if (event.paymentStatus === "used") {
3141
+ setCheckoutState("USED");
3142
+ } else {
3143
+ setCheckoutState("PENDING");
3144
+ }
3145
+ onPaymentAuthorized?.(event);
3146
+ };
3147
+ useEffect6(() => {
1738
3148
  let options2 = [];
1739
3149
  if (paymentObject.currency === "USD") {
1740
- options2 = paymentTypeOptions.filter(
1741
- (option) => option.value !== "BANK_TRANSFER"
1742
- );
3150
+ if (paymentObject.amount < 50) {
3151
+ options2 = paymentTypeOptions.filter(
3152
+ (option) => option.value !== "BANK_TRANSFER" && option.value !== "STABLE_COIN"
3153
+ );
3154
+ } else {
3155
+ options2 = paymentTypeOptions.filter(
3156
+ (option) => option.value !== "BANK_TRANSFER"
3157
+ );
3158
+ }
1743
3159
  } else {
1744
3160
  options2 = paymentTypeOptions.filter(
1745
3161
  (option) => option.value !== "STABLE_COIN"
1746
3162
  );
1747
3163
  }
1748
3164
  setFilteredPaymentTypeOptions(options2);
1749
- }, [paymentObject.currency]);
1750
- return /* @__PURE__ */ jsx30(BaseCard, { showBackButton: checkoutState === "STABLE_COIN_PAYMENT", children: /* @__PURE__ */ jsxs19("div", { className: "grid grid-cols-3", children: [
1751
- checkoutState === "PAYMENT" && /* @__PURE__ */ jsxs19("div", { className: "bg-[#EFF7FF] px-6 py-8 flex flex-col gap-5 col-span-1 rounded-l-xl", children: [
3165
+ }, [paymentObject.currency, paymentObject.amount]);
3166
+ useEffect6(() => {
3167
+ if (filteredPaymentTypeOptions.length) {
3168
+ setPaymentType(filteredPaymentTypeOptions[0].value);
3169
+ }
3170
+ }, [filteredPaymentTypeOptions]);
3171
+ return /* @__PURE__ */ jsx30(BaseCard, { children: /* @__PURE__ */ jsxs20("div", { className: "grid grid-cols-3", children: [
3172
+ checkoutState === "PENDING" && /* @__PURE__ */ jsxs20("div", { className: "bg-[#EFF7FF] px-6 py-8 flex flex-col gap-5 col-span-1 rounded-l-xl", children: [
1752
3173
  /* @__PURE__ */ jsx30("p", { className: "text-heading-text text-body-xs font-semibold", children: "Pay with" }),
1753
3174
  /* @__PURE__ */ jsx30(
1754
3175
  BaseRadioGroup,
1755
3176
  {
1756
- options: paymentTypeOptions,
3177
+ options: filteredPaymentTypeOptions,
1757
3178
  selectedChange: (e) => paymentTypeHandler(e)
1758
3179
  }
1759
3180
  )
1760
3181
  ] }),
1761
- /* @__PURE__ */ jsxs19("div", { className: "col-span-2", children: [
1762
- (checkoutState === "PAYMENT" || checkoutState === "STABLE_COIN_PAYMENT") && /* @__PURE__ */ jsxs19("div", { children: [
1763
- checkoutState === "PAYMENT" && /* @__PURE__ */ jsxs19("div", { className: "flex items-center justify-between px-12 py-8", children: [
1764
- options?.imageUrl ? /* @__PURE__ */ jsx30(
1765
- BaseImage,
3182
+ /* @__PURE__ */ jsxs20(
3183
+ "div",
3184
+ {
3185
+ className: checkoutState === "SUCCESS" ? "col-span-3" : "col-span-2",
3186
+ children: [
3187
+ checkoutState === "PENDING" && /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-between px-12 py-8", children: [
3188
+ options?.imageUrl ? /* @__PURE__ */ jsx30(
3189
+ BaseImage,
3190
+ {
3191
+ src: options?.imageUrl ?? "",
3192
+ alt: "Merchant Logo",
3193
+ width: 52,
3194
+ height: 52,
3195
+ customClass: "rounded-lg"
3196
+ }
3197
+ ) : /* @__PURE__ */ jsx30(
3198
+ "div",
3199
+ {
3200
+ className: "bg-heading-text rounded flex flex-col justify-center",
3201
+ style: { width: "52px", height: "52px" },
3202
+ children: /* @__PURE__ */ jsx30("p", { className: "text-white text-center text-body-2xs font-medium", children: "Logo" })
3203
+ }
3204
+ ),
3205
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-1", children: [
3206
+ /* @__PURE__ */ jsx30("p", { className: "text-body-2xs font-regular text-sub-copy text-right", children: paymentObject.merchantName }),
3207
+ /* @__PURE__ */ jsxs20("p", { className: "text-body-2xs font-regular text-sub-copy text-right", children: [
3208
+ "Pay:",
3209
+ " ",
3210
+ /* @__PURE__ */ jsx30("span", { className: "text-orange-500 font-extrabold", children: formatAmount(paymentObject.amount, paymentObject.currency) })
3211
+ ] })
3212
+ ] })
3213
+ ] }),
3214
+ checkoutState === "PENDING" && /* @__PURE__ */ jsx30("div", { className: "overflow-y-scroll px-10 pb-10 pt-2", children: paymentType === "CARD" ? /* @__PURE__ */ jsx30(
3215
+ PayByCard,
3216
+ {
3217
+ secretKey,
3218
+ environment,
3219
+ paymentObject,
3220
+ onPaymentAuthorized: setSuccess,
3221
+ onError
3222
+ }
3223
+ ) : paymentType === "BANK_TRANSFER" ? /* @__PURE__ */ jsx30(
3224
+ PayByTransfer,
1766
3225
  {
1767
- src: options?.imageUrl ?? "",
1768
- alt: "Merchant Logo",
1769
- width: 52,
1770
- height: 52,
1771
- customClass: "rounded-lg"
3226
+ secretKey,
3227
+ environment,
3228
+ paymentObject,
3229
+ onPaymentAuthorized: setSuccess,
3230
+ onError
1772
3231
  }
1773
3232
  ) : /* @__PURE__ */ jsx30(
1774
- "div",
3233
+ PayByStableCoin,
1775
3234
  {
1776
- className: "bg-heading-text rounded flex flex-col justify-center",
1777
- style: { width: "52px", height: "52px" },
1778
- children: /* @__PURE__ */ jsx30("p", { className: "text-white text-center text-body-2xs font-medium", children: "Logo" })
3235
+ secretKey,
3236
+ environment,
3237
+ paymentObject,
3238
+ onPaymentAuthorized: setSuccess,
3239
+ onError
1779
3240
  }
1780
- ),
1781
- /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-1", children: [
1782
- /* @__PURE__ */ jsx30("p", { className: "text-body-2xs font-regular text-sub-copy text-right", children: "Raymahni Merchant LLC" }),
1783
- /* @__PURE__ */ jsxs19("p", { className: "text-body-2xs font-regular text-sub-copy text-right", children: [
1784
- "Pay:",
1785
- " ",
1786
- /* @__PURE__ */ jsxs19("span", { className: "text-orange-500 font-extrabold", children: [
1787
- currencySign(paymentObject.currency),
1788
- " 100,051.00"
1789
- ] })
1790
- ] })
1791
- ] })
1792
- ] }),
1793
- /* @__PURE__ */ jsx30("div", { className: "overflow-y-scroll px-10 pb-10 pt-2", children: paymentType === "CARD" ? /* @__PURE__ */ jsx30(PayByCard, {}) : paymentType === "BANK_TRANSFER" ? /* @__PURE__ */ jsx30(PayByTransfer, {}) : /* @__PURE__ */ jsx30(
1794
- PayByStableCoin,
1795
- {
1796
- onProceedToPay: () => setCheckoutState("STABLE_COIN_PAYMENT")
1797
- }
1798
- ) })
1799
- ] }),
1800
- checkoutState === "SUCCESS" && /* @__PURE__ */ jsx30(BaseSuccess, {})
1801
- ] })
3241
+ ) }),
3242
+ checkoutState === "SUCCESS" && /* @__PURE__ */ jsx30(
3243
+ BaseSuccess,
3244
+ {
3245
+ amount: paymentObject.amount,
3246
+ currency: paymentObject.currency,
3247
+ redirectUrl: paymentObject.redirectUrl ?? "",
3248
+ successObject
3249
+ }
3250
+ )
3251
+ ]
3252
+ }
3253
+ )
1802
3254
  ] }) });
1803
3255
  }
1804
3256
  export {