@reevit/react 0.5.9 → 0.7.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/README.md CHANGED
@@ -5,7 +5,7 @@ Unified Payment Widget for React Applications. Accept card and mobile money paym
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @reevit/react@0.5.0
8
+ npm install @reevit/react
9
9
  ```
10
10
 
11
11
  ## Quick Start
@@ -23,6 +23,7 @@ function App() {
23
23
  amount={10000} // Amount in smallest unit (e.g., pesewas for GHS)
24
24
  currency="GHS"
25
25
  email="customer@example.com"
26
+ idempotencyKey={`order_${Date.now()}`}
26
27
  onSuccess={(result) => {
27
28
  console.log('Payment success!', result);
28
29
  alert(`Payment of ${result.currency} ${result.amount/100} successful!`);
@@ -37,6 +38,19 @@ function App() {
37
38
  }
38
39
  ```
39
40
 
41
+ ## Idempotency
42
+
43
+ Provide an `idempotencyKey` tied to your order/cart to avoid duplicate intent creation and enable safe retries.
44
+
45
+ ```tsx
46
+ <ReevitCheckout
47
+ publicKey="pk_test_your_key"
48
+ amount={10000}
49
+ currency="GHS"
50
+ idempotencyKey="order_12345"
51
+ />
52
+ ```
53
+
40
54
  ## Payment Links
41
55
 
42
56
  If you have a hosted payment link, pass the link code. The widget will create the payment intent from the public link endpoint.
