@flopay/react 0.5.5 → 0.5.10

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
@@ -625,6 +625,39 @@ function resolveTokenizedPaymentMethodId(tokenizedBody) {
625
625
  return void 0;
626
626
  }
627
627
 
628
+ // src/recent-completion.ts
629
+ var STORAGE_KEY_PREFIX = "flopay_recent_completion_";
630
+ var RECENT_COMPLETION_TTL_MS = 60 * 1e3;
631
+ function markSessionRecentlyCompleted(sessionId) {
632
+ if (!sessionId || typeof window === "undefined") return;
633
+ try {
634
+ const payload = {
635
+ expiresAt: Date.now() + RECENT_COMPLETION_TTL_MS
636
+ };
637
+ window.sessionStorage.setItem(STORAGE_KEY_PREFIX + sessionId, JSON.stringify(payload));
638
+ } catch {
639
+ }
640
+ }
641
+ function wasSessionRecentlyCompleted(sessionId) {
642
+ if (!sessionId || typeof window === "undefined") return false;
643
+ try {
644
+ const raw = window.sessionStorage.getItem(STORAGE_KEY_PREFIX + sessionId);
645
+ if (!raw) return false;
646
+ const parsed = JSON.parse(raw);
647
+ if (typeof parsed?.expiresAt !== "number") {
648
+ window.sessionStorage.removeItem(STORAGE_KEY_PREFIX + sessionId);
649
+ return false;
650
+ }
651
+ if (parsed.expiresAt <= Date.now()) {
652
+ window.sessionStorage.removeItem(STORAGE_KEY_PREFIX + sessionId);
653
+ return false;
654
+ }
655
+ return true;
656
+ } catch {
657
+ return false;
658
+ }
659
+ }
660
+
628
661
  // src/split-card-form.tsx
629
662
  var import_shared5 = require("@flopay/shared");
630
663
  var import_jsx_runtime5 = require("react/jsx-runtime");
