@flopay/react 0.4.5 → 0.4.8

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
@@ -1200,9 +1200,22 @@ function SplitCardFormInner({
1200
1200
  }
1201
1201
  setIs3DSActive(true);
1202
1202
  try {
1203
+ const retryBillingAddress = {
1204
+ ...(enableAVS ? selectedCountryRef.current : effectiveAccount.country) ? {
1205
+ country: enableAVS ? selectedCountryRef.current : effectiveAccount.country
1206
+ } : {},
1207
+ ...(enableAVS ? zipCodeRef.current.trim() : effectiveAccount.zip) || "" ? {
1208
+ postal_code: enableAVS ? zipCodeRef.current.trim() : effectiveAccount.zip
1209
+ } : {}
1210
+ };
1203
1211
  const result = await flopay.confirmPayment({
1204
1212
  clientSecret: secret,
1205
- returnUrl: window.location.href
1213
+ returnUrl: window.location.href,
1214
+ billingDetails: {
1215
+ ...effectiveAccount.email ? { email: effectiveAccount.email } : {},
1216
+ ...fullName.trim() ? { name: fullName.trim() } : {},
1217
+ ...Object.keys(retryBillingAddress).length > 0 ? { address: retryBillingAddress } : {}
1218
+ }
1206
1219
  });
1207
1220
  if (result.error) {
1208
1221
  setOverlayStatus("error");
@@ -1361,13 +1374,19 @@ function SplitCardFormInner({
1361
1374
  onError?.(submitResult.error);
1362
1375
  return;
1363
1376
  }
1364
- const billingDetails = enableAVS ? {
1365
- name: fullName,
1366
- address: {
1367
- country: selectedCountryRef.current,
1368
- postal_code: zipCodeRef.current
1369
- }
1370
- } : void 0;
1377
+ const billingAddress = {
1378
+ ...(enableAVS ? selectedCountryRef.current : resolvedAccount.country) ? {
1379
+ country: enableAVS ? selectedCountryRef.current : resolvedAccount.country
1380
+ } : {},
1381
+ ...(enableAVS ? zipCodeRef.current.trim() : resolvedAccount.zip) || "" ? {
1382
+ postal_code: enableAVS ? zipCodeRef.current.trim() : resolvedAccount.zip
1383
+ } : {}
1384
+ };
1385
+ const billingDetails = {
1386
+ ...resolvedAccount.email ? { email: resolvedAccount.email } : {},
1387
+ ...fullName.trim() ? { name: fullName.trim() } : {},
1388
+ ...Object.keys(billingAddress).length > 0 ? { address: billingAddress } : {}
1389
+ };
1371
1390
  const pmResult = await flopay.createPaymentMethod(billingDetails);
1372
1391
  if (pmResult.error || !pmResult.paymentMethodId) {
1373
1392
  updateError(pmResult.error?.message ?? "Failed to create payment method.");
@@ -1877,6 +1896,32 @@ function SplitCardFormInner({
1877
1896
  import { loadFloPay, PaymentAPI } from "@flopay/js";
1878
1897
  import { FloPayError as FloPayError3 } from "@flopay/shared";
1879
1898
  var DEFAULT_SAVED_PAYMENT_DECLINE_METHOD = "card";
1899
+ function getRedirectResultFromCheckoutProcessError(error) {
1900
+ if (!error?.type || !error.threeDSecureToken) {
1901
+ return null;
1902
+ }
1903
+ if (error.type !== "3ds_required" && error.type !== "paypal_redirect_required") {
1904
+ return null;
1905
+ }
1906
+ return {
1907
+ type: error.type,
1908
+ threeDSecureToken: error.threeDSecureToken,
1909
+ paymentMethodId: error.paymentMethodId
1910
+ };
1911
+ }
1912
+ function checkoutProcessErrorToFloPayError(error, fallbackMessage = "Payment failed. Please try again.", options) {
1913
+ const checkoutMethod = options?.checkoutMethod ?? error?.checkoutMethod ?? (error?.type === "paypal_redirect_required" ? "paypal" : "card");
1914
+ return Object.assign(
1915
+ new FloPayError3(
1916
+ error?.message ?? fallbackMessage,
1917
+ "api_error",
1918
+ {
1919
+ code: error?.gatewayErrorCode
1920
+ }
1921
+ ),
1922
+ { checkoutMethod }
1923
+ );
1924
+ }
1880
1925
  function resolveSavedPaymentReturnUrl(session) {
1881
1926
  if (typeof window !== "undefined" && window.location.href) {
1882
1927
  return window.location.href;
@@ -2485,19 +2530,45 @@ function FloPayCheckout({
2485
2530
  setModeOverlayStatus("processing");
2486
2531
  const activeSessionId2 = options?.sessionId ?? sess.id;
2487
2532
  try {
2488
- const result = await processSavedPaymentForMode({
2489
- billingApiUrl: resolvedBillingUrl,
2490
- sessionId: activeSessionId2,
2491
- session: sess
2492
- });
2493
- const paymentResult = result.type === "success" ? result.result : await handleSavedPaymentRedirectResult(result, {
2494
- flopay: flopayRef.current,
2495
- paypalFlopay: paypalFlopayRef.current,
2496
- attempt3DS: options?.attempt3DS,
2497
- billingApiUrl: resolvedBillingUrl,
2498
- sessionId: activeSessionId2,
2499
- session: sess
2500
- });
2533
+ const redirectResult = getRedirectResultFromCheckoutProcessError(options?.initialAutoProcessingError);
2534
+ let paymentResult;
2535
+ if (redirectResult) {
2536
+ paymentResult = await handleSavedPaymentRedirectResult(redirectResult, {
2537
+ flopay: flopayRef.current,
2538
+ paypalFlopay: paypalFlopayRef.current,
2539
+ attempt3DS: options?.attempt3DS,
2540
+ billingApiUrl: resolvedBillingUrl,
2541
+ sessionId: activeSessionId2,
2542
+ session: sess
2543
+ });
2544
+ } else if (options?.initialAutoProcessingError) {
2545
+ throw checkoutProcessErrorToFloPayError(
2546
+ options.initialAutoProcessingError,
2547
+ "Automatic payment failed. Please try again.",
2548
+ {
2549
+ checkoutMethod: options.initialAutoProcessingError.checkoutMethod
2550
+ }
2551
+ );
2552
+ } else if (options?.fromCreateSession) {
2553
+ if (options?.fallbackToFull) {
2554
+ setCurrentMode("full");
2555
+ }
2556
+ return false;
2557
+ } else {
2558
+ const result = await processSavedPaymentForMode({
2559
+ billingApiUrl: resolvedBillingUrl,
2560
+ sessionId: activeSessionId2,
2561
+ session: sess
2562
+ });
2563
+ paymentResult = result.type === "success" ? result.result : await handleSavedPaymentRedirectResult(result, {
2564
+ flopay: flopayRef.current,
2565
+ paypalFlopay: paypalFlopayRef.current,
2566
+ attempt3DS: options?.attempt3DS,
2567
+ billingApiUrl: resolvedBillingUrl,
2568
+ sessionId: activeSessionId2,
2569
+ session: sess
2570
+ });
2571
+ }
2501
2572
  setModeOverlayStatus("success");
2502
2573
  await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
2503
2574
  onCompleteRef.current?.(paymentResult);
@@ -2706,6 +2777,9 @@ function FloPayCheckout({
2706
2777
  await runSavedPaymentFlow(resolvedSession, {
2707
2778
  attempt3DS: true,
2708
2779
  fallbackToFull: true,
2780
+ fromCreateSession: true,
2781
+ initialAutoProcessingError: resolved.result.autoProcessingError,
2782
+ autoProcessingAttempted: resolved.result.autoProcessingAttempted,
2709
2783
  sessionId: resolved.sid || resolvedSession.id
2710
2784
  });
2711
2785
  return;
@@ -3388,9 +3462,14 @@ function CheckoutFormInner({
3388
3462
  }
3389
3463
  setIs3DSActive(true);
3390
3464
  try {
3465
+ const retryFullName = `${firstName ?? ""} ${lastName ?? ""}`.trim();
3391
3466
  const result = await flopay.confirmPayment({
3392
3467
  clientSecret: secret,
3393
- returnUrl: window.location.href
3468
+ returnUrl: window.location.href,
3469
+ billingDetails: {
3470
+ ...email ? { email } : {},
3471
+ ...retryFullName ? { name: retryFullName } : {}
3472
+ }
3394
3473
  });
3395
3474
  if (result.error) {
3396
3475
  updateError(result.error.message);
@@ -3526,7 +3605,11 @@ function CheckoutFormInner({
3526
3605
  onError?.(submitResult.error);
3527
3606
  return;
3528
3607
  }
3529
- const pmResult = await flopay.createPaymentMethod();
3608
+ const fullName = `${firstName ?? ""} ${lastName ?? ""}`.trim();
3609
+ const pmResult = await flopay.createPaymentMethod({
3610
+ ...email ? { email } : {},
3611
+ ...fullName ? { name: fullName } : {}
3612
+ });
3530
3613
  if (pmResult.error || !pmResult.paymentMethodId) {
3531
3614
  updateError(pmResult.error?.message ?? "Failed to create payment method.");
3532
3615
  return;
@@ -4029,7 +4112,7 @@ function FloPayAutomaticPaymentButton({
4029
4112
  setOverlayStatus("error");
4030
4113
  await sleep2(PROCESSING_OVERLAY_ERROR_DELAY_MS);
4031
4114
  }, [emitDecline]);
4032
- const processResolvedSession = useCallback5(async (apiResult, resolvedSessionId) => {
4115
+ const processResolvedSession = useCallback5(async (apiResult, resolvedSessionId, options) => {
4033
4116
  const session = apiResult.data.session ?? null;
4034
4117
  if (!session) {
4035
4118
  throw new FloPayError7("No session data returned", "api_error");
@@ -4044,19 +4127,15 @@ function FloPayAutomaticPaymentButton({
4044
4127
  return;
4045
4128
  }
4046
4129
  try {
4047
- const result = await processSavedPaymentForMode({
4048
- billingApiUrl: resolvedBillingUrl,
4049
- sessionId: resolvedSessionId ?? session.id,
4050
- session,
4051
- tokenizedData: automaticPaymentToken
4052
- });
4053
- let paymentResult = result.type === "success" ? result.result : null;
4054
- if (result.type !== "success") {
4130
+ let paymentResult = null;
4131
+ const redirectResult = getRedirectResultFromCheckoutProcessError(apiResult.autoProcessingError);
4132
+ const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && (apiResult.autoProcessingAttempted === true || !!apiResult.autoProcessingError || !!redirectResult);
4133
+ if (redirectResult) {
4055
4134
  const {
4056
4135
  publishableKey,
4057
4136
  paypalPublishableKey
4058
4137
  } = resolveSavedPaymentPublishableKeys(apiResult, fallbackPublishableKey);
4059
- if (result.type === "paypal_redirect_required") {
4138
+ if (redirectResult.type === "paypal_redirect_required") {
4060
4139
  persistPayPalResumeState({
4061
4140
  sessionId: session.id || resolvedSessionId,
4062
4141
  publishableKey,
@@ -4072,7 +4151,7 @@ function FloPayAutomaticPaymentButton({
4072
4151
  billingApiUrl: resolvedBillingUrl,
4073
4152
  locale
4074
4153
  });
4075
- paymentResult = await handleSavedPaymentRedirectResult(result, {
4154
+ paymentResult = await handleSavedPaymentRedirectResult(redirectResult, {
4076
4155
  flopay,
4077
4156
  paypalFlopay,
4078
4157
  attempt3DS: true,
@@ -4080,9 +4159,66 @@ function FloPayAutomaticPaymentButton({
4080
4159
  sessionId: session.id || resolvedSessionId,
4081
4160
  session
4082
4161
  });
4083
- if (result.type === "paypal_redirect_required") {
4162
+ if (redirectResult.type === "paypal_redirect_required") {
4084
4163
  clearPayPalResumeState();
4085
4164
  }
4165
+ } else if (apiResult.autoProcessingError) {
4166
+ throw checkoutProcessErrorToFloPayError(
4167
+ apiResult.autoProcessingError,
4168
+ "Automatic payment failed. Please try again.",
4169
+ {
4170
+ checkoutMethod: apiResult.autoProcessingError.checkoutMethod
4171
+ }
4172
+ );
4173
+ } else if (shouldTreatCreateSessionFlowAsServerAutoAttempt) {
4174
+ throw checkoutProcessErrorToFloPayError(
4175
+ {
4176
+ type: "unknown",
4177
+ message: "Automatic payment failed. Please try again."
4178
+ },
4179
+ "Automatic payment failed. Please try again."
4180
+ );
4181
+ } else {
4182
+ const result = await processSavedPaymentForMode({
4183
+ billingApiUrl: resolvedBillingUrl,
4184
+ sessionId: resolvedSessionId ?? session.id,
4185
+ session,
4186
+ tokenizedData: automaticPaymentToken
4187
+ });
4188
+ paymentResult = result.type === "success" ? result.result : null;
4189
+ if (result.type !== "success") {
4190
+ const {
4191
+ publishableKey,
4192
+ paypalPublishableKey
4193
+ } = resolveSavedPaymentPublishableKeys(apiResult, fallbackPublishableKey);
4194
+ if (result.type === "paypal_redirect_required") {
4195
+ persistPayPalResumeState({
4196
+ sessionId: session.id || resolvedSessionId,
4197
+ publishableKey,
4198
+ paypalPublishableKey
4199
+ });
4200
+ }
4201
+ const {
4202
+ flopay,
4203
+ paypalFlopay
4204
+ } = await loadSavedPaymentProviders({
4205
+ publishableKey,
4206
+ paypalPublishableKey,
4207
+ billingApiUrl: resolvedBillingUrl,
4208
+ locale
4209
+ });
4210
+ paymentResult = await handleSavedPaymentRedirectResult(result, {
4211
+ flopay,
4212
+ paypalFlopay,
4213
+ attempt3DS: true,
4214
+ billingApiUrl: resolvedBillingUrl,
4215
+ sessionId: session.id || resolvedSessionId,
4216
+ session
4217
+ });
4218
+ if (result.type === "paypal_redirect_required") {
4219
+ clearPayPalResumeState();
4220
+ }
4221
+ }
4086
4222
  }
4087
4223
  await showSuccess({
4088
4224
  result: paymentResult ? {
@@ -4099,7 +4235,8 @@ function FloPayAutomaticPaymentButton({
4099
4235
  } catch (err) {
4100
4236
  let floPayErr = normalizeSavedPaymentError(err);
4101
4237
  const fallbackSessionId = session.id || resolvedSessionId;
4102
- if (floPayErr.code === "authentication_required" && fallbackSessionId && automaticPaymentToken?.id && automaticPaymentToken.id.startsWith("pm_")) {
4238
+ const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && apiResult.autoProcessingAttempted === true;
4239
+ if (!shouldTreatCreateSessionFlowAsServerAutoAttempt && floPayErr.code === "authentication_required" && fallbackSessionId && automaticPaymentToken?.id && automaticPaymentToken.id.startsWith("pm_")) {
4103
4240
  try {
4104
4241
  const {
4105
4242
  publishableKey,
@@ -4196,7 +4333,9 @@ function FloPayAutomaticPaymentButton({
4196
4333
  }
4197
4334
  try {
4198
4335
  const result = await api.createAndFetchSession(createSessionDraft);
4199
- await processResolvedSession(result, result.data.session?.id ?? null);
4336
+ await processResolvedSession(result, result.data.session?.id ?? null, {
4337
+ fromCreateSession: true
4338
+ });
4200
4339
  } catch (err) {
4201
4340
  if (err instanceof FloPayError7 && err.code === "session_auto_completed") {
4202
4341
  await showSuccess({