@@ -279,6 +293,20 @@ function MpesaPayment() {
279
293
  | Monnify | NG | Card, Bank Transfer, USSD |
280
294
  | M-Pesa | KE, TZ | Mobile Money (STK Push) |
281
295
 
296
+ ## Release Notes
297
+
298
+ ### v0.7.0
299
+
300
+ - Redesigned checkout UI with premium visual polish
301
+ - New typography system: Grato Classic for body, ABC Repro Mono for amounts
302
+ - Layered shadow system for natural depth
303
+ - Replaced emoji icons with inline SVG icons (consistent cross-platform rendering)
304
+ - New loading animation (three-dot pulse), success glow effect, and countdown bar
305
+ - Improved dark mode contrast and surfaces
306
+ - Mobile bottom-sheet pattern with touch-friendly targets (44px+)
307
+ - Smoother animations with cubic-bezier easing curves
308
+ - Removed external Google Fonts dependency (zero network requests for fonts)
309
+
282
310
  ## License
283
311
 
284
312
  MIT © [Reevit](https://reevit.io)
package/dist/index.d.mts CHANGED
@@ -22,6 +22,8 @@ interface ReevitCheckoutConfig {
22
22
  customerName?: string;
23
23
  /** Unique reference for this transaction */
24
24
  reference?: string;
25
+ /** Optional idempotency key to safely retry or dedupe intent creation */
26
+ idempotencyKey?: string;
25
27
  /** Additional metadata to attach to the payment */
26
28
  metadata?: Record<string, unknown>;
27
29
  /** Custom fields for payment links (if applicable) */
package/dist/index.d.ts CHANGED
@@ -22,6 +22,8 @@ interface ReevitCheckoutConfig {
22
22
  customerName?: string;
23
23
  /** Unique reference for this transaction */
24
24
  reference?: string;
25
+ /** Optional idempotency key to safely retry or dedupe intent creation */
26
+ idempotencyKey?: string;
25
27
  /** Additional metadata to attach to the payment */
26
28
  metadata?: Record<string, unknown>;
27
29
  /** Custom fields for payment links (if applicable) */
package/dist/index.js CHANGED
@@ -259,7 +259,7 @@ var ReevitAPIClient = class {
259
259
  allowed_providers: options?.allowedProviders
260
260
  };
261
261
  }
262
- const idempotencyKey = generateIdempotencyKey({
262
+ const idempotencyKey = config.idempotencyKey || generateIdempotencyKey({
263
263
  amount: config.amount,
264
264
  currency: config.currency,
265
265
  customer: config.email || config.metadata?.customerId || "",
@@ -438,6 +438,72 @@ function normalizeBranding(branding) {
438
438
  setIf("selectedBorderColor", getString(raw.selectedBorderColor ?? raw.selected_border_color));
439
439
  return theme;
440
440
  }
441
+ var INTENT_CACHE_TTL_MS = 10 * 60 * 1e3;
442
+ var intentCache = /* @__PURE__ */ new Map();
443
+ function pruneIntentCache(now = Date.now()) {
444
+ for (const [key, entry] of intentCache) {
445
+ if (entry.expiresAt <= now) {
446
+ intentCache.delete(key);
447
+ }
448
+ }
449
+ }
450
+ function getIntentCacheEntry(key) {
451
+ const entry = intentCache.get(key);
452
+ if (!entry) {
453
+ return void 0;
454
+ }
455
+ if (entry.expiresAt <= Date.now()) {
456
+ intentCache.delete(key);
457
+ return void 0;
458
+ }
459
+ return entry;
460
+ }
461
+ function setIntentCacheEntry(key, update) {
462
+ const now = Date.now();
463
+ const existing = getIntentCacheEntry(key);
464
+ const next = {
465
+ ...existing,
466
+ ...update,
467
+ expiresAt: now + INTENT_CACHE_TTL_MS
468
+ };
469
+ intentCache.set(key, next);
470
+ return next;
471
+ }
472
+ function clearIntentCacheEntry(key) {
473
+ intentCache.delete(key);
474
+ }
475
+ function buildIdempotencyPayload(config, method, options) {
476
+ const payload = {
477
+ amount: config.amount,
478
+ currency: config.currency,
479
+ email: config.email || "",
480
+ phone: config.phone || "",
481
+ customerName: config.customerName || "",
482
+ paymentLinkCode: config.paymentLinkCode || "",
483
+ paymentMethods: config.paymentMethods || [],
484
+ metadata: config.metadata || {},
485
+ customFields: config.customFields || {},
486
+ method: method || "",
487
+ preferredProvider: options?.preferredProvider || "",
488
+ allowedProviders: options?.allowedProviders || [],
489
+ publicKey: config.publicKey || ""
490
+ };
491
+ if (config.reference) {
492
+ payload.reference = config.reference;
493
+ }
494
+ return payload;
495
+ }
496
+ function resolveIntentIdentity(config, method, options) {
497
+ pruneIntentCache();
498
+ const idempotencyKey = config.idempotencyKey || generateIdempotencyKey(buildIdempotencyPayload(config, method, options));
499
+ const existing = getIntentCacheEntry(idempotencyKey);
500
+ const reference = config.reference || existing?.reference || generateReference();
501
+ const cacheEntry = setIntentCacheEntry(idempotencyKey, { reference });
502
+ return { idempotencyKey, reference, cacheEntry };
503
+ }
504
+ function isPaymentError(error) {
505
+ return typeof error === "object" && error !== null && "code" in error && "message" in error;
506
+ }
441
507
  function mapToPaymentIntent(response, config) {
442
508
  return {
443
509
  id: response.id,
@@ -471,14 +537,22 @@ function useReevit(options) {
471
537
  selectedMethod: config.initialPaymentIntent?.availableMethods?.length === 1 ? config.initialPaymentIntent.availableMethods[0] : null
472
538
  });
473
539
  const apiClientRef = react.useRef(null);
474
- const initializingRef = react.useRef(!!config.initialPaymentIntent);
540
+ const stateRef = react.useRef(state);
541
+ react.useEffect(() => {
542
+ stateRef.current = state;
543
+ }, [state]);
544
+ const currentIntentKeyRef = react.useRef(
545
+ config.initialPaymentIntent ? `initial:${config.initialPaymentIntent.id}` : null
546
+ );
475
547
  const initRequestIdRef = react.useRef(0);
476
548
  react.useEffect(() => {
477
549
  if (config.initialPaymentIntent) {
478
550
  if (!state.paymentIntent || state.paymentIntent.id !== config.initialPaymentIntent.id) {
479
551
  dispatch({ type: "INIT_SUCCESS", payload: config.initialPaymentIntent });
480
- initializingRef.current = true;
552
+ currentIntentKeyRef.current = `initial:${config.initialPaymentIntent.id}`;
481
553
  }
554
+ } else if (currentIntentKeyRef.current?.startsWith("initial:")) {
555
+ currentIntentKeyRef.current = null;
482
556
  }
483
557
  }, [config.initialPaymentIntent, state.paymentIntent?.id]);
484
558
  if (!apiClientRef.current) {
@@ -492,61 +566,60 @@ function useReevit(options) {
492
566
  }, [state.status, onStateChange]);
493
567
  const initialize = react.useCallback(
494
568
  async (method, options2) => {
495
- if (initializingRef.current) {
569
+ if (config.initialPaymentIntent) {
496
570
  return;
497
571
  }
498
- initializingRef.current = true;
499
- const requestId = ++initRequestIdRef.current;
500
- dispatch({ type: "INIT_START" });
572
+ let requestId = 0;
573
+ let intentKey = null;
501
574
  try {
502
575
  const apiClient = apiClientRef.current;
503
576
  if (!apiClient) {
504
577
  throw new Error("API client not initialized");
505
578
  }
506
- const reference = config.reference || generateReference();
507
579
  const country = detectCountryFromCurrency(config.currency);
508
580
  const defaultMethod = config.paymentMethods && config.paymentMethods.length === 1 ? config.paymentMethods[0] : void 0;
509
581
  const paymentMethod = method ?? defaultMethod;
510
- let data;
511
- let error;
512
- if (config.paymentLinkCode) {
513
- const idempotencyKey = generateIdempotencyKey({
514
- paymentLinkCode: config.paymentLinkCode,
515
- amount: config.amount,
516
- email: config.email || "",
517
- phone: config.phone || "",
518
- method: paymentMethod || "",
519
- provider: options2?.preferredProvider || options2?.allowedProviders?.[0] || ""
520
- });
521
- const response = await fetch(
522
- `${apiBaseUrl || DEFAULT_PUBLIC_API_BASE_URL}/v1/pay/${config.paymentLinkCode}/pay`,
523
- {
524
- method: "POST",
525
- headers: {
526
- "Content-Type": "application/json",
527
- "Idempotency-Key": idempotencyKey
528
- },
529
- body: JSON.stringify({
530
- amount: config.amount,
531
- email: config.email || "",
532
- name: config.customerName || "",
533
- phone: config.phone || "",
534
- method: paymentMethod,
535
- country,
536
- provider: options2?.preferredProvider || options2?.allowedProviders?.[0],
537
- custom_fields: config.customFields
538
- })
582
+ const identity = resolveIntentIdentity(config, paymentMethod, options2);
583
+ const { idempotencyKey, reference, cacheEntry } = identity;
584
+ intentKey = idempotencyKey;
585
+ if (currentIntentKeyRef.current === idempotencyKey && stateRef.current.paymentIntent) {
586
+ return;
587
+ }
588
+ currentIntentKeyRef.current = idempotencyKey;
589
+ requestId = ++initRequestIdRef.current;
590
+ if (stateRef.current.status !== "loading") {
591
+ dispatch({ type: "INIT_START" });
592
+ }
593
+ const requestIntent = async () => {
594
+ if (config.paymentLinkCode) {
595
+ const response = await fetch(
596
+ `${apiBaseUrl || DEFAULT_PUBLIC_API_BASE_URL}/v1/pay/${config.paymentLinkCode}/pay`,
597
+ {
598
+ method: "POST",
599
+ headers: {
600
+ "Content-Type": "application/json",
601
+ "Idempotency-Key": idempotencyKey
602
+ },
603
+ body: JSON.stringify({
604
+ amount: config.amount,
605
+ email: config.email || "",
606
+ name: config.customerName || "",
607
+ phone: config.phone || "",
608
+ method: paymentMethod,
609
+ country,
610
+ provider: options2?.preferredProvider || options2?.allowedProviders?.[0],
611
+ custom_fields: config.customFields
612
+ })
613
+ }
614
+ );
615
+ const responseData = await response.json().catch(() => ({}));
616
+ if (!response.ok) {
617
+ throw buildPaymentLinkError(response, responseData);
539
618
  }
540
- );
541
- const responseData = await response.json().catch(() => ({}));
542
- if (!response.ok) {
543
- error = buildPaymentLinkError(response, responseData);
544
- } else {
545
- data = responseData;
619
+ return responseData;
546
620
  }
547
- } else {
548
621
  const result = await apiClient.createPaymentIntent(
549
- { ...config, reference },
622
+ { ...config, reference, idempotencyKey },
550
623
  paymentMethod,
551
624
  country,
552
625
  {
@@ -554,35 +627,43 @@ function useReevit(options) {
554
627
  allowedProviders: options2?.allowedProviders
555
628
  }
556
629
  );
557
- data = result.data;
558
- error = result.error;
630
+ if (result.error) {
631
+ throw result.error;
632
+ }
633
+ if (!result.data) {
634
+ throw {
635
+ code: "INIT_FAILED",
636
+ message: "No data received from API",
637
+ recoverable: true
638
+ };
639
+ }
640
+ return result.data;
641
+ };
642
+ let data;
643
+ if (cacheEntry?.response) {
644
+ data = cacheEntry.response;
645
+ } else {
646
+ let intentPromise = cacheEntry?.promise;
647
+ if (!intentPromise) {
648
+ intentPromise = requestIntent();
649
+ setIntentCacheEntry(idempotencyKey, { promise: intentPromise });
650
+ }
651
+ data = await intentPromise;
652
+ setIntentCacheEntry(idempotencyKey, { response: data, promise: void 0 });
559
653
  }
560
654
  if (requestId !== initRequestIdRef.current) {
561
655
  return;
562
656
  }
563
- if (error) {
564
- dispatch({ type: "INIT_ERROR", payload: error });
565
- onError?.(error);
566
- return;
567
- }
568
- if (!data) {
569
- const noDataError = {
570
- code: "INIT_FAILED",
571
- message: "No data received from API",
572
- recoverable: true
573
- };
574
- dispatch({ type: "INIT_ERROR", payload: noDataError });
575
- onError?.(noDataError);
576
- initializingRef.current = false;
577
- return;
578
- }
579
- const paymentIntent = mapToPaymentIntent(data, { ...config, reference });
657
+ const paymentIntent = mapToPaymentIntent(data, { ...config, reference, idempotencyKey });
580
658
  dispatch({ type: "INIT_SUCCESS", payload: paymentIntent });
581
659
  } catch (err) {
660
+ if (intentKey) {
661
+ clearIntentCacheEntry(intentKey);
662
+ }
582
663
  if (requestId !== initRequestIdRef.current) {
583
664
  return;
584
665
  }
585
- const error = {
666
+ const error = isPaymentError(err) ? err : {
586
667
  code: "INIT_FAILED",
587
668
  message: err instanceof Error ? err.message : "Failed to initialize checkout",
588
669
  recoverable: true,
@@ -590,7 +671,6 @@ function useReevit(options) {
590
671
  };
591
672
  dispatch({ type: "INIT_ERROR", payload: error });
592
673
  onError?.(error);
593
- initializingRef.current = false;
594
674
  }
595
675
  },
596
676
  [config, onError, apiBaseUrl]
@@ -671,7 +751,7 @@ function useReevit(options) {
671
751
  } catch {
672
752
  }
673
753
  }
674
- initializingRef.current = false;
754
+ currentIntentKeyRef.current = null;
675
755
  initRequestIdRef.current += 1;
676
756
  dispatch({ type: "RESET" });
677
757
  }, [state.paymentIntent, state.status]);
@@ -737,30 +817,47 @@ function detectCountryFromCurrency(currency) {
737
817
  };
738
818
  return currencyToCountry[currency.toUpperCase()] || "GH";
739
819
  }
820
+ var MethodIcons = {
821
+ card: () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
822
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "1", y: "4", width: "22", height: "16", rx: "3" }),
823
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "1", y1: "10", x2: "23", y2: "10" }),
824
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "5", y1: "15", x2: "9", y2: "15" })
825
+ ] }),
826
+ mobile_money: () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
827
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "5", y: "2", width: "14", height: "20", rx: "3" }),
828
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "18", x2: "12", y2: "18.01", strokeWidth: "2", strokeLinecap: "round" })
829
+ ] }),
830
+ bank_transfer: () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
831
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 21h18" }),
832
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 10h18" }),
833
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3l9 7H3l9-7z" }),
834
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 10v8" }),
835
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 10v8" }),
836
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 10v8" }),
837
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 10v8" })
838
+ ] }),
839
+ apple_pay: () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.53 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" }) }),
840
+ google_pay: () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12.24 10.285V14.4h6.806c-.275 1.765-2.056 5.174-6.806 5.174-4.095 0-7.439-3.389-7.439-7.574s3.345-7.574 7.439-7.574c2.33 0 3.891.989 4.785 1.849l3.254-3.138C18.189 1.186 15.479 0 12.24 0c-6.635 0-12 5.365-12 12s5.365 12 12 12c6.926 0 11.52-4.869 11.52-11.726 0-.788-.085-1.39-.189-1.989H12.24z", fill: "currentColor" }) })
841
+ };
740
842
  var methodConfig = {
741
843
  card: {
742
844
  label: "Card",
743
- icon: "\u{1F4B3}",
744
845
  description: "Pay with Visa, Mastercard, or other cards"
745
846
  },
746
847
  mobile_money: {
747
848
  label: "Mobile Money",
748
- icon: "\u{1F4F1}",
749
849
  description: "MTN, Telecel, AirtelTigo Money"
750
850
  },
751
851
  bank_transfer: {
752
852
  label: "Bank Transfer",
753
- icon: "\u{1F3E6}",
754
853
  description: "Pay directly from your bank account"
755
854
  },
756
855
  apple_pay: {
757
856
  label: "Apple Pay",
758
- icon: "\u{1F34E}",
759
857
  description: "Pay with Apple Pay"
760
858
  },
761
859
  google_pay: {
762
860
  label: "Google Pay",
763
- icon: "\u{1F916}",
764
861
  description: "Pay with Google Pay"
765
862
  }
766
863
  };
