@flopay/react 0.1.0 → 0.1.2

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.cjs CHANGED
@@ -1029,6 +1029,13 @@ function FloPayCheckout({
1029
1029
  paymentMethodId: json.paymentMethodId
1030
1030
  };
1031
1031
  }
1032
+ if (json?.gatewayErrorCode === "authentication_required") {
1033
+ return {
1034
+ type: "3ds_required",
1035
+ threeDSecureToken: ""
1036
+ // No client secret available
1037
+ };
1038
+ }
1032
1039
  throw new import_shared4.FloPayError(
1033
1040
  json?.message ?? "Payment failed. Please try again.",
1034
1041
  "api_error"
@@ -1036,6 +1043,51 @@ function FloPayCheckout({
1036
1043
  },
1037
1044
  [resolvedBillingUrl, sessionId, onComplete]
1038
1045
  );
1046
+ const handleRedirectResult = (0, import_react6.useCallback)(
1047
+ async (redirectResult, sess, options) => {
1048
+ const stripe = flopayRef.current?.getRawProvider();
1049
+ if (!stripe) return false;
1050
+ if (redirectResult.type === "3ds_required") {
1051
+ if (!options?.attempt3DS || !redirectResult.threeDSecureToken) {
1052
+ setModeError("Your card requires authentication. Please enter your payment details below.");
1053
+ return false;
1054
+ }
1055
+ const { error: nextActionError, paymentIntent } = await stripe.handleNextAction({
1056
+ clientSecret: redirectResult.threeDSecureToken
1057
+ });
1058
+ if (nextActionError) {
1059
+ setModeError(nextActionError.message ?? "3DS authentication failed.");
1060
+ return false;
1061
+ }
1062
+ if (paymentIntent && (paymentIntent.status === "requires_capture" || paymentIntent.status === "succeeded")) {
1063
+ onComplete?.({ status: "succeeded", paymentIntentId: paymentIntent.id });
1064
+ return true;
1065
+ }
1066
+ return false;
1067
+ }
1068
+ if (redirectResult.type === "paypal_redirect_required") {
1069
+ const confirmParams = {
1070
+ return_url: window.location.href
1071
+ };
1072
+ if (redirectResult.paymentMethodId) {
1073
+ confirmParams["payment_method"] = redirectResult.paymentMethodId;
1074
+ }
1075
+ const { error } = await stripe.confirmPayment({
1076
+ clientSecret: redirectResult.threeDSecureToken,
1077
+ confirmParams,
1078
+ redirect: "if_required"
1079
+ });
1080
+ if (error) {
1081
+ setModeError(error.message ?? "PayPal authorization failed.");
1082
+ return false;
1083
+ }
1084
+ onComplete?.({ status: "succeeded" });
1085
+ return true;
1086
+ }
1087
+ return false;
1088
+ },
1089
+ [resolvedBillingUrl, sessionId, onComplete]
1090
+ );
1039
1091
  (0, import_react6.useEffect)(() => {
1040
1092
  let cancelled = false;
1041
1093
  setIsLoading(true);
@@ -1070,29 +1122,11 @@ function FloPayCheckout({
1070
1122
  }
1071
1123
  if (cancelled) return;
1072
1124
  await stripeInitPromise;
1073
- if (redirectResult.type === "paypal_redirect_required") {
1074
- const stripeRef = flopayRef.current;
1075
- if (stripeRef) {
1076
- const rawStripe = stripeRef.getRawProvider();
1077
- if (rawStripe) {
1078
- const confirmParams = {
1079
- return_url: window.location.href
1080
- };
1081
- if (redirectResult.paymentMethodId) {
1082
- confirmParams["payment_method"] = redirectResult.paymentMethodId;
1083
- }
1084
- await rawStripe.confirmPayment({
1085
- clientSecret: redirectResult.threeDSecureToken,
1086
- confirmParams,
1087
- redirect: "if_required"
1088
- });
1089
- if (!cancelled) setIsLoading(false);
1090
- return;
1091
- }
1092
- }
1093
- }
1125
+ const handled = await handleRedirectResult(redirectResult, sess, { attempt3DS: true });
1094
1126
  if (!cancelled) {
1095
- setCurrentMode("full");
1127
+ if (!handled) {
1128
+ setCurrentMode("full");
1129
+ }
1096
1130
  setIsLoading(false);
1097
1131
  }
1098
1132
  return;
@@ -1146,14 +1180,22 @@ function FloPayCheckout({
1146
1180
  locale,
1147
1181
  checkoutModeProp,
1148
1182
  onSessionCompleted,
1149
- processPaymentForMode
1183
+ processPaymentForMode,
1184
+ handleRedirectResult
1150
1185
  ]);
1151
1186
  const handleConfirmCheckout = (0, import_react6.useCallback)(async () => {
1152
1187
  if (confirmProcessing || !session) return;
1153
1188
  setConfirmProcessing(true);
1154
1189
  setModeError(null);
1155
1190
  try {
1156
- await processPaymentForMode(session);
1191
+ const redirectResult = await processPaymentForMode(session);
1192
+ if (!redirectResult) {
1193
+ return;
1194
+ }
1195
+ const handled = await handleRedirectResult(redirectResult, session);
1196
+ if (!handled) {
1197
+ setCurrentMode("full");
1198
+ }
1157
1199
  } catch (err) {
1158
1200
  const floPayErr = err instanceof import_shared4.FloPayError ? err : new import_shared4.FloPayError(
1159
1201
  err instanceof Error ? err.message : "Payment failed",
@@ -1165,7 +1207,7 @@ function FloPayCheckout({
1165
1207
  } finally {
1166
1208
  setConfirmProcessing(false);
1167
1209
  }
1168
- }, [confirmProcessing, session, processPaymentForMode, onError]);
1210
+ }, [confirmProcessing, session, processPaymentForMode, handleRedirectResult, onError]);
1169
1211
  const providerOptions = (0, import_react6.useMemo)(() => {
1170
1212
  if (!unified || !session) return void 0;
1171
1213
  const opts = {
@@ -1275,33 +1317,50 @@ function FloPayCheckout({
1275
1317
  )
1276
1318
  ] }) }) });
1277
1319
  }
1278
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FloPayProvider, { flopay, options: providerOptions, children: children ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1279
- SessionInjector,
1280
- {
1281
- sessionId,
1282
- billingApiUrl: resolvedBillingUrl,
1283
- session,
1284
- children
1285
- }
1286
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1287
- SplitCardForm,
1288
- {
1289
- sessionId,
1290
- email: session?.customer?.email,
1291
- userId: session?.customer?.id,
1292
- firstName: session?.customer?.firstName,
1293
- lastName: session?.customer?.lastName,
1294
- totalAmount: session ? Math.round((0, import_shared4.buildCheckoutDisplayData)(session).total * 100) : 0,
1295
- currency: session?.currency?.toLowerCase() ?? "usd",
1296
- onComplete,
1297
- onError,
1298
- showPayPal,
1299
- showApplePay,
1300
- showGooglePay,
1301
- submitLabel,
1302
- className
1303
- }
1304
- ) }) });
1320
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(FloPayProvider, { flopay, options: providerOptions, children: [
1321
+ modeError && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1322
+ "div",
1323
+ {
1324
+ style: {
1325
+ padding: "0.75rem 1rem",
1326
+ marginBottom: "0.75rem",
1327
+ backgroundColor: "#FEF3C7",
1328
+ border: "1px solid #F59E0B",
1329
+ borderRadius: "8px",
1330
+ color: "#92400E",
1331
+ fontSize: "0.875rem"
1332
+ },
1333
+ children: modeError
1334
+ }
1335
+ ),
1336
+ children ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1337
+ SessionInjector,
1338
+ {
1339
+ sessionId,
1340
+ billingApiUrl: resolvedBillingUrl,
1341
+ session,
1342
+ children
1343
+ }
1344
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1345
+ SplitCardForm,
1346
+ {
1347
+ sessionId,
1348
+ email: session?.customer?.email,
1349
+ userId: session?.customer?.id,
1350
+ firstName: session?.customer?.firstName,
1351
+ lastName: session?.customer?.lastName,
1352
+ totalAmount: session ? Math.round((0, import_shared4.buildCheckoutDisplayData)(session).total * 100) : 0,
1353
+ currency: session?.currency?.toLowerCase() ?? "usd",
1354
+ onComplete,
1355
+ onError,
1356
+ showPayPal,
1357
+ showApplePay,
1358
+ showGooglePay,
1359
+ submitLabel,
1360
+ className
1361
+ }
1362
+ )
1363
+ ] }) });
1305
1364
  }
1306
1365
  function SessionInjector({
1307
1366
  sessionId,