@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.cjs CHANGED
@@ -1246,9 +1246,22 @@ function SplitCardFormInner({
1246
1246
  }
1247
1247
  setIs3DSActive(true);
1248
1248
  try {
1249
+ const retryBillingAddress = {
1250
+ ...(enableAVS ? selectedCountryRef.current : effectiveAccount.country) ? {
1251
+ country: enableAVS ? selectedCountryRef.current : effectiveAccount.country
1252
+ } : {},
1253
+ ...(enableAVS ? zipCodeRef.current.trim() : effectiveAccount.zip) || "" ? {
1254
+ postal_code: enableAVS ? zipCodeRef.current.trim() : effectiveAccount.zip
1255
+ } : {}
1256
+ };
1249
1257
  const result = await flopay.confirmPayment({
1250
1258
  clientSecret: secret,
1251
- returnUrl: window.location.href
1259
+ returnUrl: window.location.href,
1260
+ billingDetails: {
1261
+ ...effectiveAccount.email ? { email: effectiveAccount.email } : {},
1262
+ ...fullName.trim() ? { name: fullName.trim() } : {},
1263
+ ...Object.keys(retryBillingAddress).length > 0 ? { address: retryBillingAddress } : {}
1264
+ }
1252
1265
  });
1253
1266
  if (result.error) {
1254
1267
  setOverlayStatus("error");
@@ -1407,13 +1420,19 @@ function SplitCardFormInner({
1407
1420
  onError?.(submitResult.error);
1408
1421
  return;
1409
1422
  }
1410
- const billingDetails = enableAVS ? {
1411
- name: fullName,
1412
- address: {
1413
- country: selectedCountryRef.current,
1414
- postal_code: zipCodeRef.current
1415
- }
1416
- } : void 0;
1423
+ const billingAddress = {
1424
+ ...(enableAVS ? selectedCountryRef.current : resolvedAccount.country) ? {
1425
+ country: enableAVS ? selectedCountryRef.current : resolvedAccount.country
1426
+ } : {},
1427
+ ...(enableAVS ? zipCodeRef.current.trim() : resolvedAccount.zip) || "" ? {
1428
+ postal_code: enableAVS ? zipCodeRef.current.trim() : resolvedAccount.zip
1429
+ } : {}
1430
+ };
1431
+ const billingDetails = {
1432
+ ...resolvedAccount.email ? { email: resolvedAccount.email } : {},
1433
+ ...fullName.trim() ? { name: fullName.trim() } : {},
1434
+ ...Object.keys(billingAddress).length > 0 ? { address: billingAddress } : {}
1435
+ };
1417
1436
  const pmResult = await flopay.createPaymentMethod(billingDetails);
1418
1437
  if (pmResult.error || !pmResult.paymentMethodId) {
1419
1438
  updateError(pmResult.error?.message ?? "Failed to create payment method.");
@@ -1923,6 +1942,32 @@ function SplitCardFormInner({
1923
1942
  var import_js = require("@flopay/js");
1924
1943
  var import_shared6 = require("@flopay/shared");
1925
1944
  var DEFAULT_SAVED_PAYMENT_DECLINE_METHOD = "card";
1945
+ function getRedirectResultFromCheckoutProcessError(error) {
1946
+ if (!error?.type || !error.threeDSecureToken) {
1947
+ return null;
1948
+ }
1949
+ if (error.type !== "3ds_required" && error.type !== "paypal_redirect_required") {
1950
+ return null;
1951
+ }
1952
+ return {
1953
+ type: error.type,
1954
+ threeDSecureToken: error.threeDSecureToken,
1955
+ paymentMethodId: error.paymentMethodId
1956
+ };
1957
+ }
1958
+ function checkoutProcessErrorToFloPayError(error, fallbackMessage = "Payment failed. Please try again.", options) {
1959
+ const checkoutMethod = options?.checkoutMethod ?? error?.checkoutMethod ?? (error?.type === "paypal_redirect_required" ? "paypal" : "card");
1960
+ return Object.assign(
1961
+ new import_shared6.FloPayError(
1962
+ error?.message ?? fallbackMessage,
1963
+ "api_error",
1964
+ {
1965
+ code: error?.gatewayErrorCode
1966
+ }
1967
+ ),
1968
+ { checkoutMethod }
1969
+ );
1970
+ }
1926
1971
  function resolveSavedPaymentReturnUrl(session) {
1927
1972
  if (typeof window !== "undefined" && window.location.href) {
1928
1973
  return window.location.href;
@@ -2531,19 +2576,45 @@ function FloPayCheckout({
2531
2576
  setModeOverlayStatus("processing");
2532
2577
  const activeSessionId2 = options?.sessionId ?? sess.id;
2533
2578
  try {
2534
- const result = await processSavedPaymentForMode({
2535
- billingApiUrl: resolvedBillingUrl,
2536
- sessionId: activeSessionId2,
2537
- session: sess
2538
- });
2539
- const paymentResult = result.type === "success" ? result.result : await handleSavedPaymentRedirectResult(result, {
2540
- flopay: flopayRef.current,
2541
- paypalFlopay: paypalFlopayRef.current,
2542
- attempt3DS: options?.attempt3DS,
2543
- billingApiUrl: resolvedBillingUrl,
2544
- sessionId: activeSessionId2,
2545
- session: sess
2546
- });
2579
+ const redirectResult = getRedirectResultFromCheckoutProcessError(options?.initialAutoProcessingError);
2580
+ let paymentResult;
2581
+ if (redirectResult) {
2582
+ paymentResult = await handleSavedPaymentRedirectResult(redirectResult, {
2583
+ flopay: flopayRef.current,
2584
+ paypalFlopay: paypalFlopayRef.current,
2585
+ attempt3DS: options?.attempt3DS,
2586
+ billingApiUrl: resolvedBillingUrl,
2587
+ sessionId: activeSessionId2,
2588
+ session: sess
2589
+ });
2590
+ } else if (options?.initialAutoProcessingError) {
2591
+ throw checkoutProcessErrorToFloPayError(
2592
+ options.initialAutoProcessingError,
2593
+ "Automatic payment failed. Please try again.",
2594
+ {
2595
+ checkoutMethod: options.initialAutoProcessingError.checkoutMethod
2596
+ }
2597
+ );
2598
+ } else if (options?.fromCreateSession) {
2599
+ if (options?.fallbackToFull) {
2600
+ setCurrentMode("full");
2601
+ }
2602
+ return false;
2603
+ } else {
2604
+ const result = await processSavedPaymentForMode({
2605
+ billingApiUrl: resolvedBillingUrl,
2606
+ sessionId: activeSessionId2,
2607
+ session: sess
2608
+ });
2609
+ paymentResult = result.type === "success" ? result.result : await handleSavedPaymentRedirectResult(result, {
2610
+ flopay: flopayRef.current,
2611
+ paypalFlopay: paypalFlopayRef.current,
2612
+ attempt3DS: options?.attempt3DS,
2613
+ billingApiUrl: resolvedBillingUrl,
2614
+ sessionId: activeSessionId2,
2615
+ session: sess
2616
+ });
2617
+ }
2547
2618
  setModeOverlayStatus("success");
2548
2619
  await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
2549
2620
  onCompleteRef.current?.(paymentResult);
@@ -2752,6 +2823,9 @@ function FloPayCheckout({
2752
2823
  await runSavedPaymentFlow(resolvedSession, {
2753
2824
  attempt3DS: true,
2754
2825
  fallbackToFull: true,
2826
+ fromCreateSession: true,
2827
+ initialAutoProcessingError: resolved.result.autoProcessingError,
2828
+ autoProcessingAttempted: resolved.result.autoProcessingAttempted,
2755
2829
  sessionId: resolved.sid || resolvedSession.id
2756
2830
  });
2757
2831
  return;
@@ -3434,9 +3508,14 @@ function CheckoutFormInner({
3434
3508
  }
3435
3509
  setIs3DSActive(true);
3436
3510
  try {
3511
+ const retryFullName = `${firstName ?? ""} ${lastName ?? ""}`.trim();
3437
3512
  const result = await flopay.confirmPayment({
3438
3513
  clientSecret: secret,
3439
- returnUrl: window.location.href
3514
+ returnUrl: window.location.href,
3515
+ billingDetails: {
3516
+ ...email ? { email } : {},
3517
+ ...retryFullName ? { name: retryFullName } : {}
3518
+ }
3440
3519
  });
3441
3520
  if (result.error) {
3442
3521
  updateError(result.error.message);
@@ -3572,7 +3651,11 @@ function CheckoutFormInner({
3572
3651
  onError?.(submitResult.error);
3573
3652
  return;
3574
3653
  }
3575
- const pmResult = await flopay.createPaymentMethod();
3654
+ const fullName = `${firstName ?? ""} ${lastName ?? ""}`.trim();
3655
+ const pmResult = await flopay.createPaymentMethod({
3656
+ ...email ? { email } : {},
3657
+ ...fullName ? { name: fullName } : {}
3658
+ });
3576
3659
  if (pmResult.error || !pmResult.paymentMethodId) {
3577
3660
  updateError(pmResult.error?.message ?? "Failed to create payment method.");
3578
3661
  return;
@@ -4075,7 +4158,7 @@ function FloPayAutomaticPaymentButton({
4075
4158
  setOverlayStatus("error");
4076
4159
  await sleep2(PROCESSING_OVERLAY_ERROR_DELAY_MS);
4077
4160
  }, [emitDecline]);
4078
- const processResolvedSession = (0, import_react11.useCallback)(async (apiResult, resolvedSessionId) => {
4161
+ const processResolvedSession = (0, import_react11.useCallback)(async (apiResult, resolvedSessionId, options) => {
4079
4162
  const session = apiResult.data.session ?? null;
4080
4163
  if (!session) {
4081
4164
  throw new import_shared10.FloPayError("No session data returned", "api_error");
@@ -4090,19 +4173,15 @@ function FloPayAutomaticPaymentButton({
4090
4173
  return;
4091
4174
  }
4092
4175
  try {
4093
- const result = await processSavedPaymentForMode({
4094
- billingApiUrl: resolvedBillingUrl,
4095
- sessionId: resolvedSessionId ?? session.id,
4096
- session,
4097
- tokenizedData: automaticPaymentToken
4098
- });
4099
- let paymentResult = result.type === "success" ? result.result : null;
4100
- if (result.type !== "success") {
4176
+ let paymentResult = null;
4177
+ const redirectResult = getRedirectResultFromCheckoutProcessError(apiResult.autoProcessingError);
4178
+ const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && (apiResult.autoProcessingAttempted === true || !!apiResult.autoProcessingError || !!redirectResult);
4179
+ if (redirectResult) {
4101
4180
  const {
4102
4181
  publishableKey,
4103
4182
  paypalPublishableKey
4104
4183
  } = resolveSavedPaymentPublishableKeys(apiResult, fallbackPublishableKey);
4105
- if (result.type === "paypal_redirect_required") {
4184
+ if (redirectResult.type === "paypal_redirect_required") {
4106
4185
  persistPayPalResumeState({
4107
4186
  sessionId: session.id || resolvedSessionId,
4108
4187
  publishableKey,
@@ -4118,7 +4197,7 @@ function FloPayAutomaticPaymentButton({
4118
4197
  billingApiUrl: resolvedBillingUrl,
4119
4198
  locale
4120
4199
  });
4121
- paymentResult = await handleSavedPaymentRedirectResult(result, {
4200
+ paymentResult = await handleSavedPaymentRedirectResult(redirectResult, {
4122
4201
  flopay,
4123
4202
  paypalFlopay,
4124
4203
  attempt3DS: true,
@@ -4126,9 +4205,66 @@ function FloPayAutomaticPaymentButton({
4126
4205
  sessionId: session.id || resolvedSessionId,
4127
4206
  session
4128
4207
  });
4129
- if (result.type === "paypal_redirect_required") {
4208
+ if (redirectResult.type === "paypal_redirect_required") {
4130
4209
  clearPayPalResumeState();
4131
4210
  }
4211
+ } else if (apiResult.autoProcessingError) {
4212
+ throw checkoutProcessErrorToFloPayError(
4213
+ apiResult.autoProcessingError,
4214
+ "Automatic payment failed. Please try again.",
4215
+ {
4216
+ checkoutMethod: apiResult.autoProcessingError.checkoutMethod
4217
+ }
4218
+ );
4219
+ } else if (shouldTreatCreateSessionFlowAsServerAutoAttempt) {
4220
+ throw checkoutProcessErrorToFloPayError(
4221
+ {
4222
+ type: "unknown",
4223
+ message: "Automatic payment failed. Please try again."
4224
+ },
4225
+ "Automatic payment failed. Please try again."
4226
+ );
4227
+ } else {
4228
+ const result = await processSavedPaymentForMode({
4229
+ billingApiUrl: resolvedBillingUrl,
4230
+ sessionId: resolvedSessionId ?? session.id,
4231
+ session,
4232
+ tokenizedData: automaticPaymentToken
4233
+ });
4234
+ paymentResult = result.type === "success" ? result.result : null;
4235
+ if (result.type !== "success") {
4236
+ const {
4237
+ publishableKey,
4238
+ paypalPublishableKey
4239
+ } = resolveSavedPaymentPublishableKeys(apiResult, fallbackPublishableKey);
4240
+ if (result.type === "paypal_redirect_required") {
4241
+ persistPayPalResumeState({
4242
+ sessionId: session.id || resolvedSessionId,
4243
+ publishableKey,
4244
+ paypalPublishableKey
4245
+ });
4246
+ }
4247
+ const {
4248
+ flopay,
4249
+ paypalFlopay
4250
+ } = await loadSavedPaymentProviders({
4251
+ publishableKey,
4252
+ paypalPublishableKey,
4253
+ billingApiUrl: resolvedBillingUrl,
4254
+ locale
4255
+ });
4256
+ paymentResult = await handleSavedPaymentRedirectResult(result, {
4257
+ flopay,
4258
+ paypalFlopay,
4259
+ attempt3DS: true,
4260
+ billingApiUrl: resolvedBillingUrl,
4261
+ sessionId: session.id || resolvedSessionId,
4262
+ session
4263
+ });
4264
+ if (result.type === "paypal_redirect_required") {
4265
+ clearPayPalResumeState();
4266
+ }
4267
+ }
4132
4268
  }
4133
4269
  await showSuccess({
4134
4270
  result: paymentResult ? {
@@ -4145,7 +4281,8 @@ function FloPayAutomaticPaymentButton({
4145
4281
  } catch (err) {
4146
4282
  let floPayErr = normalizeSavedPaymentError(err);
4147
4283
  const fallbackSessionId = session.id || resolvedSessionId;
4148
- if (floPayErr.code === "authentication_required" && fallbackSessionId && automaticPaymentToken?.id && automaticPaymentToken.id.startsWith("pm_")) {
4284
+ const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && apiResult.autoProcessingAttempted === true;
4285
+ if (!shouldTreatCreateSessionFlowAsServerAutoAttempt && floPayErr.code === "authentication_required" && fallbackSessionId && automaticPaymentToken?.id && automaticPaymentToken.id.startsWith("pm_")) {
4149
4286
  try {
4150
4287
  const {
4151
4288
  publishableKey,
@@ -4242,7 +4379,9 @@ function FloPayAutomaticPaymentButton({
4242
4379
  }
4243
4380
  try {
4244
4381
  const result = await api.createAndFetchSession(createSessionDraft);
4245
- await processResolvedSession(result, result.data.session?.id ?? null);
4382
+ await processResolvedSession(result, result.data.session?.id ?? null, {
4383
+ fromCreateSession: true
4384
+ });
4246
4385
  } catch (err) {
4247
4386
  if (err instanceof import_shared10.FloPayError && err.code === "session_auto_completed") {
4248
4387
  await showSuccess({