@@ -810,7 +907,6 @@ function PaymentMethodSelector({
810
907
  ),
811
908
  style: selectedTheme?.backgroundColor ? { backgroundColor: selectedTheme.backgroundColor } : void 0,
812
909
  children: methods.map((method, index) => {
813
- const config = methodConfig[method];
814
910
  const isSelected = selectedMethod === method;
815
911
  const methodLabel = getMethodLabel(method);
816
912
  const methodDescription = getMethodDescription(method);
@@ -841,7 +937,7 @@ function PaymentMethodSelector({
841
937
  className: "reevit-method-option__logo-img"
842
938
  },
843
939
  i
844
- )) }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "reevit-method-option__icon", children: config.icon }) }),
940
+ )) }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "reevit-method-option__icon", children: MethodIcons[method]() }) }),
845
941
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "reevit-method-option__content", children: [
846
942
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "reevit-method-option__label", style: selectedTheme?.textColor ? { color: selectedTheme.textColor } : void 0, children: methodLabel }),
847
943
  !isGrid && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "reevit-method-option__description", style: selectedTheme?.descriptionColor ? { color: selectedTheme.descriptionColor } : void 0, children: methodDescription })
@@ -2401,7 +2497,11 @@ function ReevitCheckout({
2401
2497
  const renderContent = () => {
2402
2498
  if (status === "loading" || status === "processing") {
2403
2499
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "reevit-loading reevit-animate-fade-in", children: [
2404
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "reevit-spinner" }),
2500
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "reevit-dot-pulse", children: [
2501
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "reevit-dot-pulse__dot" }),
2502
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "reevit-dot-pulse__dot" }),
2503
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "reevit-dot-pulse__dot" })
2504
+ ] }),
2405
2505
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: status === "loading" ? "Preparing checkout..." : "Processing payment..." })
2406
2506
  ] });
