@miden-npm/react 0.0.6 → 0.0.7

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,6 +71,14 @@ 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) => {
@@ -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 {
@@ -149,6 +397,181 @@ async function createPaymentLink(paymentObject, environment, secretKey) {
149
397
  } catch (error) {
150
398
  }
151
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`,
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(environment, formData = {}) {
478
+ const baseUrl = getBaseUrl(environment);
479
+ const key = CryptoJS.enc.Utf8.parse(baseUrl);
480
+ const iv = CryptoJS.enc.Utf8.parse(baseUrl);
481
+ const postDataObj = JSON.stringify(formData);
482
+ const encryptedData = CryptoJS.AES.encrypt(
483
+ CryptoJS.enc.Utf8.parse(postDataObj),
484
+ key,
485
+ {
486
+ keySize: 128 / 8,
487
+ iv,
488
+ mode: CryptoJS.mode.CBC,
489
+ padding: CryptoJS.pad.Pkcs7
490
+ }
491
+ );
492
+ return {
493
+ requestParam: encryptedData.toString()
494
+ };
495
+ }
496
+ function decryptPayload(environment, payload) {
497
+ const baseUrl = getBaseUrl(environment);
498
+ const key = CryptoJS.enc.Utf8.parse(baseUrl);
499
+ const iv = CryptoJS.enc.Utf8.parse(baseUrl);
500
+ const decryptedData = CryptoJS.AES.decrypt(payload, key, {
501
+ keySize: 128 / 8,
502
+ iv,
503
+ mode: CryptoJS.mode.CBC,
504
+ padding: CryptoJS.pad.Pkcs7
505
+ });
506
+ const decryptedText = decryptedData.toString(CryptoJS.enc.Utf8);
507
+ return JSON.parse(decryptedText);
508
+ }
509
+
510
+ // src/apis/resources.api.ts
511
+ async function getCountries(environment, secretKey) {
512
+ try {
513
+ const baseUrl = getBaseUrl(environment);
514
+ const res = await fetch(`${baseUrl}/api/v1/countries-iso`, {
515
+ method: "GET",
516
+ headers: {
517
+ "Content-Type": "application/json",
518
+ Accept: "application/json",
519
+ merchantId: secretKey
520
+ }
521
+ });
522
+ return await res.json();
523
+ } catch (error) {
524
+ }
525
+ }
526
+ async function getCountryStates(countryIso3, environment, secretKey) {
527
+ try {
528
+ const baseUrl = getBaseUrl(environment);
529
+ const res = await fetch(
530
+ `${baseUrl}/api/v1/state-by-country/${countryIso3}`,
531
+ {
532
+ method: "GET",
533
+ headers: {
534
+ "Content-Type": "application/json",
535
+ Accept: "application/json",
536
+ merchantId: secretKey
537
+ }
538
+ }
539
+ );
540
+ return await res.json();
541
+ } catch (error) {
542
+ }
543
+ }
544
+ async function getStableCoins(environment) {
545
+ try {
546
+ const baseUrl = getBaseUrl(environment);
547
+ const res = await fetch(`${baseUrl}/api/v1/checkout/stable-coin`, {
548
+ method: "GET",
549
+ headers: {
550
+ "Content-Type": "application/json",
551
+ Accept: "application/json"
552
+ }
553
+ });
554
+ return await res.json();
555
+ } catch (error) {
556
+ }
557
+ }
558
+ async function getStableCoinNetworks(environment, stableCoin) {
559
+ try {
560
+ const baseUrl = getBaseUrl(environment);
561
+ const res = await fetch(
562
+ `${baseUrl}/api/v1/checkout/networks/${stableCoin}`,
563
+ {
564
+ method: "GET",
565
+ headers: {
566
+ "Content-Type": "application/json",
567
+ Accept: "application/json"
568
+ }
569
+ }
570
+ );
571
+ return await res.json();
572
+ } catch (error) {
573
+ }
574
+ }
152
575
 
153
576
  // src/components/base/input-error.tsx
154
577
  import { jsx as jsx2 } from "react/jsx-runtime";
@@ -800,13 +1223,33 @@ var BaseLabelInfo = ({
800
1223
 
801
1224
  // src/components/base/success.tsx
802
1225
  import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
803
- var BaseSuccess = ({}) => {
1226
+ var BaseSuccess = ({
1227
+ amount,
1228
+ currency,
1229
+ redirectUrl,
1230
+ successObject = {
1231
+ paymentDate: "",
1232
+ paymentId: "",
1233
+ paymentStatus: ""
1234
+ }
1235
+ }) => {
1236
+ const formatAmountHandler = formatAmount(amount, currency);
1237
+ const goToRedirectUrl = () => {
1238
+ window.open(redirectUrl, "_self", "noopener,noreferrer");
1239
+ };
1240
+ const paymentDate = new Date(
1241
+ successObject.paymentDate ?? ""
1242
+ ).toLocaleDateString("en-US", {
1243
+ year: "numeric",
1244
+ month: "long",
1245
+ day: "2-digit"
1246
+ });
804
1247
  return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-8 p-16", children: [
805
1248
  /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-8", children: [
806
1249
  /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-8", children: [
807
1250
  /* @__PURE__ */ jsx20(IconCheckCircle, { color: "#F47A1F", className: "mx-auto" }),
808
1251
  /* @__PURE__ */ jsxs11("div", { className: "flex flex-col text-center", style: { gap: "2px" }, children: [
809
- /* @__PURE__ */ jsx20("p", { className: "text-heading-text font-medium text-header-2xl", children: "\u20A62,500.00" }),
1252
+ /* @__PURE__ */ jsx20("p", { className: "text-heading-text font-medium text-header-2xl", children: formatAmountHandler }),
810
1253
  /* @__PURE__ */ jsx20("p", { className: "text-sub-copy font-regular text-body-3xs", children: "Has been paid successfully" })
811
1254
  ] })
812
1255
  ] }),
@@ -816,7 +1259,7 @@ var BaseSuccess = ({}) => {
816
1259
  {
817
1260
  type: "horizontal",
818
1261
  label: "Order ID",
819
- value: "9900009000-8890-8829hd7"
1262
+ value: successObject.paymentId
820
1263
  }
821
1264
  ) }),
822
1265
  /* @__PURE__ */ jsx20("div", { className: "py-4", children: /* @__PURE__ */ jsx20(
@@ -824,7 +1267,7 @@ var BaseSuccess = ({}) => {
824
1267
  {
825
1268
  type: "horizontal",
826
1269
  label: "Payment date",
827
- value: "July 24, 2025"
1270
+ value: paymentDate
828
1271
  }
829
1272
  ) })
830
1273
  ] })
@@ -834,7 +1277,8 @@ var BaseSuccess = ({}) => {
834
1277
  {
835
1278
  label: "Return to Merchant Website",
836
1279
  type: "secondary",
837
- customClass: "w-full"
1280
+ customClass: "w-full",
1281
+ onClick: goToRedirectUrl
838
1282
  }
839
1283
  ) })
840
1284
  ] });
@@ -854,6 +1298,7 @@ var BaseSelect = ({
854
1298
  value,
855
1299
  defaultValue,
856
1300
  onChange,
1301
+ onBlur,
857
1302
  placeholder = "Select an option",
858
1303
  hasSearch = true,
859
1304
  disabled = false,
@@ -926,6 +1371,7 @@ var BaseSelect = ({
926
1371
  const commit = (val) => {
927
1372
  if (!isControlled) setInternalValue(val);
928
1373
  onChange?.(val);
1374
+ onBlur?.(val);
929
1375
  closeMenu();
930
1376
  };
931
1377
  const onSearchInput = (e) => {
@@ -1076,6 +1522,7 @@ var BaseSelect = ({
1076
1522
  ref: searchRef,
1077
1523
  type: "text",
1078
1524
  onChange: onSearchInput,
1525
+ onBlur: onSearchInput,
1079
1526
  placeholder: `Search ${label || "options"}`,
1080
1527
  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"
1081
1528
  }
@@ -1150,96 +1597,216 @@ var BaseCurrencyAmount = ({
1150
1597
  ] });
1151
1598
  };
1152
1599
 
1153
- // src/buzapay-checkout/checkout-iframe.tsx
1154
- import { useCallback as useCallback2, useEffect as useEffect2, useRef, useState as useState2 } from "react";
1155
- import { jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
1156
- function BzpCheckoutIframe({
1157
- style = {
1158
- width: "100%",
1159
- height: "100vh",
1160
- border: "0",
1161
- borderRadius: "6px",
1162
- overflow: "hidden"
1163
- },
1164
- url,
1165
- secretKey,
1166
- environment = "sandbox",
1167
- paymentObject = {
1168
- amount: 0,
1169
- currency: "",
1170
- email: "",
1171
- phoneNumber: "",
1172
- narration: "",
1173
- redirectUrl: ""
1174
- }
1175
- }) {
1176
- const containerRef = useRef(null);
1177
- const iframeRef = useRef(null);
1178
- const [message, setMessage] = useState2("");
1179
- const [launchUrl, setLaunchUrl] = useState2("");
1180
- const [loading, setLoading] = useState2(false);
1181
- const launchIframe = useCallback2(
1182
- (url2) => {
1183
- if (iframeRef.current && iframeRef.current.parentNode) {
1184
- iframeRef.current.parentNode.removeChild(iframeRef.current);
1185
- }
1186
- const iframe = document.createElement("iframe");
1187
- iframe.src = url2;
1188
- if (style.width) iframe.style.width = style.width;
1189
- if (style.height) iframe.style.height = style.height;
1190
- if (style.border) iframe.style.border = style.border;
1191
- if (style.borderRadius) iframe.style.borderRadius = style.borderRadius;
1192
- if (style.overflow) iframe.style.overflow = style.overflow;
1193
- containerRef.current?.appendChild(iframe);
1194
- iframeRef.current = iframe;
1195
- },
1196
- [style]
1600
+ // src/components/base/input.tsx
1601
+ import React4 from "react";
1602
+ import { IMaskInput } from "react-imask";
1603
+ import { Fragment as Fragment2, jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
1604
+ var BaseInput = ({
1605
+ label = "",
1606
+ type = "text",
1607
+ mask,
1608
+ placeholder,
1609
+ validationError = "",
1610
+ hint = "",
1611
+ rules = [],
1612
+ isAmountInput = false,
1613
+ required = false,
1614
+ disabled = false,
1615
+ loading = false,
1616
+ showCopyIcon = false,
1617
+ value,
1618
+ defaultValue,
1619
+ onChange,
1620
+ onBlur,
1621
+ prefix,
1622
+ suffix,
1623
+ className = ""
1624
+ }) => {
1625
+ const isControlled = value !== void 0;
1626
+ const [rawValue, setRawValue] = React4.useState(
1627
+ defaultValue ?? value ?? ""
1197
1628
  );
1198
- const generatePaymentLinkHandler = async () => {
1199
- if (url) {
1200
- launchIframe(url);
1201
- return;
1202
- }
1203
- if (!secretKey) {
1204
- return setMessage("Secret key is required.");
1205
- }
1206
- if (!checkObjectTruthy(paymentObject)) {
1207
- return setMessage("Secret key is required.");
1208
- }
1209
- setLoading(true);
1210
- const response = await createPaymentLink(
1211
- paymentObject,
1212
- environment,
1213
- secretKey
1214
- );
1215
- if (response?.isSuccessful) {
1216
- setLaunchUrl(response.launchUrl ?? "");
1217
- setMessage("Payment link created successfully");
1218
- if (response.launchUrl) {
1219
- setLoading(false);
1220
- launchIframe(response.launchUrl);
1221
- }
1222
- } else {
1223
- setLoading(false);
1224
- setMessage("Failed to create payment link");
1629
+ const [localHint, setLocalHint] = React4.useState("");
1630
+ const [localError, setLocalError] = React4.useState("");
1631
+ React4.useEffect(() => {
1632
+ if (isControlled) setRawValue(value ?? "");
1633
+ }, [isControlled, value]);
1634
+ const formattedValue = isAmountInput ? formatAmount(rawValue.replace(/,/g, "")) : rawValue;
1635
+ const handleChange = (e) => {
1636
+ const incoming = e.target.value.replace(/,/g, "");
1637
+ if (!isControlled) setRawValue(incoming);
1638
+ onChange?.(incoming);
1639
+ setTimeout(() => {
1640
+ const el = e.target;
1641
+ el.selectionStart = el.selectionEnd = el.value.length;
1642
+ });
1643
+ };
1644
+ const handleStringChange = (e) => {
1645
+ const incoming = e.replace(/,/g, "");
1646
+ if (!isControlled) setRawValue(incoming);
1647
+ onChange?.(incoming);
1648
+ };
1649
+ const handleBlur = () => {
1650
+ onBlur?.(rawValue);
1651
+ };
1652
+ const handleKeyDown = (e) => {
1653
+ if (rules.includes("numeric")) restrictToNumericKeys(e);
1654
+ };
1655
+ const containerBg = disabled ? "bg-grey-50 cursor-not-allowed" : "bg-white";
1656
+ const containerBorder = validationError || localError ? "border-red-300 bg-red-50" : "border-grey-100";
1657
+ const copyToClipboard = (text) => {
1658
+ return navigator.clipboard.writeText(text);
1659
+ };
1660
+ const copyHandler = () => {
1661
+ copyToClipboard(rawValue).then(() => {
1662
+ setLocalHint("Text copied to clipboard");
1663
+ }).catch((err) => {
1664
+ setLocalError("Failed to copy text to clipboard");
1665
+ });
1666
+ };
1667
+ return /* @__PURE__ */ jsxs14("div", { className: `flex flex-col gap-2 ${className}`, children: [
1668
+ label ? /* @__PURE__ */ jsxs14("p", { className: "mb-0 text-body-2xs font-normal text-heading-text", children: [
1669
+ label,
1670
+ required && /* @__PURE__ */ jsx24("span", { className: "text-orange-required", children: " *" })
1671
+ ] }) : null,
1672
+ /* @__PURE__ */ jsxs14(
1673
+ "div",
1674
+ {
1675
+ className: `border-c px-3 py-2 flex items-center justify-between rounded-md h-12 ${containerBg} ${containerBorder}`,
1676
+ children: [
1677
+ prefix,
1678
+ /* @__PURE__ */ jsx24(
1679
+ IMaskInput,
1680
+ {
1681
+ type,
1682
+ mask,
1683
+ value: formattedValue,
1684
+ onChange: handleChange,
1685
+ onBlur: handleBlur,
1686
+ onKeyDown: handleKeyDown,
1687
+ disabled,
1688
+ placeholder: placeholder ?? (label ? `Enter ${label.toLowerCase()}` : void 0),
1689
+ inputMode: isAmountInput ? "decimal" : void 0,
1690
+ 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"
1691
+ }
1692
+ ),
1693
+ !loading ? /* @__PURE__ */ jsxs14(Fragment2, { children: [
1694
+ suffix,
1695
+ showCopyIcon && rawValue && rawValue.trim() !== "" && /* @__PURE__ */ jsx24(
1696
+ BaseImage,
1697
+ {
1698
+ src: "assets/images/copyIcon.svg",
1699
+ alt: "copy",
1700
+ width: 16,
1701
+ height: 16,
1702
+ customClass: "cursor-pointer hover:opacity-70 transition-opacity",
1703
+ onClick: copyHandler
1704
+ }
1705
+ )
1706
+ ] }) : (
1707
+ // Simple loader placeholder; swap for your icon component if desired
1708
+ /* @__PURE__ */ jsx24("div", { className: "animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full" })
1709
+ )
1710
+ ]
1711
+ }
1712
+ ),
1713
+ (hint || localHint) && /* @__PURE__ */ jsx24("p", { className: "text-body-3xs text-light-copy", children: localHint || hint }),
1714
+ (validationError || localError) && /* @__PURE__ */ jsx24("p", { className: "text-body-3xs text-red-500", children: localError || validationError })
1715
+ ] });
1716
+ };
1717
+
1718
+ // src/buzapay-checkout/checkout-iframe.tsx
1719
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef, useState as useState2 } from "react";
1720
+ import { jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
1721
+ function BzpCheckoutIframe({
1722
+ style = {
1723
+ width: "100%",
1724
+ height: "100vh",
1725
+ border: "0",
1726
+ borderRadius: "6px",
1727
+ overflow: "hidden"
1728
+ },
1729
+ url,
1730
+ secretKey,
1731
+ environment = "sandbox",
1732
+ paymentObject = {
1733
+ merchantName: "",
1734
+ amount: 0,
1735
+ currency: "",
1736
+ email: "",
1737
+ phoneNumber: "",
1738
+ narration: "",
1739
+ redirectUrl: ""
1740
+ }
1741
+ }) {
1742
+ const containerRef = useRef(null);
1743
+ const iframeRef = useRef(null);
1744
+ const [message, setMessage] = useState2("");
1745
+ const [launchUrl, setLaunchUrl] = useState2("");
1746
+ const [loading, setLoading] = useState2(false);
1747
+ const launchIframe = useCallback2(
1748
+ (url2) => {
1749
+ if (iframeRef.current && iframeRef.current.parentNode) {
1750
+ iframeRef.current.parentNode.removeChild(iframeRef.current);
1751
+ }
1752
+ const iframe = document.createElement("iframe");
1753
+ iframe.src = url2;
1754
+ if (style.width) iframe.style.width = style.width;
1755
+ if (style.height) iframe.style.height = style.height;
1756
+ if (style.border) iframe.style.border = style.border;
1757
+ if (style.borderRadius) iframe.style.borderRadius = style.borderRadius;
1758
+ if (style.overflow) iframe.style.overflow = style.overflow;
1759
+ containerRef.current?.appendChild(iframe);
1760
+ iframeRef.current = iframe;
1761
+ },
1762
+ [style]
1763
+ );
1764
+ const generatePaymentLinkHandler = async () => {
1765
+ if (url) {
1766
+ launchIframe(url);
1767
+ return;
1768
+ }
1769
+ if (!secretKey) {
1770
+ return setMessage("Secret key is required.");
1771
+ }
1772
+ if (!checkObjectTruthy(paymentObject)) {
1773
+ return setMessage("Secret key is required.");
1774
+ }
1775
+ setLoading(true);
1776
+ const response = await createPaymentLink(
1777
+ paymentObject,
1778
+ environment,
1779
+ secretKey
1780
+ );
1781
+ if (response?.isSuccessful) {
1782
+ setLaunchUrl(response.launchUrl ?? "");
1783
+ setMessage("Payment link created successfully");
1784
+ if (response.launchUrl) {
1785
+ setLoading(false);
1786
+ launchIframe(response.launchUrl);
1787
+ }
1788
+ } else {
1789
+ setLoading(false);
1790
+ setMessage("Failed to create payment link");
1225
1791
  }
1226
1792
  };
1227
1793
  useEffect2(() => {
1228
1794
  if (!containerRef.current) return;
1229
1795
  generatePaymentLinkHandler();
1230
1796
  }, []);
1231
- return /* @__PURE__ */ jsxs14("div", { className: "relative", style, children: [
1232
- /* @__PURE__ */ jsx24("div", { ref: containerRef, className: "w-full h-full" }),
1233
- loading && /* @__PURE__ */ jsx24("div", { className: "absolute inset-0 grid place-items-center bg-white/60", children: /* @__PURE__ */ jsx24(IconLoader, {}) })
1797
+ return /* @__PURE__ */ jsxs15("div", { className: "relative", style, children: [
1798
+ /* @__PURE__ */ jsx25("div", { ref: containerRef, className: "w-full h-full" }),
1799
+ loading && /* @__PURE__ */ jsx25("div", { className: "absolute inset-0 grid place-items-center bg-white/60", children: /* @__PURE__ */ jsx25(IconLoader, {}) })
1234
1800
  ] });
1235
1801
  }
1236
1802
 
1237
1803
  // src/buzapay-checkout/checkout-button.tsx
1238
- import { jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
1804
+ import { jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
1239
1805
  function BzpCheckoutButton({
1240
1806
  secretKey,
1241
1807
  environment = "sandbox",
1242
1808
  paymentObject = {
1809
+ merchantName: "",
1243
1810
  amount: 0,
1244
1811
  currency: "",
1245
1812
  email: "",
@@ -1284,15 +1851,15 @@ function BzpCheckoutButton({
1284
1851
  setLoading(false);
1285
1852
  }
1286
1853
  };
1287
- return launchUrl && mode === "iframe" ? /* @__PURE__ */ jsx25(
1854
+ return launchUrl && mode === "iframe" ? /* @__PURE__ */ jsx26(
1288
1855
  BzpCheckoutIframe,
1289
1856
  {
1290
1857
  url: launchUrl,
1291
1858
  secretKey,
1292
1859
  environment
1293
1860
  }
1294
- ) : /* @__PURE__ */ jsxs15("div", { children: [
1295
- /* @__PURE__ */ jsx25(
1861
+ ) : /* @__PURE__ */ jsxs16("div", { children: [
1862
+ /* @__PURE__ */ jsx26(
1296
1863
  BaseButton,
1297
1864
  {
1298
1865
  label: "Pay",
@@ -1302,292 +1869,1034 @@ function BzpCheckoutButton({
1302
1869
  onClick: generatePaymentLinkHandler
1303
1870
  }
1304
1871
  ),
1305
- /* @__PURE__ */ jsx25(BaseInputError, { errorMessage: message })
1872
+ /* @__PURE__ */ jsx26(BaseInputError, { errorMessage: message })
1306
1873
  ] });
1307
1874
  }
1308
1875
 
1309
1876
  // src/buzapay-checkout/checkout-card.tsx
1310
- import { useEffect as useEffect4, useState as useState7 } from "react";
1877
+ import { useEffect as useEffect6, useState as useState7 } from "react";
1311
1878
 
1312
1879
  // src/components/pay-by-card.tsx
1313
- import { useState as useState4 } from "react";
1314
-
1315
- // src/components/base/input.tsx
1316
- import React4 from "react";
1317
- import { Fragment as Fragment2, jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
1318
- var BaseInput = ({
1319
- label = "",
1320
- type = "text",
1321
- placeholder,
1322
- validationError = "",
1323
- hint = "",
1324
- rules = [],
1325
- isAmountInput = false,
1326
- required = false,
1327
- disabled = false,
1328
- loading = false,
1329
- showCopyIcon = false,
1330
- value,
1331
- defaultValue,
1332
- onChange,
1333
- onBlur,
1334
- prefix,
1335
- suffix,
1336
- className = ""
1337
- }) => {
1338
- const isControlled = value !== void 0;
1339
- const [rawValue, setRawValue] = React4.useState(
1340
- defaultValue ?? value ?? ""
1880
+ import { useEffect as useEffect3, useState as useState4 } from "react";
1881
+ import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
1882
+ function PayByCard({
1883
+ secretKey,
1884
+ paymentObject,
1885
+ environment = "sandbox",
1886
+ onPaymentAuthorized
1887
+ }) {
1888
+ const [formIndex, setFormIndex] = useState4(0);
1889
+ const [message, setMessage] = useState4("");
1890
+ const [isMakingPayment, setIsMakingPayment] = useState4(false);
1891
+ const [loading, setLoading] = useState4(false);
1892
+ const [cardType, setCardType] = useState4("");
1893
+ const [transactionReference, setTransactionReference] = useState4("");
1894
+ const [loadingCountries, setLoadingCountries] = useState4(false);
1895
+ const [loadingStates, setLoadingStates] = useState4(false);
1896
+ const [rawCountries, setRawCountries] = useState4([]);
1897
+ const [countries, setCountries] = useState4([]);
1898
+ const [countryStates, setCountryStates] = useState4([]);
1899
+ const [billingForm, setBillingForm] = useState4({
1900
+ address1: "",
1901
+ address2: "",
1902
+ postalCode: "",
1903
+ state: "",
1904
+ city: "",
1905
+ country: "",
1906
+ emailAddress: "",
1907
+ phoneNumber: ""
1908
+ });
1909
+ const [payForm, setPayForm] = useState4({
1910
+ customerName: "",
1911
+ cardNo: "",
1912
+ expireDate: "",
1913
+ cvv: "",
1914
+ cardPin: ""
1915
+ // Only required for Verve cards
1916
+ });
1917
+ const [billingErrors, setBillingErrors] = useState4(
1918
+ {}
1341
1919
  );
1342
- const [localHint, setLocalHint] = React4.useState("");
1343
- const [localError, setLocalError] = React4.useState("");
1344
- React4.useEffect(() => {
1345
- if (isControlled) setRawValue(value ?? "");
1346
- }, [isControlled, value]);
1347
- const formattedValue = isAmountInput ? formatAmount(rawValue.replace(/,/g, "")) : rawValue;
1348
- const handleChange = (e) => {
1349
- const incoming = e.target.value.replace(/,/g, "");
1350
- if (!isControlled) setRawValue(incoming);
1351
- onChange?.(incoming);
1352
- setTimeout(() => {
1353
- const el = e.target;
1354
- el.selectionStart = el.selectionEnd = el.value.length;
1355
- });
1920
+ const [payErrors, setPayErrors] = useState4({});
1921
+ const billingRules = {
1922
+ address1: "required",
1923
+ address2: "",
1924
+ // optional
1925
+ country: "required",
1926
+ state: "required",
1927
+ city: "required",
1928
+ postalCode: "required|no_special|char_length:6",
1929
+ emailAddress: "required|email",
1930
+ phoneNumber: "required"
1356
1931
  };
1357
- const handleBlur = () => {
1358
- onBlur?.(rawValue);
1932
+ const payRules = {
1933
+ customerName: "required",
1934
+ cardNo: "required|num_spaces",
1935
+ expireDate: "required",
1936
+ cvv: "required|numeric",
1937
+ cardPin: ""
1938
+ // optional unless Verve
1359
1939
  };
1360
- const handleKeyDown = (e) => {
1361
- if (rules.includes("numeric")) restrictToNumericKeys(e);
1940
+ const formatAmountHandler = formatAmount(
1941
+ paymentObject.amount,
1942
+ paymentObject.currency
1943
+ );
1944
+ const billingLabels = {
1945
+ address1: "Address Line 1",
1946
+ address2: "Address Line 2",
1947
+ postalCode: "Postal Code",
1948
+ state: "State",
1949
+ city: "City",
1950
+ country: "Country",
1951
+ emailAddress: "Email",
1952
+ phoneNumber: "Phone Number"
1362
1953
  };
1363
- const containerBg = disabled ? "bg-grey-50 cursor-not-allowed" : "bg-white";
1364
- const containerBorder = validationError || localError ? "border-red-300 bg-red-50" : "border-grey-100";
1365
- const copyToClipboard = (text) => {
1366
- return navigator.clipboard.writeText(text);
1954
+ const payLabels = {
1955
+ customerName: "Card Name",
1956
+ cardNo: "Card Number",
1957
+ expireDate: "Expiry Date",
1958
+ cvv: "CVV",
1959
+ cardPin: "Card PIN"
1367
1960
  };
1368
- const copyHandler = () => {
1369
- copyToClipboard(rawValue).then(() => {
1370
- setLocalHint("Text copied to clipboard");
1371
- }).catch((err) => {
1372
- setLocalError("Failed to copy text to clipboard");
1373
- });
1961
+ const proceedHandler = async () => {
1962
+ if (formIndex === 0) {
1963
+ const errs = validateGroup(billingForm, billingRules, billingLabels);
1964
+ setBillingErrors(errs);
1965
+ if (Object.keys(errs).length === 0) {
1966
+ setFormIndex(1);
1967
+ }
1968
+ return;
1969
+ }
1970
+ if (formIndex === 1) {
1971
+ const errs = validateGroup(payForm, payRules, payLabels);
1972
+ setPayErrors(errs);
1973
+ if (Object.keys(errs).length > 0) {
1974
+ return;
1975
+ }
1976
+ try {
1977
+ setIsMakingPayment(true);
1978
+ setMessage("");
1979
+ const cardDetails = {
1980
+ pan: payForm.cardNo ?? "",
1981
+ expiryDate: payForm.expireDate ?? "",
1982
+ cvv: payForm.cvv ?? "",
1983
+ cardScheme: cardType,
1984
+ nameOnCard: payForm.customerName ?? "",
1985
+ ...cardType === "Verve" && { pin: payForm.cardPin ?? "" }
1986
+ };
1987
+ const billingDetails = {
1988
+ address1: billingForm.address1 ?? "",
1989
+ address2: billingForm.address2 ?? "",
1990
+ postalCode: billingForm.postalCode ?? "",
1991
+ state: billingForm.state ?? "",
1992
+ city: billingForm.city ?? "",
1993
+ country: billingForm.country ?? "",
1994
+ emailAddress: billingForm.emailAddress ?? "",
1995
+ phoneNumber: billingForm.phoneNumber ?? ""
1996
+ };
1997
+ const encryptedCardDetails = encryptPayload(environment, cardDetails);
1998
+ const payload = {
1999
+ customerId: paymentObject?.email || payForm.customerName || "",
2000
+ amount: String(paymentObject?.amount ?? ""),
2001
+ currency: paymentObject?.currency || "USD",
2002
+ narration: paymentObject?.narration || "Test transaction",
2003
+ encryptedCardDetails: encryptedCardDetails.requestParam,
2004
+ billingDetails,
2005
+ redirectUrl: paymentObject?.redirectUrl || "",
2006
+ paymentReference: transactionReference,
2007
+ isCheckout: true
2008
+ };
2009
+ const request = { ...payload, merchantId: secretKey };
2010
+ let response = await authorizeCardPayment(environment, request);
2011
+ if (response?.responseParam) {
2012
+ response = decryptPayload(environment, response.responseParam);
2013
+ }
2014
+ if (response?.isSuccessful) {
2015
+ if (response.threeDsInteractionRequired === true) {
2016
+ const threeDsData = {
2017
+ transactionReference: response.transactionReference,
2018
+ threeDsHtml: response.threeDsHtml,
2019
+ amount: response.amount,
2020
+ responseMessage: response.responseMessage,
2021
+ paReq: response.threeDsHtml?.paReq,
2022
+ termUrl: response.threeDsHtml?.termUrl,
2023
+ action: response.threeDsHtml?.action,
2024
+ acsUrl: response.threeDsHtml?.acsUrl,
2025
+ md: response.threeDsHtml?.md
2026
+ };
2027
+ localStorage.setItem("threeDsData", JSON.stringify(threeDsData));
2028
+ const threeDsUrl = `${window.location.origin}/account/three-ds-confirm`;
2029
+ window.open(threeDsUrl, "_blank", "noopener,noreferrer");
2030
+ setMessage(
2031
+ "3D Secure authentication opened in new tab. Please complete the verification"
2032
+ );
2033
+ setIsMakingPayment(false);
2034
+ return;
2035
+ }
2036
+ if (response.responseMessage === "Payer Interaction Required" && response.threeDsHtml) {
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
+ localStorage.setItem("threeDsData", JSON.stringify(threeDsData));
2049
+ const threeDsUrl = `${window.location.origin}/account/three-ds-confirm`;
2050
+ window.open(threeDsUrl, "_blank", "noopener,noreferrer");
2051
+ setMessage(
2052
+ "3D Secure authentication opened in new tab. Please complete the verification"
2053
+ );
2054
+ setIsMakingPayment(false);
2055
+ return;
2056
+ }
2057
+ if (response.transactionReference?.trim()) {
2058
+ onPaymentAuthorized?.({
2059
+ paymentId: response.transactionReference,
2060
+ paymentDate: response?.data?.updatedAt,
2061
+ // optional if present
2062
+ paymentStatus: "Authorized"
2063
+ });
2064
+ }
2065
+ setMessage("Card payment authorized successfully");
2066
+ setIsMakingPayment(false);
2067
+ return;
2068
+ }
2069
+ setMessage(response?.responseMessage || "Payment failed");
2070
+ onPaymentAuthorized?.({
2071
+ paymentId: response?.transactionReference,
2072
+ paymentDate: response?.data?.updatedAt,
2073
+ paymentStatus: "Payment failed"
2074
+ });
2075
+ setIsMakingPayment(false);
2076
+ } catch (err) {
2077
+ let friendly = "Payment failed";
2078
+ if (err?.error?.responseParam) {
2079
+ try {
2080
+ const decryptedError = decryptPayload(
2081
+ environment,
2082
+ err.error.responseParam
2083
+ );
2084
+ friendly = decryptedError?.responseMessage || friendly;
2085
+ } catch {
2086
+ friendly = err?.error?.responseMessage || err?.error?.message || friendly;
2087
+ }
2088
+ } else {
2089
+ friendly = err?.error?.responseMessage || err?.error?.message || "Payment failed";
2090
+ }
2091
+ setMessage(friendly);
2092
+ setIsMakingPayment(false);
2093
+ }
2094
+ }
1374
2095
  };
1375
- return /* @__PURE__ */ jsxs16("div", { className: `flex flex-col gap-2 ${className}`, children: [
1376
- label ? /* @__PURE__ */ jsxs16("p", { className: "mb-0 text-body-2xs font-normal text-heading-text", children: [
1377
- label,
1378
- required && /* @__PURE__ */ jsx26("span", { className: "text-orange-required", children: " *" })
1379
- ] }) : null,
1380
- /* @__PURE__ */ jsxs16(
1381
- "div",
1382
- {
1383
- className: `border-c px-3 py-2 flex items-center justify-between rounded-md h-12 ${containerBg} ${containerBorder}`,
1384
- children: [
1385
- prefix,
1386
- /* @__PURE__ */ jsx26(
1387
- "input",
1388
- {
1389
- type,
1390
- value: formattedValue,
1391
- onChange: handleChange,
1392
- onBlur: handleBlur,
1393
- onKeyDown: handleKeyDown,
1394
- disabled,
1395
- placeholder: placeholder ?? (label ? `Enter ${label.toLowerCase()}` : void 0),
1396
- inputMode: isAmountInput ? "decimal" : void 0,
1397
- 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"
1398
- }
1399
- ),
1400
- !loading ? /* @__PURE__ */ jsxs16(Fragment2, { children: [
1401
- suffix,
1402
- showCopyIcon && rawValue && rawValue.trim() !== "" && /* @__PURE__ */ jsx26(
1403
- BaseImage,
1404
- {
1405
- src: "assets/images/copyIcon.svg",
1406
- alt: "copy",
1407
- width: 16,
1408
- height: 16,
1409
- customClass: "cursor-pointer hover:opacity-70 transition-opacity",
1410
- onClick: copyHandler
1411
- }
1412
- )
1413
- ] }) : (
1414
- // Simple loader placeholder; swap for your icon component if desired
1415
- /* @__PURE__ */ jsx26("div", { className: "animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full" })
1416
- )
1417
- ]
2096
+ const generatePaymentLinkHandler = async () => {
2097
+ if (!secretKey) {
2098
+ setMessage("Secret key is required.");
2099
+ return;
2100
+ }
2101
+ if (!checkObjectTruthy(paymentObject)) {
2102
+ setMessage("Kindly ensure you are passing all the required data.");
2103
+ return;
2104
+ }
2105
+ setLoading(true);
2106
+ setMessage("");
2107
+ try {
2108
+ const response = await createPaymentLink(
2109
+ paymentObject,
2110
+ environment,
2111
+ secretKey
2112
+ );
2113
+ if (response?.isSuccessful && response.launchUrl) {
2114
+ const queryParams = getQueryParams(response.launchUrl);
2115
+ setTransactionReference(queryParams["paymentReference"]);
2116
+ setMessage("Payment link created successfully");
2117
+ } else {
2118
+ setMessage("Failed to create payment link");
1418
2119
  }
1419
- ),
1420
- (hint || localHint) && /* @__PURE__ */ jsx26("p", { className: "text-body-3xs text-light-copy", children: localHint || hint }),
1421
- (validationError || localError) && /* @__PURE__ */ jsx26("p", { className: "text-body-3xs text-red-500", children: localError || validationError })
1422
- ] });
1423
- };
1424
-
1425
- // src/components/pay-by-card.tsx
1426
- import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
1427
- function PayByCard({}) {
1428
- const [formIndex, setFormIndex] = useState4(0);
2120
+ } catch (e) {
2121
+ setMessage(e?.message || "Failed to create payment link");
2122
+ } finally {
2123
+ setLoading(false);
2124
+ }
2125
+ };
2126
+ const getAllCountries = async () => {
2127
+ setLoadingCountries(true);
2128
+ try {
2129
+ const response = await getCountries(
2130
+ environment,
2131
+ secretKey
2132
+ );
2133
+ if (response?.isSuccessful) {
2134
+ setRawCountries(response.data);
2135
+ setCountries(
2136
+ (response.data ?? []).map((c) => {
2137
+ return { label: c.countryName, value: c.iso2 };
2138
+ })
2139
+ );
2140
+ }
2141
+ } catch (e) {
2142
+ setMessage(e?.message || "Failed to get countries");
2143
+ } finally {
2144
+ setLoadingCountries(false);
2145
+ }
2146
+ };
2147
+ const getStates = async (countryIso2) => {
2148
+ const country = rawCountries.find((c) => c.iso2 === countryIso2);
2149
+ if (!country) return;
2150
+ setLoadingStates(true);
2151
+ try {
2152
+ const response = await getCountryStates(
2153
+ country.iso3,
2154
+ environment,
2155
+ secretKey
2156
+ );
2157
+ if (response?.isSuccessful) {
2158
+ setCountryStates(
2159
+ (response.data ?? []).map((s) => ({
2160
+ label: s.name,
2161
+ value: s.name
2162
+ }))
2163
+ );
2164
+ }
2165
+ } catch (e) {
2166
+ setMessage(e?.message || "Failed to get country states");
2167
+ } finally {
2168
+ setLoadingStates(false);
2169
+ }
2170
+ };
2171
+ const cardNumberInputHandler = (event) => {
2172
+ setCardType(cardTypeHandler(event));
2173
+ payRules.cardPin = "required|numeric";
2174
+ };
2175
+ useEffect3(() => {
2176
+ (async () => {
2177
+ await generatePaymentLinkHandler();
2178
+ await getAllCountries();
2179
+ })();
2180
+ }, []);
1429
2181
  return /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-6", children: [
1430
2182
  formIndex === 0 && /* @__PURE__ */ jsxs17("div", { className: "grid grid-cols-2 gap-6 overflow-y-auto", children: [
1431
- /* @__PURE__ */ jsx27(BaseInput, { label: "First Name", required: true }),
1432
- /* @__PURE__ */ jsx27(BaseInput, { label: "Last Name", required: true }),
1433
- /* @__PURE__ */ jsx27(BaseInput, { label: "Email", required: true }),
1434
- /* @__PURE__ */ jsx27(BaseInput, { label: "Phone Number", required: true }),
2183
+ /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(
2184
+ BaseInput,
2185
+ {
2186
+ label: "Address Line 1",
2187
+ required: true,
2188
+ value: billingForm.address1,
2189
+ onChange: (e) => {
2190
+ setBillingForm({ ...billingForm, address1: e });
2191
+ if (billingErrors.address1) {
2192
+ setBillingErrors((er) => ({ ...er, address1: "" }));
2193
+ }
2194
+ },
2195
+ validationError: billingErrors.address1 ?? ""
2196
+ }
2197
+ ) }),
2198
+ /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(
2199
+ BaseInput,
2200
+ {
2201
+ label: "Address Line 2",
2202
+ value: billingForm.address2,
2203
+ onChange: (e) => setBillingForm({ ...billingForm, address2: e }),
2204
+ validationError: billingErrors.address2 ?? ""
2205
+ }
2206
+ ) }),
2207
+ /* @__PURE__ */ jsx27(
2208
+ BaseSelect,
2209
+ {
2210
+ label: "Select Country",
2211
+ required: true,
2212
+ options: countries,
2213
+ loading: loadingCountries,
2214
+ value: billingForm.country,
2215
+ onChange: (e) => {
2216
+ setBillingForm({ ...billingForm, country: e, state: "" });
2217
+ getStates(e);
2218
+ if (billingErrors.country) {
2219
+ setBillingErrors((er) => ({ ...er, country: "" }));
2220
+ }
2221
+ },
2222
+ validationError: billingErrors.country ?? ""
2223
+ }
2224
+ ),
2225
+ /* @__PURE__ */ jsx27(
2226
+ BaseSelect,
2227
+ {
2228
+ label: "Select State",
2229
+ required: true,
2230
+ options: countryStates,
2231
+ loading: loadingStates,
2232
+ value: billingForm.state,
2233
+ onChange: (e) => {
2234
+ setBillingForm({ ...billingForm, state: e });
2235
+ if (billingErrors.state) {
2236
+ setBillingErrors((er) => ({ ...er, state: "" }));
2237
+ }
2238
+ },
2239
+ validationError: billingErrors.state ?? ""
2240
+ }
2241
+ ),
2242
+ /* @__PURE__ */ jsx27(
2243
+ BaseInput,
2244
+ {
2245
+ label: "City",
2246
+ required: true,
2247
+ value: billingForm.city,
2248
+ onChange: (e) => {
2249
+ setBillingForm({ ...billingForm, city: e });
2250
+ if (billingErrors.city) {
2251
+ setBillingErrors((er) => ({ ...er, city: "" }));
2252
+ }
2253
+ },
2254
+ validationError: billingErrors.city ?? ""
2255
+ }
2256
+ ),
2257
+ /* @__PURE__ */ jsx27(
2258
+ BaseInput,
2259
+ {
2260
+ label: "Postal Code",
2261
+ required: true,
2262
+ value: billingForm.postalCode,
2263
+ onChange: (e) => {
2264
+ setBillingForm({ ...billingForm, postalCode: e });
2265
+ if (billingErrors.postalCode) {
2266
+ setBillingErrors((er) => ({ ...er, postalCode: "" }));
2267
+ }
2268
+ },
2269
+ validationError: billingErrors.postalCode ?? ""
2270
+ }
2271
+ ),
1435
2272
  /* @__PURE__ */ jsx27(
1436
- BaseSelect,
2273
+ BaseInput,
1437
2274
  {
1438
- label: "Select Country",
2275
+ label: "Email",
1439
2276
  required: true,
1440
- options: [
1441
- { label: "United States", value: "US" },
1442
- { label: "Canada", value: "CA" },
1443
- { label: "United Kingdom", value: "UK" }
1444
- ]
2277
+ value: billingForm.emailAddress,
2278
+ onChange: (e) => {
2279
+ setBillingForm({ ...billingForm, emailAddress: e });
2280
+ if (billingErrors.emailAddress) {
2281
+ setBillingErrors((er) => ({ ...er, emailAddress: "" }));
2282
+ }
2283
+ },
2284
+ validationError: billingErrors.emailAddress ?? ""
1445
2285
  }
1446
2286
  ),
1447
2287
  /* @__PURE__ */ jsx27(
1448
- BaseSelect,
2288
+ BaseInput,
1449
2289
  {
1450
- label: "Select State",
2290
+ label: "Phone Number",
1451
2291
  required: true,
1452
- options: [
1453
- { label: "California", value: "CA" },
1454
- { label: "Texas", value: "TX" },
1455
- { label: "New York", value: "NY" }
1456
- ]
2292
+ value: billingForm.phoneNumber,
2293
+ onChange: (e) => {
2294
+ setBillingForm({ ...billingForm, phoneNumber: e });
2295
+ if (billingErrors.phoneNumber) {
2296
+ setBillingErrors((er) => ({ ...er, phoneNumber: "" }));
2297
+ }
2298
+ },
2299
+ validationError: billingErrors.phoneNumber ?? ""
1457
2300
  }
1458
- ),
1459
- /* @__PURE__ */ jsx27(BaseInput, { label: "City", required: true }),
1460
- /* @__PURE__ */ jsx27(BaseInput, { label: "Postal Code", required: true }),
1461
- /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(BaseInput, { label: "Street Address", required: true }) })
2301
+ )
1462
2302
  ] }),
1463
2303
  formIndex === 1 && /* @__PURE__ */ jsxs17(
1464
2304
  "div",
1465
2305
  {
1466
2306
  className: "grid grid-cols-2 gap-6 overflow-y-auto",
1467
- style: { maxHeight: "320px" },
2307
+ style: { maxHeight: 320 },
1468
2308
  children: [
1469
- /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(BaseInput, { label: "Card Name", required: true }) }),
1470
- /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(BaseInput, { label: "Card Number", required: true }) }),
1471
- /* @__PURE__ */ jsx27(BaseInput, { label: "Expiry Date", required: true }),
1472
- /* @__PURE__ */ jsx27(BaseInput, { label: "CVV", required: true })
2309
+ /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(
2310
+ BaseInput,
2311
+ {
2312
+ label: "Card Name",
2313
+ required: true,
2314
+ value: payForm.customerName,
2315
+ onChange: (e) => {
2316
+ setPayForm({ ...payForm, customerName: e });
2317
+ if (payErrors.customerName) {
2318
+ setPayErrors((er) => ({ ...er, customerName: "" }));
2319
+ }
2320
+ },
2321
+ validationError: payErrors.customerName ?? ""
2322
+ }
2323
+ ) }),
2324
+ /* @__PURE__ */ jsx27("div", { className: "col-span-2", children: /* @__PURE__ */ jsx27(
2325
+ BaseInput,
2326
+ {
2327
+ label: "Card Number",
2328
+ required: true,
2329
+ rules: ["numeric"],
2330
+ mask: "0000 0000 0000 0000",
2331
+ placeholder: "0000 0000 0000 0000",
2332
+ value: payForm.cardNo,
2333
+ onChange: (e) => {
2334
+ setPayForm({ ...payForm, cardNo: e });
2335
+ if (payErrors.cardNo)
2336
+ setPayErrors((er) => ({ ...er, cardNo: "" }));
2337
+ cardNumberInputHandler(e);
2338
+ },
2339
+ validationError: payErrors.cardNo ?? ""
2340
+ }
2341
+ ) }),
2342
+ /* @__PURE__ */ jsx27(
2343
+ BaseInput,
2344
+ {
2345
+ label: "Expiry Date",
2346
+ required: true,
2347
+ value: payForm.expireDate,
2348
+ mask: "00/00",
2349
+ placeholder: "00/00",
2350
+ onChange: (e) => {
2351
+ setPayForm({ ...payForm, expireDate: e });
2352
+ if (payErrors.expireDate)
2353
+ setPayErrors((er) => ({ ...er, expireDate: "" }));
2354
+ },
2355
+ validationError: payErrors.expireDate ?? ""
2356
+ }
2357
+ ),
2358
+ /* @__PURE__ */ jsx27(
2359
+ BaseInput,
2360
+ {
2361
+ label: "CVV",
2362
+ required: true,
2363
+ rules: ["numeric"],
2364
+ value: payForm.cvv,
2365
+ mask: "000",
2366
+ placeholder: "000",
2367
+ onChange: (e) => {
2368
+ setPayForm({ ...payForm, cvv: e });
2369
+ if (payErrors.cvv) setPayErrors((er) => ({ ...er, cvv: "" }));
2370
+ },
2371
+ validationError: payErrors.cvv ?? ""
2372
+ }
2373
+ ),
2374
+ cardType === "Verve" && /* @__PURE__ */ jsx27(
2375
+ BaseInput,
2376
+ {
2377
+ label: "Card Pin",
2378
+ required: true,
2379
+ rules: ["numeric"],
2380
+ value: payForm.cardPin,
2381
+ mask: "0000",
2382
+ placeholder: "0000",
2383
+ onChange: (e) => {
2384
+ setPayForm({ ...payForm, cardPin: e });
2385
+ if (payErrors.cardPin)
2386
+ setPayErrors((er) => ({ ...er, cardPin: "" }));
2387
+ },
2388
+ validationError: payErrors.cardPin ?? ""
2389
+ }
2390
+ )
1473
2391
  ]
1474
2392
  }
1475
2393
  ),
1476
2394
  /* @__PURE__ */ jsx27(
1477
2395
  BaseButton,
1478
2396
  {
1479
- label: formIndex === 0 ? "Proceed" : "Pay",
2397
+ label: formIndex === 0 ? "Proceed" : `Pay ${formatAmountHandler}`,
1480
2398
  type: "primary",
1481
2399
  customClass: "w-full",
1482
- onClick: formIndex === 0 ? () => setFormIndex(1) : void 0
2400
+ loading: isMakingPayment,
2401
+ onClick: proceedHandler,
2402
+ disabled: isMakingPayment
1483
2403
  }
1484
2404
  )
1485
2405
  ] });
1486
2406
  }
1487
2407
 
1488
2408
  // src/components/pay-by-transfer.tsx
1489
- import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState5 } from "react";
2409
+ import {
2410
+ useCallback as useCallback3,
2411
+ useEffect as useEffect4,
2412
+ useRef as useRef2,
2413
+ useState as useState5
2414
+ } from "react";
1490
2415
  import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
1491
2416
  var PayByTransfer = ({
1492
- amountDisplay = "NGN 200,500.00",
1493
- bankName = "Teerus MFB",
1494
- accountNumber = "0001928940",
1495
- initialSeconds = 30 * 60,
1496
- onConfirmPaid,
2417
+ secretKey,
2418
+ paymentObject,
2419
+ environment = "sandbox",
2420
+ onPaymentAuthorized,
1497
2421
  onCancel
1498
2422
  }) => {
1499
- const [remaining, setRemaining] = useState5(initialSeconds);
2423
+ const [formIndex, setFormIndex] = useState5(0);
2424
+ const [isMakingPayment, setIsMakingPayment] = useState5(false);
2425
+ const [isConfirmCall, setIsConfirmCall] = useState5(false);
2426
+ const [isPaymentConfirmed, setIsPaymentConfirmed] = useState5(false);
2427
+ const [transactionReference, setTransactionReference] = useState5("");
2428
+ const [paymentReferenceStatus, setPaymentReferenceStatus] = useState5("");
2429
+ const [isFetchingPaymentDetails, setIsFetchingPaymentDetails] = useState5(false);
2430
+ const [paymentReferenceDetails, setPaymentReferenceDetails] = useState5(null);
2431
+ const [paymentAccountDetails, setPaymentAccountDetails] = useState5(null);
2432
+ const [paymentMade, setPaymentMade] = useState5(false);
2433
+ const [loading, setLoading] = useState5(false);
2434
+ const [message, setMessage] = useState5("");
2435
+ const [remainingSeconds, setRemainingSeconds] = useState5(60);
2436
+ const [countDownTime, setCountDownTime] = useState5("00:00");
1500
2437
  const intervalRef = useRef2(null);
1501
- const countDownTime = useMemo2(() => {
1502
- const clamped = Math.max(0, remaining);
1503
- const m = Math.floor(clamped / 60);
1504
- const s = clamped % 60;
1505
- return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
1506
- }, [remaining]);
1507
- useEffect3(() => {
1508
- intervalRef.current = window.setInterval(() => {
1509
- setRemaining((prev) => prev - 1);
1510
- }, 1e3);
1511
- return () => {
1512
- if (intervalRef.current) {
1513
- clearInterval(intervalRef.current);
1514
- intervalRef.current = null;
2438
+ const [transferForm, setTransferForm] = useState5({
2439
+ customerName: ""
2440
+ });
2441
+ const [transferErrors, setTransferErrors] = useState5(
2442
+ {}
2443
+ );
2444
+ const transferRules = {
2445
+ customerName: "required"
2446
+ };
2447
+ const transferLabels = {
2448
+ customerName: "Customer Name"
2449
+ };
2450
+ const formatAmountHandler = formatAmount(
2451
+ paymentObject.amount,
2452
+ paymentObject.currency
2453
+ );
2454
+ const payHandler = async () => {
2455
+ if (formIndex === 0) {
2456
+ const errs = validateGroup(transferForm, transferRules, transferLabels);
2457
+ setTransferErrors(errs);
2458
+ if (Object.keys(errs).length === 0) {
2459
+ const payload = {
2460
+ paymentReference: transactionReference,
2461
+ channel: "virtual_account",
2462
+ customerName: transferForm.customerName ?? "",
2463
+ merchantId: secretKey
2464
+ };
2465
+ setIsMakingPayment(true);
2466
+ try {
2467
+ const response = await generatePaymentAccount(environment, payload);
2468
+ if (response?.isSuccessful) {
2469
+ setPaymentAccountDetails(response.data);
2470
+ startTimer();
2471
+ setMessage("Virtual account generated successfully for payment.");
2472
+ setIsMakingPayment(true);
2473
+ setFormIndex(1);
2474
+ }
2475
+ } catch (err) {
2476
+ setIsMakingPayment(false);
2477
+ setMessage(err.error.responseMessage || err.error.message);
2478
+ }
1515
2479
  }
1516
- };
2480
+ return;
2481
+ }
2482
+ };
2483
+ const getReferenceDetails = async () => {
2484
+ setIsFetchingPaymentDetails(true);
2485
+ try {
2486
+ const response = await getPaymentReferenceDetails(
2487
+ environment,
2488
+ transactionReference
2489
+ );
2490
+ if (response?.isSuccessful) {
2491
+ setPaymentReferenceDetails(response.data);
2492
+ const made = response.data?.paymentStatus === "Payment Received";
2493
+ setPaymentMade(made);
2494
+ const noServerStatus = response.data?.finalTransactionStatus == null || response.data?.paymentStatus == null;
2495
+ if (noServerStatus) {
2496
+ if (isConfirmCall) {
2497
+ setMessage("Transaction not confirmed !!");
2498
+ }
2499
+ if (!isPaymentConfirmed && !made) {
2500
+ setPaymentReferenceStatus("pending");
2501
+ onPaymentAuthorized?.({
2502
+ paymentId: transactionReference,
2503
+ paymentDate: response.data?.updatedAt,
2504
+ paymentStatus: "pending"
2505
+ });
2506
+ } else {
2507
+ setPaymentReferenceStatus("confirmed");
2508
+ onPaymentAuthorized?.({
2509
+ paymentId: transactionReference,
2510
+ paymentDate: response.data?.updatedAt,
2511
+ paymentStatus: "confirmed"
2512
+ });
2513
+ }
2514
+ } else if (response.data?.finalTransactionStatus === "Success" || response.data?.paymentStatus === "Received" || response.data?.paymentStatus === "Payment Received") {
2515
+ setPaymentReferenceStatus("confirmed");
2516
+ setIsPaymentConfirmed(true);
2517
+ setMessage("Transaction confirmed !!");
2518
+ onPaymentAuthorized?.({
2519
+ paymentId: transactionReference,
2520
+ paymentDate: response.data?.updatedAt,
2521
+ paymentStatus: "confirmed"
2522
+ });
2523
+ }
2524
+ } else if (!response?.isSuccessful && response?.responseCode === "119") {
2525
+ setPaymentReferenceStatus("used");
2526
+ setMessage(response.responseMessage || "");
2527
+ onPaymentAuthorized?.({
2528
+ paymentId: transactionReference,
2529
+ paymentDate: null,
2530
+ paymentStatus: "used"
2531
+ });
2532
+ }
2533
+ } catch (err) {
2534
+ setPaymentReferenceStatus("");
2535
+ setMessage(
2536
+ err?.error?.responseMessage || err?.error?.message || "Something went wrong"
2537
+ );
2538
+ } finally {
2539
+ setIsFetchingPaymentDetails(false);
2540
+ }
2541
+ };
2542
+ const generatePaymentLinkHandler = async () => {
2543
+ if (!secretKey) {
2544
+ setMessage("Secret key is required.");
2545
+ return;
2546
+ }
2547
+ if (!checkObjectTruthy(paymentObject)) {
2548
+ setMessage("Kindly ensure you are passing all the required data.");
2549
+ return;
2550
+ }
2551
+ setLoading(true);
2552
+ setMessage("");
2553
+ try {
2554
+ const response = await createPaymentLink(
2555
+ paymentObject,
2556
+ environment,
2557
+ secretKey
2558
+ );
2559
+ if (response?.isSuccessful && response.launchUrl) {
2560
+ const queryParams = getQueryParams(response.launchUrl);
2561
+ setTransactionReference(queryParams["paymentReference"]);
2562
+ setMessage("Payment link created successfully");
2563
+ } else {
2564
+ setMessage("Failed to create payment link");
2565
+ }
2566
+ } catch (e) {
2567
+ setMessage(e?.message || "Failed to create payment link");
2568
+ } finally {
2569
+ setLoading(false);
2570
+ }
2571
+ };
2572
+ const updateDisplay = useCallback3((secs) => {
2573
+ const minutes = String(Math.floor(secs / 60)).padStart(2, "0");
2574
+ const seconds = String(secs % 60).padStart(2, "0");
2575
+ setCountDownTime(`${minutes}:${seconds}`);
1517
2576
  }, []);
1518
- useEffect3(() => {
1519
- if (remaining < 0 && intervalRef.current) {
2577
+ const startTimer = useCallback3(() => {
2578
+ if (intervalRef.current) {
2579
+ clearInterval(intervalRef.current);
2580
+ intervalRef.current = null;
2581
+ }
2582
+ updateDisplay(remainingSeconds);
2583
+ intervalRef.current = setInterval(() => {
2584
+ setRemainingSeconds((prev) => {
2585
+ const next = prev - 1;
2586
+ if (next < 0) {
2587
+ if (intervalRef.current) {
2588
+ clearInterval(intervalRef.current);
2589
+ intervalRef.current = null;
2590
+ }
2591
+ setCountDownTime("00:00");
2592
+ return 0;
2593
+ }
2594
+ updateDisplay(next);
2595
+ return next;
2596
+ });
2597
+ }, 1e3);
2598
+ }, [remainingSeconds, updateDisplay]);
2599
+ const stopTimer = () => {
2600
+ if (intervalRef.current) {
1520
2601
  clearInterval(intervalRef.current);
1521
2602
  intervalRef.current = null;
1522
2603
  }
1523
- }, [remaining]);
2604
+ };
2605
+ useEffect4(() => {
2606
+ (async () => {
2607
+ await generatePaymentLinkHandler();
2608
+ })();
2609
+ }, []);
2610
+ useEffect4(() => {
2611
+ if (remainingSeconds < 0 && intervalRef.current) {
2612
+ stopTimer();
2613
+ }
2614
+ }, [remainingSeconds]);
1524
2615
  return /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-10", children: [
1525
- /* @__PURE__ */ jsxs18("p", { className: "text-sub-copy text-sm font-semibold text-center", children: [
1526
- "Amount to Pay ",
1527
- amountDisplay
2616
+ formIndex === 0 && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-10", children: [
2617
+ /* @__PURE__ */ jsx28(
2618
+ BaseInput,
2619
+ {
2620
+ label: "Customer Name",
2621
+ required: true,
2622
+ value: transferForm.customerName,
2623
+ onChange: (e) => {
2624
+ setTransferForm({ ...transferForm, customerName: e });
2625
+ if (transferForm.customerName) {
2626
+ setTransferErrors((er) => ({ ...er, customerName: "" }));
2627
+ }
2628
+ },
2629
+ validationError: transferErrors.customerName ?? ""
2630
+ }
2631
+ ),
2632
+ /* @__PURE__ */ jsx28(
2633
+ BaseButton,
2634
+ {
2635
+ label: `Pay ${formatAmountHandler}`,
2636
+ type: "primary",
2637
+ customClass: "w-full",
2638
+ loading: isMakingPayment,
2639
+ onClick: payHandler
2640
+ }
2641
+ )
1528
2642
  ] }),
1529
- /* @__PURE__ */ jsxs18("div", { className: "bg-[#EFF7FF] p-4 rounded-lg flex flex-col gap-6", children: [
1530
- /* @__PURE__ */ jsx28(BaseLabelInfo, { label: "Bank Name", value: bankName, type: "horizontal" }),
1531
- /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between", children: [
2643
+ formIndex === 1 && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-10", children: [
2644
+ /* @__PURE__ */ jsxs18("div", { className: "bg-[#EFF7FF] p-4 rounded-lg flex flex-col gap-6", children: [
1532
2645
  /* @__PURE__ */ jsx28(
1533
2646
  BaseLabelInfo,
1534
2647
  {
1535
- label: "Account Number",
1536
- value: accountNumber,
1537
- type: "horizontal"
2648
+ label: "Bank Name",
2649
+ value: `${paymentAccountDetails?.bank} ${paymentAccountDetails?.accountName}`
1538
2650
  }
1539
2651
  ),
1540
- /* @__PURE__ */ jsx28(BaseCopy, { color: "#9DBFDE", copyText: accountNumber })
2652
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between", children: [
2653
+ /* @__PURE__ */ jsx28(
2654
+ BaseLabelInfo,
2655
+ {
2656
+ label: "Account Number",
2657
+ value: paymentAccountDetails?.accountNumber
2658
+ }
2659
+ ),
2660
+ /* @__PURE__ */ jsx28(
2661
+ BaseCopy,
2662
+ {
2663
+ color: "#9DBFDE",
2664
+ copyText: paymentAccountDetails?.accountNumber ?? ""
2665
+ }
2666
+ )
2667
+ ] }),
2668
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between", children: [
2669
+ /* @__PURE__ */ jsx28(BaseLabelInfo, { label: "Amount", value: formatAmountHandler }),
2670
+ /* @__PURE__ */ jsx28(BaseCopy, { color: "#9DBFDE", copyText: formatAmountHandler })
2671
+ ] })
1541
2672
  ] }),
1542
- /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between", children: [
2673
+ /* @__PURE__ */ jsxs18("p", { className: "w-2/3 mx-auto text-center text-body-2xs font-medium text-sub-copy", children: [
2674
+ "This account is for this transaction only and expires in",
2675
+ " ",
2676
+ /* @__PURE__ */ jsx28("span", { className: "text-orange-500", children: remainingSeconds >= 0 ? countDownTime : "00:00" })
2677
+ ] }),
2678
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-4", children: [
1543
2679
  /* @__PURE__ */ jsx28(
1544
- BaseLabelInfo,
2680
+ BaseButton,
1545
2681
  {
1546
- label: "Amount",
1547
- value: amountDisplay,
1548
- type: "horizontal"
2682
+ label: "I have paid the money",
2683
+ type: "primary",
2684
+ customClass: "w-full",
2685
+ loading: isFetchingPaymentDetails,
2686
+ onClick: getReferenceDetails
1549
2687
  }
1550
2688
  ),
1551
- /* @__PURE__ */ jsx28(BaseCopy, { color: "#9DBFDE", copyText: amountDisplay })
2689
+ /* @__PURE__ */ jsx28(
2690
+ "button",
2691
+ {
2692
+ type: "button",
2693
+ onClick: onCancel,
2694
+ className: "text-heading-text text-body-2xs font-medium text-center py-2 cursor-pointer",
2695
+ children: "Cancel Payment"
2696
+ }
2697
+ )
1552
2698
  ] })
1553
- ] }),
1554
- /* @__PURE__ */ jsxs18("p", { className: "w-2/3 mx-auto text-center text-body-2xs font-medium text-sub-copy", children: [
1555
- "This account is for this transaction only and expires in",
1556
- " ",
1557
- /* @__PURE__ */ jsx28("span", { className: "text-orange-500", children: remaining >= 0 ? countDownTime : "00:00" })
1558
- ] }),
1559
- /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-4", children: [
1560
- /* @__PURE__ */ jsx28(
1561
- BaseButton,
1562
- {
1563
- label: "I have paid the money",
1564
- type: "primary",
1565
- customClass: "w-full",
1566
- onClick: onConfirmPaid
1567
- }
1568
- ),
1569
- /* @__PURE__ */ jsx28(
1570
- "button",
1571
- {
1572
- type: "button",
1573
- onClick: onCancel,
1574
- className: "text-heading-text text-body-2xs font-medium text-center py-2 cursor-pointer",
1575
- children: "Cancel Payment"
1576
- }
1577
- )
1578
2699
  ] })
1579
2700
  ] });
1580
2701
  };
1581
2702
 
1582
2703
  // src/components/pay-by-stable-coin.tsx
1583
- import { useState as useState6 } from "react";
2704
+ import { useEffect as useEffect5, useState as useState6 } from "react";
1584
2705
  import { Fragment as Fragment3, jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
1585
- var PayByStableCoin = ({ onProceedToPay }) => {
2706
+ var PayByStableCoin = ({
2707
+ secretKey,
2708
+ paymentObject,
2709
+ environment = "sandbox",
2710
+ onPaymentAuthorized
2711
+ }) => {
1586
2712
  const [formIndex, setFormIndex] = useState6(0);
1587
- const payHandler = () => {
1588
- setFormIndex(1);
1589
- onProceedToPay?.();
2713
+ const [message, setMessage] = useState6("");
2714
+ const [loading, setLoading] = useState6(false);
2715
+ const [generatingAddress, setGeneratingAddress] = useState6(false);
2716
+ const [loadingStableCoins, setLoadingStableCoins] = useState6(false);
2717
+ const [loadingStableCoinNetworks, setLoadingStableCoinNetworks] = useState6(false);
2718
+ const [transactionReference, setTransactionReference] = useState6("");
2719
+ const [stableCoins, setStableCoins] = useState6([]);
2720
+ const [networkList, setNetworkList] = useState6([]);
2721
+ const [addressDetails, setAddressDetails] = useState6(null);
2722
+ const [generateAddressPayload, setGenerateAddressPayload] = useState6(null);
2723
+ const [isConfirmingPayment, setIsConfirmingPayment] = useState6(false);
2724
+ const [paymentReferenceDetails, setPaymentReferenceDetails] = useState6(null);
2725
+ const [paymentReferenceStatus, setPaymentReferenceStatus] = useState6("");
2726
+ const [stableCoinForm, setStableCoinForm] = useState6({
2727
+ stableCoin: "",
2728
+ network: ""
2729
+ });
2730
+ const [stableCoinErrors, setStableCoinErrors] = useState6({});
2731
+ const stableCoinRules = {
2732
+ stableCoin: "required",
2733
+ network: "required"
2734
+ };
2735
+ const stableCoinLabels = {
2736
+ stableCoin: "Stable Coin",
2737
+ network: "Network"
2738
+ };
2739
+ const generatePaymentLinkHandler = async () => {
2740
+ if (!secretKey) {
2741
+ setMessage("Secret key is required.");
2742
+ return;
2743
+ }
2744
+ if (!checkObjectTruthy(paymentObject)) {
2745
+ setMessage("Kindly ensure you are passing all the required data.");
2746
+ return;
2747
+ }
2748
+ setLoading(true);
2749
+ setMessage("");
2750
+ try {
2751
+ const response = await createPaymentLink(
2752
+ paymentObject,
2753
+ environment,
2754
+ secretKey
2755
+ );
2756
+ if (response?.isSuccessful && response.launchUrl) {
2757
+ const queryParams = getQueryParams(response.launchUrl);
2758
+ setTransactionReference(queryParams["paymentReference"]);
2759
+ setMessage("Payment link created successfully");
2760
+ } else {
2761
+ setMessage("Failed to create payment link");
2762
+ }
2763
+ } catch (e) {
2764
+ setMessage(e?.message || "Failed to create payment link");
2765
+ } finally {
2766
+ setLoading(false);
2767
+ }
2768
+ };
2769
+ const generateAddress = async (payload) => {
2770
+ if (!payload) return;
2771
+ setGeneratingAddress(true);
2772
+ try {
2773
+ const response = await generateStableCoinAddress(
2774
+ environment,
2775
+ payload
2776
+ );
2777
+ if (response?.isSuccessful) {
2778
+ setAddressDetails(response.data);
2779
+ setFormIndex(1);
2780
+ }
2781
+ } catch (e) {
2782
+ setMessage(e?.message || "Failed to generate address");
2783
+ } finally {
2784
+ setGeneratingAddress(false);
2785
+ }
2786
+ };
2787
+ const getAllStableCoins = async () => {
2788
+ setLoadingStableCoins(true);
2789
+ try {
2790
+ const response = await getStableCoins(environment);
2791
+ if (response?.isSuccessful) {
2792
+ setStableCoins(
2793
+ response.data?.map((c) => ({
2794
+ label: c.name,
2795
+ value: c.name
2796
+ })) ?? []
2797
+ );
2798
+ }
2799
+ } catch (e) {
2800
+ setMessage(e?.message || "Failed to get stable coins");
2801
+ } finally {
2802
+ setLoadingStableCoins(false);
2803
+ }
2804
+ };
2805
+ const getAllStableCoinNetworks = async (stableCoin) => {
2806
+ setLoadingStableCoinNetworks(true);
2807
+ try {
2808
+ const response = await getStableCoinNetworks(
2809
+ environment,
2810
+ stableCoin
2811
+ );
2812
+ if (response?.isSuccessful) {
2813
+ setNetworkList(
2814
+ response.networks?.map((n) => ({
2815
+ label: n,
2816
+ value: n
2817
+ })) ?? []
2818
+ );
2819
+ }
2820
+ } catch (e) {
2821
+ setMessage(e?.message || "Failed to get stable coin networks");
2822
+ } finally {
2823
+ setLoadingStableCoinNetworks(false);
2824
+ }
2825
+ };
2826
+ const confirmPaymentHandler = async () => {
2827
+ setIsConfirmingPayment(true);
2828
+ try {
2829
+ const response = await getPaymentReferenceDetails(environment, transactionReference);
2830
+ if (response?.isSuccessful) {
2831
+ setPaymentReferenceDetails(response.data);
2832
+ const needsConfirm = response.data?.finalTransactionStatus == null || response.data?.paymentStatus == null;
2833
+ if (needsConfirm) {
2834
+ setMessage("Transaction not confirmed !!");
2835
+ setPaymentReferenceStatus("pending");
2836
+ onPaymentAuthorized?.({
2837
+ paymentId: transactionReference,
2838
+ paymentDate: response.data?.updatedAt ?? "",
2839
+ paymentStatus: "pending"
2840
+ });
2841
+ } else if (response.data?.finalTransactionStatus === "Success" || response.data?.paymentStatus === "Payment Received") {
2842
+ setMessage("Transaction confirmed !!");
2843
+ setPaymentReferenceStatus("confirmed");
2844
+ onPaymentAuthorized?.({
2845
+ paymentId: transactionReference,
2846
+ paymentDate: response.data?.updatedAt,
2847
+ paymentStatus: "confirmed"
2848
+ });
2849
+ }
2850
+ } else if (!response?.isSuccessful && response?.responseCode === "119") {
2851
+ setPaymentReferenceStatus("used");
2852
+ setMessage(response.responseMessage || "");
2853
+ onPaymentAuthorized?.({
2854
+ paymentId: transactionReference,
2855
+ paymentDate: null,
2856
+ paymentStatus: "used"
2857
+ });
2858
+ }
2859
+ } catch (err) {
2860
+ setPaymentReferenceStatus("");
2861
+ setMessage(
2862
+ err?.error?.responseMessage || err?.error?.message || "Something went wrong"
2863
+ );
2864
+ } finally {
2865
+ setIsConfirmingPayment(false);
2866
+ }
2867
+ };
2868
+ const formatAmountHandler = formatAmount(
2869
+ paymentObject.amount,
2870
+ paymentObject.currency
2871
+ );
2872
+ const payHandler = async () => {
2873
+ const errs = validateGroup(
2874
+ stableCoinForm,
2875
+ stableCoinRules,
2876
+ stableCoinLabels
2877
+ );
2878
+ setStableCoinErrors(errs);
2879
+ if (Object.keys(errs).length === 0) {
2880
+ const payload = {
2881
+ paymentReference: transactionReference,
2882
+ currency: stableCoinForm.stableCoin,
2883
+ chain: stableCoinForm.network,
2884
+ transactionAmount: paymentObject.amount,
2885
+ merchantId: secretKey
2886
+ };
2887
+ setGenerateAddressPayload(payload);
2888
+ await generateAddress(payload);
2889
+ } else {
2890
+ return;
2891
+ }
1590
2892
  };
2893
+ const amountPlusNetworkFee = addressDetails ? Number(addressDetails.transactionAmount) + addressDetails.networkFee : 0;
2894
+ useEffect5(() => {
2895
+ (async () => {
2896
+ await generatePaymentLinkHandler();
2897
+ await getAllStableCoins();
2898
+ })();
2899
+ }, []);
1591
2900
  return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-6", children: [
1592
2901
  formIndex === 0 && /* @__PURE__ */ jsxs19(Fragment3, { children: [
1593
2902
  /* @__PURE__ */ jsxs19("div", { className: "grid grid-cols-1 gap-6", children: [
@@ -1596,11 +2905,17 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1596
2905
  {
1597
2906
  label: "Select Crypto",
1598
2907
  required: true,
1599
- options: [
1600
- { label: "USDT", value: "USDT" },
1601
- { label: "USDC", value: "USDC" },
1602
- { label: "BUSD", value: "BUSD" }
1603
- ]
2908
+ options: stableCoins,
2909
+ loading: loadingStableCoins,
2910
+ value: stableCoinForm.stableCoin,
2911
+ onChange: (e) => {
2912
+ setStableCoinForm({ ...stableCoinForm, stableCoin: e });
2913
+ getAllStableCoinNetworks(e);
2914
+ if (stableCoinErrors.stableCoin) {
2915
+ setStableCoinErrors((er) => ({ ...er, stableCoin: "" }));
2916
+ }
2917
+ },
2918
+ validationError: stableCoinErrors.stableCoin ?? ""
1604
2919
  }
1605
2920
  ),
1606
2921
  /* @__PURE__ */ jsx29(
@@ -1608,52 +2923,46 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1608
2923
  {
1609
2924
  label: "Select Network",
1610
2925
  required: true,
1611
- options: [
1612
- { label: "Ethereum", value: "ETH" },
1613
- { label: "Binance Smart Chain", value: "BSC" },
1614
- { label: "Polygon", value: "MATIC" }
1615
- ]
2926
+ options: networkList,
2927
+ loading: loadingStableCoinNetworks,
2928
+ value: stableCoinForm.network,
2929
+ onChange: (e) => {
2930
+ setStableCoinForm({ ...stableCoinForm, network: e });
2931
+ if (stableCoinErrors.network) {
2932
+ setStableCoinErrors((er) => ({ ...er, network: "" }));
2933
+ }
2934
+ },
2935
+ validationError: stableCoinErrors.network ?? ""
1616
2936
  }
1617
2937
  )
1618
2938
  ] }),
1619
2939
  /* @__PURE__ */ jsx29(
1620
2940
  BaseButton,
1621
2941
  {
1622
- label: "Pay",
2942
+ label: `Pay ${formatAmountHandler}`,
1623
2943
  type: "primary",
1624
2944
  customClass: "w-full",
2945
+ loading: generatingAddress,
1625
2946
  onClick: payHandler
1626
2947
  }
1627
2948
  )
1628
2949
  ] }),
1629
2950
  formIndex === 1 && /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-6", children: [
1630
- /* @__PURE__ */ jsxs19("div", { className: "mx-auto", children: [
1631
- /* @__PURE__ */ jsx29(
1632
- BaseImage,
1633
- {
1634
- src: "../../../assets/images/stable-coin-qr-code.png",
1635
- alt: "QR Code",
1636
- width: 122,
1637
- height: 122,
1638
- customClass: "mb-1"
1639
- }
1640
- ),
1641
- /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-4xs text-light-copy font-normal text-center", children: "USDC" })
1642
- ] }),
2951
+ /* @__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 }) }),
1643
2952
  /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-6 border-c border-grey-100 p-4 rounded-2xl bg-light-white-50", children: [
1644
2953
  /* @__PURE__ */ jsxs19("div", { className: "border-b border-grey-border pb-4 flex flex-col gap-2", children: [
1645
2954
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-3xs text-light-copy font-normal", children: "Network" }),
1646
2955
  /* @__PURE__ */ jsxs19("div", { className: "flex justify-between", children: [
1647
2956
  /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-1", children: [
1648
- /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-2xs font-medium text-sub-copy", children: "BNB Smart Chain (BEP20)" }),
2957
+ /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-2xs font-medium text-sub-copy", children: addressDetails?.chain }),
1649
2958
  /* @__PURE__ */ jsxs19("div", { className: "flex items-center gap-2", children: [
1650
2959
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-3xs text-light-copy font-normal", children: "*Est. arrival = 3 mins" }),
1651
2960
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-3xs text-light-copy font-normal", children: "|" }),
1652
2961
  /* @__PURE__ */ jsx29(
1653
2962
  BaseCurrencyAmount,
1654
2963
  {
1655
- currency: "USDC",
1656
- amount: 10,
2964
+ currency: generateAddressPayload?.currency ?? "",
2965
+ amount: addressDetails?.networkFee ?? 0,
1657
2966
  textClass: "mb-0 text-body-3xs text-light-copy font-normal",
1658
2967
  iconColorClass: "#557591",
1659
2968
  iconWidth: 12,
@@ -1668,8 +2977,8 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1668
2977
  /* @__PURE__ */ jsxs19("div", { className: "pb-4 flex flex-col gap-2", children: [
1669
2978
  /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-3xs text-light-copy font-normal", children: "Deposit Address >" }),
1670
2979
  /* @__PURE__ */ jsxs19("div", { className: "flex justify-between", children: [
1671
- /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-2xs font-medium text-sub-copy w-2/3 break-words", children: "0j8938ysheeee8333c162883a4d4f5g6t111nhk8uey37777yt6" }),
1672
- /* @__PURE__ */ jsx29(BaseCopy, { copyText: "0j8938ysheeee8333c162883a4d4f5g6t111nhk8uey37777yt6" })
2980
+ /* @__PURE__ */ jsx29("p", { className: "mb-0 text-body-2xs font-medium text-sub-copy w-2/3 break-words", children: addressDetails?.walletAddress }),
2981
+ /* @__PURE__ */ jsx29(BaseCopy, { copyText: addressDetails?.walletAddress ?? "" })
1673
2982
  ] })
1674
2983
  ] })
1675
2984
  ] }),
@@ -1679,8 +2988,8 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1679
2988
  /* @__PURE__ */ jsx29(
1680
2989
  BaseCurrencyAmount,
1681
2990
  {
1682
- currency: "USDC",
1683
- amount: 12,
2991
+ currency: generateAddressPayload?.currency ?? "",
2992
+ amount: addressDetails?.networkFee ?? 0,
1684
2993
  textClass: "mb-0 text-body-2xs font-extrabold text-primary-black",
1685
2994
  iconColorClass: "#231F20"
1686
2995
  }
@@ -1691,8 +3000,8 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1691
3000
  /* @__PURE__ */ jsx29(
1692
3001
  BaseCurrencyAmount,
1693
3002
  {
1694
- currency: "USDC",
1695
- amount: 15,
3003
+ currency: generateAddressPayload?.currency ?? "",
3004
+ amount: amountPlusNetworkFee,
1696
3005
  textClass: "mb-0 text-body-lg font-extrabold text-primary-black",
1697
3006
  iconColorClass: "#231F20",
1698
3007
  iconWidth: 20,
@@ -1706,7 +3015,9 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1706
3015
  {
1707
3016
  label: "Confirm Payment",
1708
3017
  type: "primary",
1709
- customClass: "w-full"
3018
+ customClass: "w-full",
3019
+ loading: isConfirmingPayment,
3020
+ onClick: confirmPaymentHandler
1710
3021
  }
1711
3022
  ) })
1712
3023
  ] })
@@ -1716,9 +3027,11 @@ var PayByStableCoin = ({ onProceedToPay }) => {
1716
3027
  // src/buzapay-checkout/checkout-card.tsx
1717
3028
  import { jsx as jsx30, jsxs as jsxs20 } from "react/jsx-runtime";
1718
3029
  function BzpCheckoutCard({
3030
+ secretKey,
1719
3031
  options,
1720
3032
  environment = "sandbox",
1721
3033
  paymentObject = {
3034
+ merchantName: "",
1722
3035
  amount: 0,
1723
3036
  currency: "",
1724
3037
  email: "",
@@ -1727,7 +3040,7 @@ function BzpCheckoutCard({
1727
3040
  redirectUrl: ""
1728
3041
  }
1729
3042
  }) {
1730
- const [checkoutState, setCheckoutState] = useState7("PAYMENT");
3043
+ const [checkoutState, setCheckoutState] = useState7("PENDING");
1731
3044
  const paymentTypeOptions = [
1732
3045
  { label: "Card", value: "CARD" },
1733
3046
  { label: "Bank Transfer", value: "BANK_TRANSFER" },
@@ -1735,10 +3048,25 @@ function BzpCheckoutCard({
1735
3048
  ];
1736
3049
  const [filteredPaymentTypeOptions, setFilteredPaymentTypeOptions] = useState7([]);
1737
3050
  const [paymentType, setPaymentType] = useState7("");
3051
+ const [successObject, setSuccessObject] = useState7({
3052
+ paymentDate: "",
3053
+ paymentId: "",
3054
+ paymentStatus: ""
3055
+ });
1738
3056
  const paymentTypeHandler = (event) => {
1739
3057
  setPaymentType(event);
1740
3058
  };
1741
- useEffect4(() => {
3059
+ const setSuccess = (event) => {
3060
+ setSuccessObject({ ...event });
3061
+ if (successObject.paymentStatus === "pending") {
3062
+ setCheckoutState("PENDING");
3063
+ } else if (successObject.paymentStatus === "used") {
3064
+ setCheckoutState("USED");
3065
+ } else {
3066
+ setCheckoutState("SUCCESS");
3067
+ }
3068
+ };
3069
+ useEffect6(() => {
1742
3070
  let options2 = [];
1743
3071
  if (paymentObject.currency === "USD") {
1744
3072
  options2 = paymentTypeOptions.filter(
@@ -1751,63 +3079,91 @@ function BzpCheckoutCard({
1751
3079
  }
1752
3080
  setFilteredPaymentTypeOptions(options2);
1753
3081
  }, [paymentObject.currency]);
1754
- useEffect4(() => {
3082
+ useEffect6(() => {
1755
3083
  if (filteredPaymentTypeOptions.length) {
1756
3084
  setPaymentType(filteredPaymentTypeOptions[0].value);
1757
3085
  }
1758
3086
  }, [filteredPaymentTypeOptions]);
1759
- return /* @__PURE__ */ jsx30(BaseCard, { showBackButton: checkoutState === "STABLE_COIN_PAYMENT", children: /* @__PURE__ */ jsxs20("div", { className: "grid grid-cols-3", children: [
1760
- checkoutState === "PAYMENT" && /* @__PURE__ */ jsxs20("div", { className: "bg-[#EFF7FF] px-6 py-8 flex flex-col gap-5 col-span-1 rounded-l-xl", children: [
3087
+ return /* @__PURE__ */ jsx30(BaseCard, { children: /* @__PURE__ */ jsxs20("div", { className: "grid grid-cols-3", children: [
3088
+ checkoutState === "PENDING" && /* @__PURE__ */ jsxs20("div", { className: "bg-[#EFF7FF] px-6 py-8 flex flex-col gap-5 col-span-1 rounded-l-xl", children: [
1761
3089
  /* @__PURE__ */ jsx30("p", { className: "text-heading-text text-body-xs font-semibold", children: "Pay with" }),
1762
3090
  /* @__PURE__ */ jsx30(
1763
3091
  BaseRadioGroup,
1764
3092
  {
1765
- options: paymentTypeOptions,
3093
+ options: filteredPaymentTypeOptions,
1766
3094
  selectedChange: (e) => paymentTypeHandler(e)
1767
3095
  }
1768
3096
  )
1769
3097
  ] }),
1770
- /* @__PURE__ */ jsxs20("div", { className: "col-span-2", children: [
1771
- (checkoutState === "PAYMENT" || checkoutState === "STABLE_COIN_PAYMENT") && /* @__PURE__ */ jsxs20("div", { children: [
1772
- checkoutState === "PAYMENT" && /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-between px-12 py-8", children: [
1773
- options?.imageUrl ? /* @__PURE__ */ jsx30(
1774
- BaseImage,
3098
+ /* @__PURE__ */ jsxs20(
3099
+ "div",
3100
+ {
3101
+ className: checkoutState === "SUCCESS" ? "col-span-3" : "col-span-2",
3102
+ children: [
3103
+ checkoutState === "PENDING" && /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-between px-12 py-8", children: [
3104
+ options?.imageUrl ? /* @__PURE__ */ jsx30(
3105
+ BaseImage,
3106
+ {
3107
+ src: options?.imageUrl ?? "",
3108
+ alt: "Merchant Logo",
3109
+ width: 52,
3110
+ height: 52,
3111
+ customClass: "rounded-lg"
3112
+ }
3113
+ ) : /* @__PURE__ */ jsx30(
3114
+ "div",
3115
+ {
3116
+ className: "bg-heading-text rounded flex flex-col justify-center",
3117
+ style: { width: "52px", height: "52px" },
3118
+ children: /* @__PURE__ */ jsx30("p", { className: "text-white text-center text-body-2xs font-medium", children: "Logo" })
3119
+ }
3120
+ ),
3121
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-1", children: [
3122
+ /* @__PURE__ */ jsx30("p", { className: "text-body-2xs font-regular text-sub-copy text-right", children: paymentObject.merchantName }),
3123
+ /* @__PURE__ */ jsxs20("p", { className: "text-body-2xs font-regular text-sub-copy text-right", children: [
3124
+ "Pay:",
3125
+ " ",
3126
+ /* @__PURE__ */ jsx30("span", { className: "text-orange-500 font-extrabold", children: formatAmount(paymentObject.amount, paymentObject.currency) })
3127
+ ] })
3128
+ ] })
3129
+ ] }),
3130
+ checkoutState === "PENDING" && /* @__PURE__ */ jsx30("div", { className: "overflow-y-scroll px-10 pb-10 pt-2", children: paymentType === "CARD" ? /* @__PURE__ */ jsx30(
3131
+ PayByCard,
3132
+ {
3133
+ secretKey,
3134
+ environment,
3135
+ paymentObject,
3136
+ onPaymentAuthorized: setSuccess
3137
+ }
3138
+ ) : paymentType === "BANK_TRANSFER" ? /* @__PURE__ */ jsx30(
3139
+ PayByTransfer,
1775
3140
  {
1776
- src: options?.imageUrl ?? "",
1777
- alt: "Merchant Logo",
1778
- width: 52,
1779
- height: 52,
1780
- customClass: "rounded-lg"
3141
+ secretKey,
3142
+ environment,
3143
+ paymentObject,
3144
+ onPaymentAuthorized: setSuccess
1781
3145
  }
1782
3146
  ) : /* @__PURE__ */ jsx30(
1783
- "div",
3147
+ PayByStableCoin,
1784
3148
  {
1785
- className: "bg-heading-text rounded flex flex-col justify-center",
1786
- style: { width: "52px", height: "52px" },
1787
- children: /* @__PURE__ */ jsx30("p", { className: "text-white text-center text-body-2xs font-medium", children: "Logo" })
3149
+ secretKey,
3150
+ environment,
3151
+ paymentObject,
3152
+ onPaymentAuthorized: setSuccess
1788
3153
  }
1789
- ),
1790
- /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-1", children: [
1791
- /* @__PURE__ */ jsx30("p", { className: "text-body-2xs font-regular text-sub-copy text-right", children: "Raymahni Merchant LLC" }),
1792
- /* @__PURE__ */ jsxs20("p", { className: "text-body-2xs font-regular text-sub-copy text-right", children: [
1793
- "Pay:",
1794
- " ",
1795
- /* @__PURE__ */ jsx30("span", { className: "text-orange-500 font-extrabold", children: formatAmount(
1796
- paymentObject.amount,
1797
- paymentObject.currency
1798
- ) })
1799
- ] })
1800
- ] })
1801
- ] }),
1802
- /* @__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(
1803
- PayByStableCoin,
1804
- {
1805
- onProceedToPay: () => setCheckoutState("STABLE_COIN_PAYMENT")
1806
- }
1807
- ) })
1808
- ] }),
1809
- checkoutState === "SUCCESS" && /* @__PURE__ */ jsx30(BaseSuccess, {})
1810
- ] })
3154
+ ) }),
3155
+ checkoutState === "SUCCESS" && /* @__PURE__ */ jsx30(
3156
+ BaseSuccess,
3157
+ {
3158
+ amount: paymentObject.amount,
3159
+ currency: paymentObject.currency,
3160
+ redirectUrl: paymentObject.redirectUrl,
3161
+ successObject
3162
+ }
3163
+ )
3164
+ ]
3165
+ }
3166
+ )
1811
3167
  ] }) });
1812
3168
  }
1813
3169
  export {