@reevit/react 0.3.2 → 0.3.4

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.mjs CHANGED
@@ -111,7 +111,7 @@ var ReevitAPIClient = class {
111
111
  "Content-Type": "application/json",
112
112
  "X-Reevit-Key": this.publicKey,
113
113
  "X-Reevit-Client": "@reevit/react",
114
- "X-Reevit-Client-Version": "0.2.5"
114
+ "X-Reevit-Client-Version": "0.3.2"
115
115
  };
116
116
  if (method === "POST" || method === "PATCH" || method === "PUT") {
117
117
  headers["Idempotency-Key"] = `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
@@ -267,6 +267,9 @@ function mapProviderToPsp(provider) {
267
267
  if (providerLower.includes("paystack")) return "paystack";
268
268
  if (providerLower.includes("hubtel")) return "hubtel";
269
269
  if (providerLower.includes("flutterwave")) return "flutterwave";
270
+ if (providerLower.includes("monnify")) return "monnify";
271
+ if (providerLower.includes("mpesa") || providerLower.includes("m-pesa")) return "mpesa";
272
+ if (providerLower.includes("stripe")) return "stripe";
270
273
  return "paystack";
271
274
  }
272
275
  function mapToPaymentIntent(response, config) {
@@ -801,384 +804,102 @@ function PaystackBridge({
801
804
  /* @__PURE__ */ jsx("p", { children: "Connecting to Paystack..." })
802
805
  ] }) });
803
806
  }
804
- var ReevitContext = createContext(null);
805
- function useReevitContext() {
806
- const context = useContext(ReevitContext);
807
- if (!context) {
808
- throw new Error("useReevitContext must be used within ReevitCheckout");
809
- }
810
- return context;
807
+ function loadHubtelScript() {
808
+ return new Promise((resolve, reject) => {
809
+ if (window.HubtelCheckout) {
810
+ resolve();
811
+ return;
812
+ }
813
+ const script = document.createElement("script");
814
+ script.src = "https://checkout.hubtel.com/checkout.js";
815
+ script.async = true;
816
+ script.onload = () => resolve();
817
+ script.onerror = () => reject(new Error("Failed to load Hubtel script"));
818
+ document.head.appendChild(script);
819
+ });
811
820
  }
812
- function ReevitCheckout({
813
- // Config
814
- publicKey,
821
+ function HubtelBridge({
822
+ merchantAccount,
815
823
  amount,
816
- currency,
817
- email = "",
818
- phone = "",
824
+ currency = "GHS",
819
825
  reference,
820
- metadata,
821
- paymentMethods = ["card", "mobile_money"],
822
- initialPaymentIntent,
823
- // Callbacks
826
+ email,
827
+ phone,
828
+ description = "Payment",
824
829
  onSuccess,
825
830
  onError,
826
831
  onClose,
827
- onStateChange,
828
- // UI
829
- children,
830
- autoOpen = false,
831
- isOpen: controlledIsOpen,
832
- onOpenChange,
833
- theme,
834
- apiBaseUrl
832
+ autoStart = true
835
833
  }) {
836
- const [internalIsOpen, setInternalIsOpen] = useState(autoOpen);
837
- const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
838
- const setIsOpen = useCallback(
839
- (value) => {
840
- if (onOpenChange) {
841
- onOpenChange(value);
842
- } else {
843
- setInternalIsOpen(value);
834
+ const initialized = useRef(false);
835
+ const startPayment = useCallback(async () => {
836
+ try {
837
+ await loadHubtelScript();
838
+ if (!window.HubtelCheckout) {
839
+ throw new Error("Hubtel checkout not available");
844
840
  }
845
- },
846
- [onOpenChange]
847
- );
848
- const [showPSPBridge, setShowPSPBridge] = useState(false);
849
- const [momoData, setMomoData] = useState(null);
850
- const {
851
- status,
852
- paymentIntent,
853
- selectedMethod,
854
- error,
855
- result,
856
- initialize,
857
- selectMethod,
858
- processPayment,
859
- reset,
860
- close: closeCheckout,
861
- isLoading,
862
- isComplete
863
- } = useReevit({
864
- config: {
865
- publicKey,
866
- amount,
867
- currency,
868
- email,
869
- phone,
870
- reference,
871
- metadata,
872
- paymentMethods,
873
- initialPaymentIntent
874
- },
875
- apiBaseUrl,
876
- onSuccess: (result2) => {
877
- onSuccess?.(result2);
878
- setTimeout(() => {
879
- setIsOpen(false);
880
- }, 2e3);
881
- },
882
- onError,
883
- onClose: () => {
884
- setIsOpen(false);
885
- onClose?.();
886
- },
887
- onStateChange
888
- });
889
- useEffect(() => {
890
- if (isOpen && status === "idle" && !initialPaymentIntent) {
891
- initialize();
841
+ window.HubtelCheckout.initPayment({
842
+ merchantAccount,
843
+ basicDescription: description,
844
+ totalAmount: amount / 100,
845
+ // Hubtel expects amount in major units (GHS, not pesewas)
846
+ currency,
847
+ clientReference: reference || `hubtel_${Date.now()}`,
848
+ customerEmail: email,
849
+ customerMsisdn: phone,
850
+ onComplete: (response) => {
851
+ if (response.status === "Success") {
852
+ const result = {
853
+ paymentId: response.transactionId,
854
+ reference: response.clientReference,
855
+ amount: Math.round(response.amount * 100),
856
+ // Convert back to pesewas
857
+ currency: response.currency,
858
+ paymentMethod: "mobile_money",
859
+ psp: "hubtel",
860
+ pspReference: response.transactionId,
861
+ status: "success"
862
+ };
863
+ onSuccess(result);
864
+ } else {
865
+ const error = {
866
+ code: "PAYMENT_FAILED",
867
+ message: response.message || "Payment failed",
868
+ recoverable: true
869
+ };
870
+ onError(error);
871
+ }
872
+ },
873
+ onCancel: () => {
874
+ onClose();
875
+ }
876
+ });
877
+ } catch (err) {
878
+ const error = {
879
+ code: "PSP_ERROR",
880
+ message: "Failed to initialize Hubtel",
881
+ recoverable: true,
882
+ originalError: err
883
+ };
884
+ onError(error);
892
885
  }
893
- }, [isOpen, status, initialize, initialPaymentIntent]);
886
+ }, [merchantAccount, amount, currency, reference, email, phone, description, onSuccess, onError, onClose]);
894
887
  useEffect(() => {
895
- if (isOpen && selectedMethod && paymentIntent && !showPSPBridge) {
896
- if (selectedMethod === "card") {
897
- setShowPSPBridge(true);
898
- } else if (selectedMethod === "mobile_money" && (momoData?.phone || phone)) {
899
- setShowPSPBridge(true);
900
- }
901
- }
902
- }, [isOpen, selectedMethod, showPSPBridge, paymentIntent, momoData, phone]);
903
- const handleOpen = useCallback(() => {
904
- if (controlledIsOpen !== void 0) return;
905
- setIsOpen(true);
906
- setShowPSPBridge(false);
907
- setMomoData(null);
908
- }, [controlledIsOpen, setIsOpen]);
909
- const handleClose = useCallback(() => {
910
- closeCheckout();
911
- setIsOpen(false);
912
- setShowPSPBridge(false);
913
- setMomoData(null);
914
- }, [closeCheckout, setIsOpen]);
915
- const handleMethodSelect = useCallback(
916
- (method) => {
917
- selectMethod(method);
918
- },
919
- [selectMethod]
920
- );
921
- const handleContinue = useCallback(() => {
922
- if (!selectedMethod) return;
923
- if (selectedMethod === "card") {
924
- setShowPSPBridge(true);
925
- }
926
- }, [selectedMethod]);
927
- const handleMomoSubmit = useCallback(
928
- (data) => {
929
- setMomoData(data);
930
- setShowPSPBridge(true);
931
- },
932
- []
933
- );
934
- const handlePSPSuccess = useCallback(
935
- (pspResult) => {
936
- processPayment({ ...pspResult, momoData });
937
- },
938
- [processPayment, momoData]
939
- );
940
- const handlePSPError = useCallback(
941
- (error2) => {
942
- setShowPSPBridge(false);
943
- onError?.(error2);
944
- },
945
- [onError]
946
- );
947
- const handlePSPClose = useCallback(() => {
948
- setShowPSPBridge(false);
949
- }, []);
950
- const handleBack = useCallback(() => {
951
- reset();
952
- setMomoData(null);
953
- setShowPSPBridge(false);
954
- }, [reset]);
955
- const themeStyles = theme ? createThemeVariables(theme) : {};
956
- const isControlled = controlledIsOpen !== void 0;
957
- const trigger = children ? /* @__PURE__ */ jsx("span", { onClick: isControlled ? void 0 : handleOpen, role: isControlled ? void 0 : "button", tabIndex: isControlled ? void 0 : 0, children }) : !isControlled ? /* @__PURE__ */ jsxs("button", { className: "reevit-trigger-btn", onClick: handleOpen, children: [
958
- "Pay ",
959
- formatAmount(amount, currency)
960
- ] }) : null;
961
- const renderContent = () => {
962
- if (status === "loading" || status === "processing") {
963
- return /* @__PURE__ */ jsxs("div", { className: "reevit-loading", children: [
964
- /* @__PURE__ */ jsx("div", { className: "reevit-spinner" }),
965
- /* @__PURE__ */ jsx("p", { children: status === "loading" ? "Preparing checkout..." : "Processing payment..." })
966
- ] });
967
- }
968
- if (status === "success" && result) {
969
- return /* @__PURE__ */ jsxs("div", { className: "reevit-success", children: [
970
- /* @__PURE__ */ jsx("div", { className: "reevit-success__icon", children: "\u2713" }),
971
- /* @__PURE__ */ jsx("h3", { children: "Payment Successful" }),
972
- /* @__PURE__ */ jsxs("p", { children: [
973
- "Reference: ",
974
- result.reference
975
- ] })
976
- ] });
888
+ if (autoStart && !initialized.current) {
889
+ initialized.current = true;
890
+ startPayment();
977
891
  }
978
- if (status === "failed" && error && !error.recoverable) {
979
- return /* @__PURE__ */ jsxs("div", { className: "reevit-error", children: [
980
- /* @__PURE__ */ jsx("div", { className: "reevit-error__icon", children: "\u2715" }),
981
- /* @__PURE__ */ jsx("h3", { children: "Payment Failed" }),
982
- /* @__PURE__ */ jsx("p", { children: error.message }),
983
- /* @__PURE__ */ jsx("button", { className: "reevit-btn reevit-btn--primary", onClick: handleBack, children: "Try Again" })
984
- ] });
985
- }
986
- if (showPSPBridge) {
987
- const pspKey = paymentIntent?.pspPublicKey || publicKey;
988
- return /* @__PURE__ */ jsx(
989
- PaystackBridge,
990
- {
991
- publicKey: pspKey,
992
- email,
993
- phone: momoData?.phone || phone,
994
- amount: paymentIntent?.amount ?? amount,
995
- currency: paymentIntent?.currency ?? currency,
996
- reference,
997
- accessCode: paymentIntent?.clientSecret,
998
- metadata: {
999
- ...metadata,
1000
- // Override with correct payment intent ID for webhook routing
1001
- // This ensures Paystack webhook includes the correct ID to find the payment
1002
- payment_id: paymentIntent?.id,
1003
- connection_id: paymentIntent?.connectionId ?? metadata?.connection_id,
1004
- customer_phone: momoData?.phone || phone
1005
- },
1006
- channels: selectedMethod === "mobile_money" ? ["mobile_money"] : ["card"],
1007
- onSuccess: handlePSPSuccess,
1008
- onError: handlePSPError,
1009
- onClose: handlePSPClose
1010
- }
1011
- );
1012
- }
1013
- if (selectedMethod === "mobile_money" && !showPSPBridge) {
1014
- return /* @__PURE__ */ jsx(
1015
- MobileMoneyForm,
1016
- {
1017
- onSubmit: handleMomoSubmit,
1018
- onCancel: handleBack,
1019
- isLoading,
1020
- initialPhone: phone
1021
- }
1022
- );
1023
- }
1024
- return /* @__PURE__ */ jsxs("div", { className: "reevit-method-step", children: [
1025
- /* @__PURE__ */ jsx(
1026
- PaymentMethodSelector,
1027
- {
1028
- methods: paymentMethods,
1029
- selectedMethod,
1030
- onSelect: handleMethodSelect,
1031
- disabled: isLoading
1032
- }
1033
- ),
1034
- selectedMethod && selectedMethod !== "mobile_money" && /* @__PURE__ */ jsx("div", { className: "reevit-method-step__actions", children: /* @__PURE__ */ jsx(
1035
- "button",
1036
- {
1037
- className: "reevit-btn reevit-btn--primary",
1038
- onClick: handleContinue,
1039
- disabled: isLoading,
1040
- children: "Continue"
1041
- }
1042
- ) })
1043
- ] });
1044
- };
1045
- return /* @__PURE__ */ jsxs(ReevitContext.Provider, { value: { publicKey, amount, currency }, children: [
1046
- trigger,
1047
- isOpen && /* @__PURE__ */ jsx("div", { className: "reevit-overlay", onClick: handleClose, children: /* @__PURE__ */ jsxs(
1048
- "div",
1049
- {
1050
- className: cn("reevit-modal", isComplete && "reevit-modal--success"),
1051
- style: themeStyles,
1052
- onClick: (e) => e.stopPropagation(),
1053
- role: "dialog",
1054
- "aria-modal": "true",
1055
- children: [
1056
- /* @__PURE__ */ jsxs("div", { className: "reevit-modal__header", children: [
1057
- /* @__PURE__ */ jsx("div", { className: "reevit-modal__branding", children: /* @__PURE__ */ jsx(
1058
- "img",
1059
- {
1060
- src: "https://i.imgur.com/bzUR5Lm.png",
1061
- alt: "Reevit",
1062
- className: "reevit-modal__logo"
1063
- }
1064
- ) }),
1065
- /* @__PURE__ */ jsx(
1066
- "button",
1067
- {
1068
- className: "reevit-modal__close",
1069
- onClick: handleClose,
1070
- "aria-label": "Close",
1071
- children: "\u2715"
1072
- }
1073
- )
1074
- ] }),
1075
- /* @__PURE__ */ jsxs("div", { className: "reevit-modal__amount", children: [
1076
- /* @__PURE__ */ jsx("span", { className: "reevit-modal__amount-label", children: "Amount" }),
1077
- /* @__PURE__ */ jsx("span", { className: "reevit-modal__amount-value", children: formatAmount(amount, currency) })
1078
- ] }),
1079
- /* @__PURE__ */ jsx("div", { className: "reevit-modal__content", children: renderContent() }),
1080
- /* @__PURE__ */ jsx("div", { className: "reevit-modal__footer", children: /* @__PURE__ */ jsx("span", { className: "reevit-modal__secured", children: "\u{1F512} Secured by Reevit" }) })
1081
- ]
1082
- }
1083
- ) })
1084
- ] });
1085
- }
1086
- function loadHubtelScript() {
1087
- return new Promise((resolve, reject) => {
1088
- if (window.HubtelCheckout) {
1089
- resolve();
1090
- return;
1091
- }
1092
- const script = document.createElement("script");
1093
- script.src = "https://checkout.hubtel.com/checkout.js";
1094
- script.async = true;
1095
- script.onload = () => resolve();
1096
- script.onerror = () => reject(new Error("Failed to load Hubtel script"));
1097
- document.head.appendChild(script);
1098
- });
1099
- }
1100
- function HubtelBridge({
1101
- merchantAccount,
1102
- amount,
1103
- currency = "GHS",
1104
- reference,
1105
- email,
1106
- phone,
1107
- description = "Payment",
1108
- onSuccess,
1109
- onError,
1110
- onClose,
1111
- autoStart = true
1112
- }) {
1113
- const initialized = useRef(false);
1114
- const startPayment = useCallback(async () => {
1115
- try {
1116
- await loadHubtelScript();
1117
- if (!window.HubtelCheckout) {
1118
- throw new Error("Hubtel checkout not available");
1119
- }
1120
- window.HubtelCheckout.initPayment({
1121
- merchantAccount,
1122
- basicDescription: description,
1123
- totalAmount: amount / 100,
1124
- // Hubtel expects amount in major units (GHS, not pesewas)
1125
- currency,
1126
- clientReference: reference || `hubtel_${Date.now()}`,
1127
- customerEmail: email,
1128
- customerMsisdn: phone,
1129
- onComplete: (response) => {
1130
- if (response.status === "Success") {
1131
- const result = {
1132
- paymentId: response.transactionId,
1133
- reference: response.clientReference,
1134
- amount: Math.round(response.amount * 100),
1135
- // Convert back to pesewas
1136
- currency: response.currency,
1137
- paymentMethod: "mobile_money",
1138
- psp: "hubtel",
1139
- pspReference: response.transactionId,
1140
- status: "success"
1141
- };
1142
- onSuccess(result);
1143
- } else {
1144
- const error = {
1145
- code: "PAYMENT_FAILED",
1146
- message: response.message || "Payment failed",
1147
- recoverable: true
1148
- };
1149
- onError(error);
1150
- }
1151
- },
1152
- onCancel: () => {
1153
- onClose();
1154
- }
1155
- });
1156
- } catch (err) {
1157
- const error = {
1158
- code: "PSP_ERROR",
1159
- message: "Failed to initialize Hubtel",
1160
- recoverable: true,
1161
- originalError: err
1162
- };
1163
- onError(error);
1164
- }
1165
- }, [merchantAccount, amount, currency, reference, email, phone, description, onSuccess, onError, onClose]);
1166
- useEffect(() => {
1167
- if (autoStart && !initialized.current) {
1168
- initialized.current = true;
1169
- startPayment();
1170
- }
1171
- }, [autoStart, startPayment]);
1172
- return /* @__PURE__ */ jsx("div", { className: "reevit-psp-bridge reevit-psp-bridge--hubtel", children: /* @__PURE__ */ jsxs("div", { className: "reevit-psp-bridge__loading", children: [
1173
- /* @__PURE__ */ jsx("div", { className: "reevit-spinner" }),
1174
- /* @__PURE__ */ jsx("p", { children: "Connecting to Hubtel..." })
1175
- ] }) });
1176
- }
1177
- function loadFlutterwaveScript() {
1178
- return new Promise((resolve, reject) => {
1179
- if (window.FlutterwaveCheckout) {
1180
- resolve();
1181
- return;
892
+ }, [autoStart, startPayment]);
893
+ return /* @__PURE__ */ jsx("div", { className: "reevit-psp-bridge reevit-psp-bridge--hubtel", children: /* @__PURE__ */ jsxs("div", { className: "reevit-psp-bridge__loading", children: [
894
+ /* @__PURE__ */ jsx("div", { className: "reevit-spinner" }),
895
+ /* @__PURE__ */ jsx("p", { children: "Connecting to Hubtel..." })
896
+ ] }) });
897
+ }
898
+ function loadFlutterwaveScript() {
899
+ return new Promise((resolve, reject) => {
900
+ if (window.FlutterwaveCheckout) {
901
+ resolve();
902
+ return;
1182
903
  }
1183
904
  const script = document.createElement("script");
1184
905
  script.src = "https://checkout.flutterwave.com/v3.js";
@@ -1299,202 +1020,41 @@ function FlutterwaveBridge({
1299
1020
  /* @__PURE__ */ jsx("p", { children: "Connecting to Flutterwave..." })
1300
1021
  ] }) });
1301
1022
  }
1302
- var STRIPE_SCRIPT_URL = "https://js.stripe.com/v3/";
1303
- var stripeScriptPromise = null;
1304
- function loadStripeScript() {
1305
- if (stripeScriptPromise) return stripeScriptPromise;
1306
- if (document.getElementById("stripe-js-script")) {
1307
- stripeScriptPromise = Promise.resolve();
1308
- return stripeScriptPromise;
1023
+ var MONNIFY_SCRIPT_URL = "https://sdk.monnify.com/plugin/monnify.js";
1024
+ var monnifyScriptPromise = null;
1025
+ function loadMonnifyScript() {
1026
+ if (monnifyScriptPromise) return monnifyScriptPromise;
1027
+ if (document.getElementById("monnify-sdk-script")) {
1028
+ monnifyScriptPromise = Promise.resolve();
1029
+ return monnifyScriptPromise;
1309
1030
  }
1310
- stripeScriptPromise = new Promise((resolve, reject) => {
1031
+ monnifyScriptPromise = new Promise((resolve, reject) => {
1311
1032
  const script = document.createElement("script");
1312
- script.id = "stripe-js-script";
1313
- script.src = STRIPE_SCRIPT_URL;
1033
+ script.id = "monnify-sdk-script";
1034
+ script.src = MONNIFY_SCRIPT_URL;
1314
1035
  script.async = true;
1315
1036
  script.onload = () => resolve();
1316
- script.onerror = () => reject(new Error("Failed to load Stripe.js"));
1037
+ script.onerror = () => reject(new Error("Failed to load Monnify SDK"));
1317
1038
  document.head.appendChild(script);
1318
1039
  });
1319
- return stripeScriptPromise;
1040
+ return monnifyScriptPromise;
1320
1041
  }
1321
- function StripeBridge({
1322
- publishableKey,
1323
- clientSecret,
1042
+ function MonnifyBridge({
1043
+ apiKey,
1044
+ contractCode,
1324
1045
  amount,
1325
1046
  currency,
1326
- appearance,
1047
+ reference,
1048
+ customerName,
1049
+ customerEmail,
1050
+ customerPhone,
1051
+ paymentDescription,
1052
+ isTestMode = false,
1053
+ metadata,
1054
+ autoOpen = true,
1327
1055
  onSuccess,
1328
1056
  onError,
1329
- onReady,
1330
- onCancel
1331
- }) {
1332
- const [isLoading, setIsLoading] = useState(true);
1333
- const [isSubmitting, setIsSubmitting] = useState(false);
1334
- const [error, setError] = useState(null);
1335
- const stripeRef = useRef(null);
1336
- const elementsRef = useRef(null);
1337
- const paymentElementRef = useRef(null);
1338
- const containerRef = useRef(null);
1339
- useEffect(() => {
1340
- let mounted = true;
1341
- const initStripe = async () => {
1342
- try {
1343
- await loadStripeScript();
1344
- if (!mounted || !window.Stripe) {
1345
- throw new Error("Stripe not available");
1346
- }
1347
- stripeRef.current = window.Stripe(publishableKey);
1348
- elementsRef.current = stripeRef.current.elements({
1349
- clientSecret,
1350
- appearance: appearance || { theme: "stripe" }
1351
- });
1352
- paymentElementRef.current = elementsRef.current.create("payment");
1353
- if (containerRef.current) {
1354
- paymentElementRef.current.mount(containerRef.current);
1355
- }
1356
- paymentElementRef.current.on("ready", () => {
1357
- if (mounted) {
1358
- setIsLoading(false);
1359
- onReady?.();
1360
- }
1361
- });
1362
- paymentElementRef.current.on("change", (event) => {
1363
- if (event.error) {
1364
- setError(event.error.message);
1365
- } else {
1366
- setError(null);
1367
- }
1368
- });
1369
- } catch (err) {
1370
- if (mounted) {
1371
- const message = err instanceof Error ? err.message : "Failed to initialize Stripe";
1372
- setError(message);
1373
- setIsLoading(false);
1374
- onError({ code: "STRIPE_INIT_ERROR", message });
1375
- }
1376
- }
1377
- };
1378
- initStripe();
1379
- return () => {
1380
- mounted = false;
1381
- paymentElementRef.current?.destroy();
1382
- };
1383
- }, [publishableKey, clientSecret, appearance, onReady, onError]);
1384
- const handleSubmit = useCallback(async () => {
1385
- if (!stripeRef.current || !elementsRef.current) {
1386
- onError({ code: "NOT_INITIALIZED", message: "Stripe not initialized" });
1387
- return;
1388
- }
1389
- setIsSubmitting(true);
1390
- setError(null);
1391
- try {
1392
- const { error: submitError } = await elementsRef.current.submit();
1393
- if (submitError) {
1394
- setError(submitError.message);
1395
- onError({ code: submitError.code || "VALIDATION_ERROR", message: submitError.message });
1396
- setIsSubmitting(false);
1397
- return;
1398
- }
1399
- const { error: confirmError, paymentIntent } = await stripeRef.current.confirmPayment({
1400
- elements: elementsRef.current,
1401
- redirect: "if_required"
1402
- });
1403
- if (confirmError) {
1404
- setError(confirmError.message);
1405
- onError({ code: confirmError.code || "PAYMENT_ERROR", message: confirmError.message });
1406
- } else if (paymentIntent) {
1407
- onSuccess({
1408
- paymentIntentId: paymentIntent.id,
1409
- status: paymentIntent.status
1410
- });
1411
- }
1412
- } catch (err) {
1413
- const message = err instanceof Error ? err.message : "Payment failed";
1414
- setError(message);
1415
- onError({ code: "UNKNOWN_ERROR", message });
1416
- } finally {
1417
- setIsSubmitting(false);
1418
- }
1419
- }, [onSuccess, onError]);
1420
- return /* @__PURE__ */ jsxs("div", { className: "reevit-stripe-bridge", children: [
1421
- isLoading && /* @__PURE__ */ jsxs("div", { className: "reevit-stripe-loading", children: [
1422
- /* @__PURE__ */ jsx("div", { className: "reevit-spinner" }),
1423
- /* @__PURE__ */ jsx("p", { children: "Loading secure payment form..." })
1424
- ] }),
1425
- /* @__PURE__ */ jsx(
1426
- "div",
1427
- {
1428
- ref: containerRef,
1429
- className: "reevit-stripe-element",
1430
- style: { display: isLoading ? "none" : "block", minHeight: "200px" }
1431
- }
1432
- ),
1433
- error && /* @__PURE__ */ jsx("div", { className: "reevit-stripe-error", children: /* @__PURE__ */ jsx("p", { children: error }) }),
1434
- /* @__PURE__ */ jsxs("div", { className: "reevit-stripe-actions", children: [
1435
- /* @__PURE__ */ jsx(
1436
- "button",
1437
- {
1438
- type: "button",
1439
- className: "reevit-submit-btn",
1440
- onClick: handleSubmit,
1441
- disabled: isLoading || isSubmitting,
1442
- children: isSubmitting ? /* @__PURE__ */ jsx("span", { className: "reevit-spinner" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1443
- "Pay ",
1444
- currency,
1445
- " ",
1446
- (amount / 100).toFixed(2)
1447
- ] })
1448
- }
1449
- ),
1450
- onCancel && /* @__PURE__ */ jsx(
1451
- "button",
1452
- {
1453
- type: "button",
1454
- className: "reevit-cancel-btn",
1455
- onClick: onCancel,
1456
- disabled: isSubmitting,
1457
- children: "Cancel"
1458
- }
1459
- )
1460
- ] })
1461
- ] });
1462
- }
1463
- var MONNIFY_SCRIPT_URL = "https://sdk.monnify.com/plugin/monnify.js";
1464
- var monnifyScriptPromise = null;
1465
- function loadMonnifyScript() {
1466
- if (monnifyScriptPromise) return monnifyScriptPromise;
1467
- if (document.getElementById("monnify-sdk-script")) {
1468
- monnifyScriptPromise = Promise.resolve();
1469
- return monnifyScriptPromise;
1470
- }
1471
- monnifyScriptPromise = new Promise((resolve, reject) => {
1472
- const script = document.createElement("script");
1473
- script.id = "monnify-sdk-script";
1474
- script.src = MONNIFY_SCRIPT_URL;
1475
- script.async = true;
1476
- script.onload = () => resolve();
1477
- script.onerror = () => reject(new Error("Failed to load Monnify SDK"));
1478
- document.head.appendChild(script);
1479
- });
1480
- return monnifyScriptPromise;
1481
- }
1482
- function MonnifyBridge({
1483
- apiKey,
1484
- contractCode,
1485
- amount,
1486
- currency,
1487
- reference,
1488
- customerName,
1489
- customerEmail,
1490
- customerPhone,
1491
- paymentDescription,
1492
- isTestMode = false,
1493
- metadata,
1494
- autoOpen = true,
1495
- onSuccess,
1496
- onError,
1497
- onClose
1057
+ onClose
1498
1058
  }) {
1499
1059
  const [isLoading, setIsLoading] = useState(true);
1500
1060
  const [isReady, setIsReady] = useState(false);
@@ -1751,6 +1311,582 @@ function useMPesaStatusPolling(statusEndpoint, checkoutRequestId, options) {
1751
1311
  }, [checkoutRequestId, statusEndpoint, interval, maxAttempts, headers, onSuccess, onFailed, onTimeout]);
1752
1312
  return { startPolling };
1753
1313
  }
1314
+ var STRIPE_SCRIPT_URL = "https://js.stripe.com/v3/";
1315
+ var stripeScriptPromise = null;
1316
+ function loadStripeScript() {
1317
+ if (stripeScriptPromise) return stripeScriptPromise;
1318
+ if (document.getElementById("stripe-js-script")) {
1319
+ stripeScriptPromise = Promise.resolve();
1320
+ return stripeScriptPromise;
1321
+ }
1322
+ stripeScriptPromise = new Promise((resolve, reject) => {
1323
+ const script = document.createElement("script");
1324
+ script.id = "stripe-js-script";
1325
+ script.src = STRIPE_SCRIPT_URL;
1326
+ script.async = true;
1327
+ script.onload = () => resolve();
1328
+ script.onerror = () => reject(new Error("Failed to load Stripe.js"));
1329
+ document.head.appendChild(script);
1330
+ });
1331
+ return stripeScriptPromise;
1332
+ }
1333
+ function StripeBridge({
1334
+ publishableKey,
1335
+ clientSecret,
1336
+ amount,
1337
+ currency,
1338
+ appearance,
1339
+ onSuccess,
1340
+ onError,
1341
+ onReady,
1342
+ onCancel
1343
+ }) {
1344
+ const [isLoading, setIsLoading] = useState(true);
1345
+ const [isSubmitting, setIsSubmitting] = useState(false);
1346
+ const [error, setError] = useState(null);
1347
+ const stripeRef = useRef(null);
1348
+ const elementsRef = useRef(null);
1349
+ const paymentElementRef = useRef(null);
1350
+ const containerRef = useRef(null);
1351
+ useEffect(() => {
1352
+ let mounted = true;
1353
+ const initStripe = async () => {
1354
+ try {
1355
+ await loadStripeScript();
1356
+ if (!mounted || !window.Stripe) {
1357
+ throw new Error("Stripe not available");
1358
+ }
1359
+ stripeRef.current = window.Stripe(publishableKey);
1360
+ elementsRef.current = stripeRef.current.elements({
1361
+ clientSecret,
1362
+ appearance: appearance || { theme: "stripe" }
1363
+ });
1364
+ paymentElementRef.current = elementsRef.current.create("payment");
1365
+ if (containerRef.current) {
1366
+ paymentElementRef.current.mount(containerRef.current);
1367
+ }
1368
+ paymentElementRef.current.on("ready", () => {
1369
+ if (mounted) {
1370
+ setIsLoading(false);
1371
+ onReady?.();
1372
+ }
1373
+ });
1374
+ paymentElementRef.current.on("change", (event) => {
1375
+ if (event.error) {
1376
+ setError(event.error.message);
1377
+ } else {
1378
+ setError(null);
1379
+ }
1380
+ });
1381
+ } catch (err) {
1382
+ if (mounted) {
1383
+ const message = err instanceof Error ? err.message : "Failed to initialize Stripe";
1384
+ setError(message);
1385
+ setIsLoading(false);
1386
+ onError({ code: "STRIPE_INIT_ERROR", message });
1387
+ }
1388
+ }
1389
+ };
1390
+ initStripe();
1391
+ return () => {
1392
+ mounted = false;
1393
+ paymentElementRef.current?.destroy();
1394
+ };
1395
+ }, [publishableKey, clientSecret, appearance, onReady, onError]);
1396
+ const handleSubmit = useCallback(async () => {
1397
+ if (!stripeRef.current || !elementsRef.current) {
1398
+ onError({ code: "NOT_INITIALIZED", message: "Stripe not initialized" });
1399
+ return;
1400
+ }
1401
+ setIsSubmitting(true);
1402
+ setError(null);
1403
+ try {
1404
+ const { error: submitError } = await elementsRef.current.submit();
1405
+ if (submitError) {
1406
+ setError(submitError.message);
1407
+ onError({ code: submitError.code || "VALIDATION_ERROR", message: submitError.message });
1408
+ setIsSubmitting(false);
1409
+ return;
1410
+ }
1411
+ const { error: confirmError, paymentIntent } = await stripeRef.current.confirmPayment({
1412
+ elements: elementsRef.current,
1413
+ redirect: "if_required"
1414
+ });
1415
+ if (confirmError) {
1416
+ setError(confirmError.message);
1417
+ onError({ code: confirmError.code || "PAYMENT_ERROR", message: confirmError.message });
1418
+ } else if (paymentIntent) {
1419
+ onSuccess({
1420
+ paymentIntentId: paymentIntent.id,
1421
+ status: paymentIntent.status
1422
+ });
1423
+ }
1424
+ } catch (err) {
1425
+ const message = err instanceof Error ? err.message : "Payment failed";
1426
+ setError(message);
1427
+ onError({ code: "UNKNOWN_ERROR", message });
1428
+ } finally {
1429
+ setIsSubmitting(false);
1430
+ }
1431
+ }, [onSuccess, onError]);
1432
+ return /* @__PURE__ */ jsxs("div", { className: "reevit-stripe-bridge", children: [
1433
+ isLoading && /* @__PURE__ */ jsxs("div", { className: "reevit-stripe-loading", children: [
1434
+ /* @__PURE__ */ jsx("div", { className: "reevit-spinner" }),
1435
+ /* @__PURE__ */ jsx("p", { children: "Loading secure payment form..." })
1436
+ ] }),
1437
+ /* @__PURE__ */ jsx(
1438
+ "div",
1439
+ {
1440
+ ref: containerRef,
1441
+ className: "reevit-stripe-element",
1442
+ style: { display: isLoading ? "none" : "block", minHeight: "200px" }
1443
+ }
1444
+ ),
1445
+ error && /* @__PURE__ */ jsx("div", { className: "reevit-stripe-error", children: /* @__PURE__ */ jsx("p", { children: error }) }),
1446
+ /* @__PURE__ */ jsxs("div", { className: "reevit-stripe-actions", children: [
1447
+ /* @__PURE__ */ jsx(
1448
+ "button",
1449
+ {
1450
+ type: "button",
1451
+ className: "reevit-submit-btn",
1452
+ onClick: handleSubmit,
1453
+ disabled: isLoading || isSubmitting,
1454
+ children: isSubmitting ? /* @__PURE__ */ jsx("span", { className: "reevit-spinner" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1455
+ "Pay ",
1456
+ currency,
1457
+ " ",
1458
+ (amount / 100).toFixed(2)
1459
+ ] })
1460
+ }
1461
+ ),
1462
+ onCancel && /* @__PURE__ */ jsx(
1463
+ "button",
1464
+ {
1465
+ type: "button",
1466
+ className: "reevit-cancel-btn",
1467
+ onClick: onCancel,
1468
+ disabled: isSubmitting,
1469
+ children: "Cancel"
1470
+ }
1471
+ )
1472
+ ] })
1473
+ ] });
1474
+ }
1475
+ var ReevitContext = createContext(null);
1476
+ function useReevitContext() {
1477
+ const context = useContext(ReevitContext);
1478
+ if (!context) {
1479
+ throw new Error("useReevitContext must be used within ReevitCheckout");
1480
+ }
1481
+ return context;
1482
+ }
1483
+ function ReevitCheckout({
1484
+ // Config
1485
+ publicKey,
1486
+ amount,
1487
+ currency,
1488
+ email = "",
1489
+ phone = "",
1490
+ reference,
1491
+ metadata,
1492
+ paymentMethods = ["card", "mobile_money"],
1493
+ initialPaymentIntent,
1494
+ // Callbacks
1495
+ onSuccess,
1496
+ onError,
1497
+ onClose,
1498
+ onStateChange,
1499
+ // UI
1500
+ children,
1501
+ autoOpen = false,
1502
+ isOpen: controlledIsOpen,
1503
+ onOpenChange,
1504
+ theme,
1505
+ apiBaseUrl
1506
+ }) {
1507
+ const [internalIsOpen, setInternalIsOpen] = useState(autoOpen);
1508
+ const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
1509
+ const setIsOpen = useCallback(
1510
+ (value) => {
1511
+ if (onOpenChange) {
1512
+ onOpenChange(value);
1513
+ } else {
1514
+ setInternalIsOpen(value);
1515
+ }
1516
+ },
1517
+ [onOpenChange]
1518
+ );
1519
+ const [showPSPBridge, setShowPSPBridge] = useState(false);
1520
+ const [momoData, setMomoData] = useState(null);
1521
+ const {
1522
+ status,
1523
+ paymentIntent,
1524
+ selectedMethod,
1525
+ error,
1526
+ result,
1527
+ initialize,
1528
+ selectMethod,
1529
+ processPayment,
1530
+ reset,
1531
+ close: closeCheckout,
1532
+ isLoading,
1533
+ isComplete
1534
+ } = useReevit({
1535
+ config: {
1536
+ publicKey,
1537
+ amount,
1538
+ currency,
1539
+ email,
1540
+ phone,
1541
+ reference,
1542
+ metadata,
1543
+ paymentMethods,
1544
+ initialPaymentIntent
1545
+ },
1546
+ apiBaseUrl,
1547
+ onSuccess: (result2) => {
1548
+ onSuccess?.(result2);
1549
+ setTimeout(() => {
1550
+ setIsOpen(false);
1551
+ }, 2e3);
1552
+ },
1553
+ onError,
1554
+ onClose: () => {
1555
+ setIsOpen(false);
1556
+ onClose?.();
1557
+ },
1558
+ onStateChange
1559
+ });
1560
+ useEffect(() => {
1561
+ if (isOpen && status === "idle" && !initialPaymentIntent) {
1562
+ initialize();
1563
+ }
1564
+ }, [isOpen, status, initialize, initialPaymentIntent]);
1565
+ useEffect(() => {
1566
+ if (isOpen && selectedMethod && paymentIntent && !showPSPBridge) {
1567
+ if (selectedMethod === "card") {
1568
+ setShowPSPBridge(true);
1569
+ } else if (selectedMethod === "mobile_money" && (momoData?.phone || phone)) {
1570
+ setShowPSPBridge(true);
1571
+ }
1572
+ }
1573
+ }, [isOpen, selectedMethod, showPSPBridge, paymentIntent, momoData, phone]);
1574
+ const handleOpen = useCallback(() => {
1575
+ if (controlledIsOpen !== void 0) return;
1576
+ setIsOpen(true);
1577
+ setShowPSPBridge(false);
1578
+ setMomoData(null);
1579
+ }, [controlledIsOpen, setIsOpen]);
1580
+ const handleClose = useCallback(() => {
1581
+ closeCheckout();
1582
+ setIsOpen(false);
1583
+ setShowPSPBridge(false);
1584
+ setMomoData(null);
1585
+ }, [closeCheckout, setIsOpen]);
1586
+ const handleMethodSelect = useCallback(
1587
+ (method) => {
1588
+ selectMethod(method);
1589
+ },
1590
+ [selectMethod]
1591
+ );
1592
+ const handleContinue = useCallback(() => {
1593
+ if (!selectedMethod) return;
1594
+ if (selectedMethod === "card") {
1595
+ setShowPSPBridge(true);
1596
+ }
1597
+ }, [selectedMethod]);
1598
+ const handleMomoSubmit = useCallback(
1599
+ (data) => {
1600
+ setMomoData(data);
1601
+ setShowPSPBridge(true);
1602
+ },
1603
+ []
1604
+ );
1605
+ const handlePSPSuccess = useCallback(
1606
+ (pspResult) => {
1607
+ processPayment({ ...pspResult, momoData });
1608
+ },
1609
+ [processPayment, momoData]
1610
+ );
1611
+ const handlePSPError = useCallback(
1612
+ (error2) => {
1613
+ setShowPSPBridge(false);
1614
+ onError?.(error2);
1615
+ },
1616
+ [onError]
1617
+ );
1618
+ const handlePSPClose = useCallback(() => {
1619
+ setShowPSPBridge(false);
1620
+ }, []);
1621
+ const handleBack = useCallback(() => {
1622
+ reset();
1623
+ setMomoData(null);
1624
+ setShowPSPBridge(false);
1625
+ }, [reset]);
1626
+ const themeStyles = theme ? createThemeVariables(theme) : {};
1627
+ const isControlled = controlledIsOpen !== void 0;
1628
+ const trigger = children ? /* @__PURE__ */ jsx("span", { onClick: isControlled ? void 0 : handleOpen, role: isControlled ? void 0 : "button", tabIndex: isControlled ? void 0 : 0, children }) : !isControlled ? /* @__PURE__ */ jsxs("button", { className: "reevit-trigger-btn", onClick: handleOpen, children: [
1629
+ "Pay ",
1630
+ formatAmount(amount, currency)
1631
+ ] }) : null;
1632
+ const renderContent = () => {
1633
+ if (status === "loading" || status === "processing") {
1634
+ return /* @__PURE__ */ jsxs("div", { className: "reevit-loading", children: [
1635
+ /* @__PURE__ */ jsx("div", { className: "reevit-spinner" }),
1636
+ /* @__PURE__ */ jsx("p", { children: status === "loading" ? "Preparing checkout..." : "Processing payment..." })
1637
+ ] });
1638
+ }
1639
+ if (status === "success" && result) {
1640
+ return /* @__PURE__ */ jsxs("div", { className: "reevit-success", children: [
1641
+ /* @__PURE__ */ jsx("div", { className: "reevit-success__icon", children: "\u2713" }),
1642
+ /* @__PURE__ */ jsx("h3", { children: "Payment Successful" }),
1643
+ /* @__PURE__ */ jsxs("p", { children: [
1644
+ "Reference: ",
1645
+ result.reference
1646
+ ] })
1647
+ ] });
1648
+ }
1649
+ if (status === "failed" && error && !error.recoverable) {
1650
+ return /* @__PURE__ */ jsxs("div", { className: "reevit-error", children: [
1651
+ /* @__PURE__ */ jsx("div", { className: "reevit-error__icon", children: "\u2715" }),
1652
+ /* @__PURE__ */ jsx("h3", { children: "Payment Failed" }),
1653
+ /* @__PURE__ */ jsx("p", { children: error.message }),
1654
+ /* @__PURE__ */ jsx("button", { className: "reevit-btn reevit-btn--primary", onClick: handleBack, children: "Try Again" })
1655
+ ] });
1656
+ }
1657
+ if (showPSPBridge) {
1658
+ const pspKey = paymentIntent?.pspPublicKey || publicKey;
1659
+ const psp = paymentIntent?.recommendedPsp || "paystack";
1660
+ const bridgeMetadata = {
1661
+ ...metadata,
1662
+ // Override with correct payment intent ID for webhook routing
1663
+ // This ensures webhook includes the correct ID to find the payment
1664
+ payment_id: paymentIntent?.id,
1665
+ connection_id: paymentIntent?.connectionId ?? metadata?.connection_id,
1666
+ customer_phone: momoData?.phone || phone
1667
+ };
1668
+ switch (psp) {
1669
+ case "paystack":
1670
+ return /* @__PURE__ */ jsx(
1671
+ PaystackBridge,
1672
+ {
1673
+ publicKey: pspKey,
1674
+ email,
1675
+ phone: momoData?.phone || phone,
1676
+ amount: paymentIntent?.amount ?? amount,
1677
+ currency: paymentIntent?.currency ?? currency,
1678
+ reference,
1679
+ accessCode: paymentIntent?.clientSecret,
1680
+ metadata: bridgeMetadata,
1681
+ channels: selectedMethod === "mobile_money" ? ["mobile_money"] : ["card"],
1682
+ onSuccess: handlePSPSuccess,
1683
+ onError: handlePSPError,
1684
+ onClose: handlePSPClose
1685
+ }
1686
+ );
1687
+ case "hubtel":
1688
+ return /* @__PURE__ */ jsx(
1689
+ HubtelBridge,
1690
+ {
1691
+ merchantAccount: pspKey,
1692
+ amount: paymentIntent?.amount ?? amount,
1693
+ currency: paymentIntent?.currency ?? currency,
1694
+ reference: paymentIntent?.reference || reference,
1695
+ email,
1696
+ phone: momoData?.phone || phone,
1697
+ description: `Payment ${paymentIntent?.reference || reference || ""}`,
1698
+ onSuccess: handlePSPSuccess,
1699
+ onError: (err) => handlePSPError(err),
1700
+ onClose: handlePSPClose
1701
+ }
1702
+ );
1703
+ case "flutterwave":
1704
+ return /* @__PURE__ */ jsx(
1705
+ FlutterwaveBridge,
1706
+ {
1707
+ publicKey: pspKey,
1708
+ amount: paymentIntent?.amount ?? amount,
1709
+ currency: paymentIntent?.currency ?? currency,
1710
+ reference: paymentIntent?.reference || reference,
1711
+ email,
1712
+ phone: momoData?.phone || phone,
1713
+ metadata: bridgeMetadata,
1714
+ onSuccess: handlePSPSuccess,
1715
+ onError: (err) => handlePSPError(err),
1716
+ onClose: handlePSPClose
1717
+ }
1718
+ );
1719
+ case "monnify":
1720
+ return /* @__PURE__ */ jsx(
1721
+ MonnifyBridge,
1722
+ {
1723
+ apiKey: pspKey,
1724
+ contractCode: metadata?.contract_code || pspKey,
1725
+ amount: paymentIntent?.amount ?? amount,
1726
+ currency: paymentIntent?.currency ?? currency,
1727
+ reference: paymentIntent?.reference || reference || `monnify_${Date.now()}`,
1728
+ customerName: metadata?.customer_name || email,
1729
+ customerEmail: email,
1730
+ customerPhone: momoData?.phone || phone,
1731
+ metadata: bridgeMetadata,
1732
+ onSuccess: (result2) => handlePSPSuccess({
1733
+ paymentId: result2.transactionReference,
1734
+ reference: result2.paymentReference,
1735
+ amount: result2.amount,
1736
+ currency: paymentIntent?.currency ?? currency,
1737
+ paymentMethod: selectedMethod || "card",
1738
+ psp: "monnify",
1739
+ pspReference: result2.transactionReference,
1740
+ status: "success"
1741
+ }),
1742
+ onError: (err) => handlePSPError({
1743
+ code: err.code,
1744
+ message: err.message,
1745
+ recoverable: true
1746
+ }),
1747
+ onClose: handlePSPClose
1748
+ }
1749
+ );
1750
+ case "mpesa":
1751
+ return /* @__PURE__ */ jsx(
1752
+ MPesaBridge,
1753
+ {
1754
+ apiEndpoint: `${apiBaseUrl || "https://api.reevit.io"}/v1/payments/${paymentIntent?.id}/mpesa`,
1755
+ phoneNumber: momoData?.phone || phone || "",
1756
+ amount: paymentIntent?.amount ?? amount,
1757
+ currency: paymentIntent?.currency ?? currency,
1758
+ reference: paymentIntent?.reference || reference || `mpesa_${Date.now()}`,
1759
+ description: `Payment ${paymentIntent?.reference || reference || ""}`,
1760
+ headers: { "x-reevit-public-key": publicKey },
1761
+ onSuccess: (result2) => handlePSPSuccess({
1762
+ paymentId: result2.transactionId,
1763
+ reference: result2.reference,
1764
+ amount: paymentIntent?.amount ?? amount,
1765
+ currency: paymentIntent?.currency ?? currency,
1766
+ paymentMethod: "mobile_money",
1767
+ psp: "mpesa",
1768
+ pspReference: result2.transactionId,
1769
+ status: "success"
1770
+ }),
1771
+ onError: (err) => handlePSPError({
1772
+ code: err.code,
1773
+ message: err.message,
1774
+ recoverable: true
1775
+ })
1776
+ }
1777
+ );
1778
+ case "stripe":
1779
+ return /* @__PURE__ */ jsx(
1780
+ StripeBridge,
1781
+ {
1782
+ publishableKey: pspKey,
1783
+ clientSecret: paymentIntent?.clientSecret || "",
1784
+ amount: paymentIntent?.amount ?? amount,
1785
+ currency: paymentIntent?.currency ?? currency,
1786
+ onSuccess: (result2) => handlePSPSuccess({
1787
+ paymentId: result2.paymentIntentId,
1788
+ reference: paymentIntent?.reference || reference || result2.paymentIntentId,
1789
+ amount: paymentIntent?.amount ?? amount,
1790
+ currency: paymentIntent?.currency ?? currency,
1791
+ paymentMethod: selectedMethod || "card",
1792
+ psp: "stripe",
1793
+ pspReference: result2.paymentIntentId,
1794
+ status: result2.status === "succeeded" ? "success" : "pending"
1795
+ }),
1796
+ onError: (err) => handlePSPError({
1797
+ code: err.code,
1798
+ message: err.message,
1799
+ recoverable: true
1800
+ }),
1801
+ onCancel: handlePSPClose
1802
+ }
1803
+ );
1804
+ default:
1805
+ return /* @__PURE__ */ jsxs("div", { className: "reevit-error", children: [
1806
+ /* @__PURE__ */ jsx("div", { className: "reevit-error__icon", children: "\u26A0\uFE0F" }),
1807
+ /* @__PURE__ */ jsx("h3", { children: "Payment Provider Not Supported" }),
1808
+ /* @__PURE__ */ jsxs("p", { children: [
1809
+ "The selected payment provider (",
1810
+ psp,
1811
+ ") is not currently supported in this checkout."
1812
+ ] }),
1813
+ /* @__PURE__ */ jsx("button", { className: "reevit-btn reevit-btn--primary", onClick: handleBack, children: "Go Back" })
1814
+ ] });
1815
+ }
1816
+ }
1817
+ if (selectedMethod === "mobile_money" && !showPSPBridge) {
1818
+ return /* @__PURE__ */ jsx(
1819
+ MobileMoneyForm,
1820
+ {
1821
+ onSubmit: handleMomoSubmit,
1822
+ onCancel: handleBack,
1823
+ isLoading,
1824
+ initialPhone: phone
1825
+ }
1826
+ );
1827
+ }
1828
+ return /* @__PURE__ */ jsxs("div", { className: "reevit-method-step", children: [
1829
+ /* @__PURE__ */ jsx(
1830
+ PaymentMethodSelector,
1831
+ {
1832
+ methods: paymentMethods,
1833
+ selectedMethod,
1834
+ onSelect: handleMethodSelect,
1835
+ disabled: isLoading
1836
+ }
1837
+ ),
1838
+ selectedMethod && selectedMethod !== "mobile_money" && /* @__PURE__ */ jsx("div", { className: "reevit-method-step__actions", children: /* @__PURE__ */ jsx(
1839
+ "button",
1840
+ {
1841
+ className: "reevit-btn reevit-btn--primary",
1842
+ onClick: handleContinue,
1843
+ disabled: isLoading,
1844
+ children: "Continue"
1845
+ }
1846
+ ) })
1847
+ ] });
1848
+ };
1849
+ return /* @__PURE__ */ jsxs(ReevitContext.Provider, { value: { publicKey, amount, currency }, children: [
1850
+ trigger,
1851
+ isOpen && /* @__PURE__ */ jsx("div", { className: "reevit-overlay", onClick: handleClose, children: /* @__PURE__ */ jsxs(
1852
+ "div",
1853
+ {
1854
+ className: cn("reevit-modal", isComplete && "reevit-modal--success"),
1855
+ style: themeStyles,
1856
+ onClick: (e) => e.stopPropagation(),
1857
+ role: "dialog",
1858
+ "aria-modal": "true",
1859
+ children: [
1860
+ /* @__PURE__ */ jsxs("div", { className: "reevit-modal__header", children: [
1861
+ /* @__PURE__ */ jsx("div", { className: "reevit-modal__branding", children: /* @__PURE__ */ jsx(
1862
+ "img",
1863
+ {
1864
+ src: "https://i.imgur.com/bzUR5Lm.png",
1865
+ alt: "Reevit",
1866
+ className: "reevit-modal__logo"
1867
+ }
1868
+ ) }),
1869
+ /* @__PURE__ */ jsx(
1870
+ "button",
1871
+ {
1872
+ className: "reevit-modal__close",
1873
+ onClick: handleClose,
1874
+ "aria-label": "Close",
1875
+ children: "\u2715"
1876
+ }
1877
+ )
1878
+ ] }),
1879
+ /* @__PURE__ */ jsxs("div", { className: "reevit-modal__amount", children: [
1880
+ /* @__PURE__ */ jsx("span", { className: "reevit-modal__amount-label", children: "Amount" }),
1881
+ /* @__PURE__ */ jsx("span", { className: "reevit-modal__amount-value", children: formatAmount(amount, currency) })
1882
+ ] }),
1883
+ /* @__PURE__ */ jsx("div", { className: "reevit-modal__content", children: renderContent() }),
1884
+ /* @__PURE__ */ jsx("div", { className: "reevit-modal__footer", children: /* @__PURE__ */ jsx("span", { className: "reevit-modal__secured", children: "\u{1F512} Secured by Reevit" }) })
1885
+ ]
1886
+ }
1887
+ ) })
1888
+ ] });
1889
+ }
1754
1890
 
1755
1891
  export { FlutterwaveBridge, HubtelBridge, MPesaBridge, MobileMoneyForm, MonnifyBridge, PaymentMethodSelector, PaystackBridge, ReevitAPIClient, ReevitCheckout, StripeBridge, createReevitClient, detectNetwork, formatAmount, formatPhone, loadFlutterwaveScript, loadHubtelScript, loadMonnifyScript, loadPaystackScript, loadStripeScript, useMPesaStatusPolling, useReevit, useReevitContext, validatePhone };
1756
1892
  //# sourceMappingURL=index.mjs.map