@@ -756,6 +789,17 @@ function PayPalButtonInner({
756
789
  const redirectStatus = params.get("redirect_status");
757
790
  if (!paymentIntentId || !clientSecret) return;
758
791
  paypalResumeAttempted.current = true;
792
+ console.info("[FloPay debug] PayPal resume effect firing", {
793
+ paymentIntentId,
794
+ redirectStatus,
795
+ currentSessionId: sessionId,
796
+ url: window.location.href
797
+ });
798
+ const cleanedUrl = new URL(window.location.href);
799
+ cleanedUrl.searchParams.delete("payment_intent");
800
+ cleanedUrl.searchParams.delete("payment_intent_client_secret");
801
+ cleanedUrl.searchParams.delete("redirect_status");
802
+ window.history.replaceState({}, "", cleanedUrl.toString());
759
803
  (async () => {
760
804
  try {
761
805
  setSubmitting(true);
@@ -778,11 +822,6 @@ function PayPalButtonInner({
778
822
  threeDSecureActionResultTokenId: paymentIntent.id,
779
823
  isPaypal: true
780
824
  });
781
- const url = new URL(window.location.href);
782
- url.searchParams.delete("payment_intent");
783
- url.searchParams.delete("payment_intent_client_secret");
784
- url.searchParams.delete("redirect_status");
785
- window.history.replaceState({}, "", url.toString());
786
825
  } else {
787
826
  const message = "PayPal payment was not completed. Please try again.";
788
827
  onErrorChange?.(message);
@@ -810,8 +849,9 @@ function PayPalButtonInner({
810
849
  accountPatch: beforeClick.accountPatch,
811
850
  sessionId: beforeClick.sessionId
812
851
  };
852
+ onButtonClick?.("paypal");
813
853
  event.resolve();
814
- }, [isProcessing, runBeforeButtonClick, submitting]);
854
+ }, [isProcessing, onButtonClick, runBeforeButtonClick, submitting]);
815
855
  const handlePayPalConfirm = (0, import_react7.useCallback)(async (event) => {
816
856
  if (!stripe || !elements) return;
817
857
  let prepared = beforeClickRef.current;
@@ -829,7 +869,6 @@ function PayPalButtonInner({
829
869
  }
830
870
  const effectiveSessionId = prepared?.sessionId ?? sessionId;
831
871
  const effectiveEmail = prepared?.accountPatch?.email ?? email;
832
- onButtonClick?.("paypal");
833
872
  try {
834
873
  setSubmitting(true);
835
874
  onErrorChange?.(null);
@@ -904,7 +943,7 @@ function PayPalButtonInner({
904
943
  } finally {
905
944
  setSubmitting(false);
906
945
  }
907
- }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]);
946
+ }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]);
908
947
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
909
948
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
910
949
  import_react_stripe_js.ExpressCheckoutElement,
@@ -975,7 +1014,6 @@ function WalletButtonInner({
975
1014
  const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
976
1015
  const effectiveSessionId = prepared?.sessionId ?? sessionId;
977
1016
  const effectiveEmail = prepared?.accountPatch?.email ?? email;
978
- onButtonClick?.(walletType === "apple_pay" ? "apple_pay" : "google_pay");
979
1017
  try {
980
1018
  setSubmitting(true);
981
1019
  onErrorChange?.(null);
@@ -1041,7 +1079,7 @@ function WalletButtonInner({
1041
1079
  setSubmitting(false);
1042
1080
  }
1043
1081
  },
1044
- [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]
1082
+ [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]
1045
1083
  );
1046
1084
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1047
1085
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
@@ -1061,6 +1099,7 @@ function WalletButtonInner({
1061
1099
  accountPatch: beforeClick.accountPatch,
1062
1100
  sessionId: beforeClick.sessionId
1063
1101
  };
1102
+ onButtonClick?.(lastWalletMethodRef.current);
1064
1103
  event.resolve();
1065
1104
  },
1066
1105
  onConfirm: handleWalletConfirm,
@@ -1315,6 +1354,11 @@ function SplitCardFormInner({
1315
1354
  const effectiveAccount = mergeAccountPatch(resolvedAccount, overrides?.accountPatch);
1316
1355
  const resolvedCompletionPaymentMethodId = overrides?.completionPaymentMethodId ?? resolveTokenizedPaymentMethodId(tokenizedBody);
1317
1356
  const requestTokenizedBody = tokenizedBody.originalPaymentMethodId ? { ...tokenizedBody, originalPaymentMethodId: void 0 } : tokenizedBody;
1357
+ console.info("[FloPay debug] processPaymentInternal -> POST /process", {
1358
+ sessionId: effectiveSessionId,
1359
+ paymentIntentId: tokenizedBody.threeDSecureActionResultTokenId,
1360
+ isPaypal: tokenizedBody.isPaypal
1361
+ });
1318
1362
  try {
1319
1363
  const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
1320
1364
  method: "POST",
@@ -1365,6 +1409,7 @@ function SplitCardFormInner({
1365
1409
  })
1366
1410
  });
1367
1411
  if (response.ok) {
1412
+ markSessionRecentlyCompleted(effectiveSessionId);
1368
1413
  setOverlayStatus("success");
1369
1414
  await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_SUCCESS_DELAY_MS));
1370
1415
  onComplete?.({
@@ -2777,6 +2822,7 @@ async function loadSavedPaymentProviders({
2777
2822
  var import_jsx_runtime6 = require("react/jsx-runtime");
2778
2823
  var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
2779
2824
  var PAYPAL_RESUME_STORAGE_KEY = "flopay_checkout_saved_payment_resume";
2825
+ var sessionInflightMap = /* @__PURE__ */ new Map();
2780
2826
  function sleep(ms) {
2781
2827
  return new Promise((resolve) => setTimeout(resolve, ms));
2782
2828
  }
@@ -3018,6 +3064,7 @@ function FloPayCheckout({
3018
3064
  }
3019
3065
  }
3020
3066
  }
3067
+ if (activeSessionId2) markSessionRecentlyCompleted(activeSessionId2);
3021
3068
  setModeOverlayStatus("success");
3022
3069
  await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
3023
3070
  onCompleteRef.current?.(paymentResult);
@@ -3114,6 +3161,7 @@ function FloPayCheckout({
3114
3161
  );
3115
3162
  }
3116
3163
  const paymentMethodId = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
3164
+ if (resumeState.sessionId) markSessionRecentlyCompleted(resumeState.sessionId);
3117
3165
  setModeOverlayStatus("success");
3118
3166
  await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
3119
3167
  onCompleteRef.current?.({
@@ -3143,13 +3191,11 @@ function FloPayCheckout({
3143
3191
  }
3144
3192
  })();
3145
3193
  }, [emitDecline, locale, normalizeSavedPaymentError, resolvedBillingUrl]);
3146
- const inflightRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
3147
3194
  const initializedHashRef = (0, import_react8.useRef)(null);
3148
3195
  function hashCreateParams(params) {
3149
3196
  const key = JSON.stringify({
3150
3197
  c: params?.clientId,
3151
3198
  a: {
3152
- u: params?.account?.userId ?? "",
3153
3199
  e: params?.account?.email?.trim().toLowerCase() ?? "",
3154
3200
  country: params?.account?.country ?? ""
3155
3201
  },
@@ -3188,20 +3234,42 @@ function FloPayCheckout({
3188
3234
  const api = new import_js2.PaymentAPI(resolvedBillingUrl);
3189
3235
  let sid = typeof window !== "undefined" ? window.sessionStorage.getItem(cacheKey) : null;
3190
3236
  let realResult = null;
3237
+ console.info("[FloPay debug] resolveInlineSession enter", {
3238
+ cacheKey,
3239
+ cachedSid: sid,
3240
+ url: typeof window !== "undefined" ? window.location.href : null
3241
+ });
3191
3242
  if (sid) {
3192
3243
  try {
3193
3244
  realResult = await api.getUnifiedCheckoutSession(sid);
3194
- if (realResult.data.session?.status === "complete") {
3245
+ const status = realResult.data.session?.status;
3246
+ console.info("[FloPay debug] resolveInlineSession cache hit", {
3247
+ cacheKey,
3248
+ sid,
3249
+ status,
3250
+ recentlyCompleted: wasSessionRecentlyCompleted(sid)
3251
+ });
3252
+ if (status === "complete") {
3253
+ if (wasSessionRecentlyCompleted(sid)) {
3254
+ console.info("[FloPay debug] resolveInlineSession reuse-completed", { sid });
3255
+ return { sid, result: realResult };
3256
+ }
3257
+ console.warn("[FloPay debug] resolveInlineSession clearing stale complete cache", { sid });
3195
3258
  if (typeof window !== "undefined") window.sessionStorage.removeItem(cacheKey);
3196
3259
  sid = null;
3197
3260
  realResult = null;
3198
3261
  }
3199
- } catch {
3262
+ } catch (err) {
3263
+ console.warn("[FloPay debug] resolveInlineSession getUnifiedCheckoutSession threw", { sid, err });
3200
3264
  if (typeof window !== "undefined") window.sessionStorage.removeItem(cacheKey);
3201
3265
  sid = null;
3202
3266
  }
3203
3267
  }
3204
3268
  if (!sid) {
3269
+ console.warn("[FloPay debug] resolveInlineSession POSTing /v1/checkouts/sessions", {
3270
+ cacheKey,
3271
+ url: typeof window !== "undefined" ? window.location.href : null
3272
+ });
3205
3273
  const paramsWithAnalytics = {
3206
3274
  ...params,
3207
3275
  avsCheck: !!enableAVS,
@@ -3225,16 +3293,22 @@ function FloPayCheckout({
3225
3293
  }
3226
3294
  const mergedParams = mergeInlineSessionPatch(baseParams, patch);
3227
3295
  const cacheKey = hashCreateParams(mergedParams);
3228
- let promise = inflightRef.current.get(cacheKey);
3296
+ let promise = sessionInflightMap.get(cacheKey);
3297
+ const inflightHit = !!promise;
3229
3298
  if (!promise) {
3230
3299
  promise = resolveInlineSession(mergedParams, cacheKey);
3231
- inflightRef.current.set(cacheKey, promise);
3300
+ sessionInflightMap.set(cacheKey, promise);
3232
3301
  }
3302
+ console.info("[FloPay debug] bootstrapInlineSession", {
3303
+ cacheKey,
3304
+ inflightHit,
3305
+ url: typeof window !== "undefined" ? window.location.href : null
3306
+ });
3233
3307
  let resolved;
3234
3308
  try {
3235
3309
  resolved = await promise;
3236
3310
  } finally {
3237
- inflightRef.current.delete(cacheKey);
3311
+ sessionInflightMap.delete(cacheKey);
3238
3312
  }
3239
3313
  initializedHashRef.current = cacheKey;
3240
3314
  try {