2407
2507
  }
@@ -2417,12 +2517,22 @@ function ReevitCheckout({
2417
2517
  "Reference: ",
2418
2518
  result.reference
2419
2519
  ] }),
2420
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "reevit-success__redirect", children: "Redirecting in a moment..." })
2520
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "reevit-success__redirect", children: "Redirecting in a moment..." }),
2521
+ /* @__PURE__ */ jsxRuntime.jsx(
2522
+ "div",
2523
+ {
2524
+ className: "reevit-success__countdown",
2525
+ style: { animationDuration: `${successDelayMs}ms` }
2526
+ }
2527
+ )
2421
2528
  ] });
2422
2529
  }
2423
2530
  if (status === "failed" && error && !error.recoverable) {
2424
2531
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "reevit-error reevit-animate-fade-in", children: [
2425
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "reevit-error__icon", children: "\u2715" }),
2532
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "reevit-error__icon", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2533
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2534
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2535
+ ] }) }),
2426
2536
  /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Payment Failed" }),
2427
2537
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: error.message }),
2428
2538
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: "reevit-btn reevit-btn--primary", onClick: handleBack, children: "Try Again" })
@@ -2544,7 +2654,11 @@ function ReevitCheckout({
2544
2654
  );
2545
2655
  default:
2546
2656
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "reevit-error", children: [
2547
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "reevit-error__icon", children: "\u26A0\uFE0F" }),
2657
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "reevit-error__icon", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2658
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
2659
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
2660
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
2661
+ ] }) }),
2548
2662
  /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Provider Not Supported" }),
2549
2663
  /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
2550
2664
  "Provider (",