@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.mjs CHANGED
@@ -588,6 +588,39 @@ function resolveTokenizedPaymentMethodId(tokenizedBody) {
588
588
  return void 0;
589
589
  }
590
590
 
591
+ // src/recent-completion.ts
592
+ var STORAGE_KEY_PREFIX = "flopay_recent_completion_";
593
+ var RECENT_COMPLETION_TTL_MS = 60 * 1e3;
594
+ function markSessionRecentlyCompleted(sessionId) {
595
+ if (!sessionId || typeof window === "undefined") return;
596
+ try {
597
+ const payload = {
598
+ expiresAt: Date.now() + RECENT_COMPLETION_TTL_MS
599
+ };
600
+ window.sessionStorage.setItem(STORAGE_KEY_PREFIX + sessionId, JSON.stringify(payload));
601
+ } catch {
602
+ }
603
+ }
604
+ function wasSessionRecentlyCompleted(sessionId) {
605
+ if (!sessionId || typeof window === "undefined") return false;
606
+ try {
607
+ const raw = window.sessionStorage.getItem(STORAGE_KEY_PREFIX + sessionId);
608
+ if (!raw) return false;
609
+ const parsed = JSON.parse(raw);
610
+ if (typeof parsed?.expiresAt !== "number") {
611
+ window.sessionStorage.removeItem(STORAGE_KEY_PREFIX + sessionId);
612
+ return false;
613
+ }
614
+ if (parsed.expiresAt <= Date.now()) {
615
+ window.sessionStorage.removeItem(STORAGE_KEY_PREFIX + sessionId);
616
+ return false;
617
+ }
618
+ return true;
619
+ } catch {
620
+ return false;
621
+ }
622
+ }
623
+
591
624
  // src/split-card-form.tsx
592
625
  import { FloPayError as FloPayError2 } from "@flopay/shared";
593
626
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -719,6 +752,17 @@ function PayPalButtonInner({
719
752
  const redirectStatus = params.get("redirect_status");
720
753
  if (!paymentIntentId || !clientSecret) return;
721
754
  paypalResumeAttempted.current = true;
755
+ console.info("[FloPay debug] PayPal resume effect firing", {
756
+ paymentIntentId,
757
+ redirectStatus,
758
+ currentSessionId: sessionId,
759
+ url: window.location.href
760
+ });
761
+ const cleanedUrl = new URL(window.location.href);
762
+ cleanedUrl.searchParams.delete("payment_intent");
763
+ cleanedUrl.searchParams.delete("payment_intent_client_secret");
764
+ cleanedUrl.searchParams.delete("redirect_status");
765
+ window.history.replaceState({}, "", cleanedUrl.toString());
722
766
  (async () => {
723
767
  try {
724
768
  setSubmitting(true);
@@ -741,11 +785,6 @@ function PayPalButtonInner({
741
785
  threeDSecureActionResultTokenId: paymentIntent.id,
742
786
  isPaypal: true
743
787
  });
744
- const url = new URL(window.location.href);
745
- url.searchParams.delete("payment_intent");
746
- url.searchParams.delete("payment_intent_client_secret");
747
- url.searchParams.delete("redirect_status");
748
- window.history.replaceState({}, "", url.toString());
749
788
  } else {
750
789
  const message = "PayPal payment was not completed. Please try again.";
751
790
  onErrorChange?.(message);
@@ -773,8 +812,9 @@ function PayPalButtonInner({
773
812
  accountPatch: beforeClick.accountPatch,
774
813
  sessionId: beforeClick.sessionId
775
814
  };
815
+ onButtonClick?.("paypal");
776
816
  event.resolve();
777
- }, [isProcessing, runBeforeButtonClick, submitting]);
817
+ }, [isProcessing, onButtonClick, runBeforeButtonClick, submitting]);
778
818
  const handlePayPalConfirm = useCallback(async (event) => {
779
819
  if (!stripe || !elements) return;
780
820
  let prepared = beforeClickRef.current;
@@ -792,7 +832,6 @@ function PayPalButtonInner({
792
832
  }
793
833
  const effectiveSessionId = prepared?.sessionId ?? sessionId;
794
834
  const effectiveEmail = prepared?.accountPatch?.email ?? email;
795
- onButtonClick?.("paypal");
796
835
  try {
797
836
  setSubmitting(true);
798
837
  onErrorChange?.(null);
@@ -867,7 +906,7 @@ function PayPalButtonInner({
867
906
  } finally {
868
907
  setSubmitting(false);
869
908
  }
870
- }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]);
909
+ }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]);
871
910
  return /* @__PURE__ */ jsxs3(Fragment2, { children: [
872
911
  /* @__PURE__ */ jsx5(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ jsx5(
873
912
  ExpressCheckoutElement,
@@ -938,7 +977,6 @@ function WalletButtonInner({
938
977
  const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
939
978
  const effectiveSessionId = prepared?.sessionId ?? sessionId;
940
979
  const effectiveEmail = prepared?.accountPatch?.email ?? email;
941
- onButtonClick?.(walletType === "apple_pay" ? "apple_pay" : "google_pay");
942
980
  try {
943
981
  setSubmitting(true);
944
982
  onErrorChange?.(null);
@@ -1004,7 +1042,7 @@ function WalletButtonInner({
1004
1042
  setSubmitting(false);
1005
1043
  }
1006
1044
  },
1007
- [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]
1045
+ [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]
1008
1046
  );
1009
1047
  return /* @__PURE__ */ jsxs3(Fragment2, { children: [
1010
1048
  /* @__PURE__ */ jsx5(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ jsx5(
@@ -1024,6 +1062,7 @@ function WalletButtonInner({
1024
1062
  accountPatch: beforeClick.accountPatch,
1025
1063
  sessionId: beforeClick.sessionId
1026
1064
  };
1065
+ onButtonClick?.(lastWalletMethodRef.current);
1027
1066
  event.resolve();
1028
1067
  },
1029
1068
  onConfirm: handleWalletConfirm,
@@ -1278,6 +1317,11 @@ function SplitCardFormInner({
1278
1317
  const effectiveAccount = mergeAccountPatch(resolvedAccount, overrides?.accountPatch);
1279
1318
  const resolvedCompletionPaymentMethodId = overrides?.completionPaymentMethodId ?? resolveTokenizedPaymentMethodId(tokenizedBody);
1280
1319
  const requestTokenizedBody = tokenizedBody.originalPaymentMethodId ? { ...tokenizedBody, originalPaymentMethodId: void 0 } : tokenizedBody;
1320
+ console.info("[FloPay debug] processPaymentInternal -> POST /process", {
1321
+ sessionId: effectiveSessionId,
1322
+ paymentIntentId: tokenizedBody.threeDSecureActionResultTokenId,
1323
+ isPaypal: tokenizedBody.isPaypal
1324
+ });
1281
1325
  try {
1282
1326
  const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
1283
1327
  method: "POST",
@@ -1328,6 +1372,7 @@ function SplitCardFormInner({
1328
1372
  })
1329
1373
  });
1330
1374
  if (response.ok) {
1375
+ markSessionRecentlyCompleted(effectiveSessionId);
1331
1376
  setOverlayStatus("success");
1332
1377
  await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_SUCCESS_DELAY_MS));
1333
1378
  onComplete?.({
@@ -2740,6 +2785,7 @@ async function loadSavedPaymentProviders({
2740
2785
  import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
2741
2786
  var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
2742
2787
  var PAYPAL_RESUME_STORAGE_KEY = "flopay_checkout_saved_payment_resume";
2788
+ var sessionInflightMap = /* @__PURE__ */ new Map();
2743
2789
  function sleep(ms) {
2744
2790
  return new Promise((resolve) => setTimeout(resolve, ms));
2745
2791
  }
@@ -2981,6 +3027,7 @@ function FloPayCheckout({
2981
3027
  }
2982
3028
  }
2983
3029
  }
3030
+ if (activeSessionId2) markSessionRecentlyCompleted(activeSessionId2);
2984
3031
  setModeOverlayStatus("success");
2985
3032
  await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
2986
3033
  onCompleteRef.current?.(paymentResult);
@@ -3077,6 +3124,7 @@ function FloPayCheckout({
3077
3124
  );
3078
3125
  }
3079
3126
  const paymentMethodId = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
3127
+ if (resumeState.sessionId) markSessionRecentlyCompleted(resumeState.sessionId);
3080
3128
  setModeOverlayStatus("success");
3081
3129
  await sleep(PROCESSING_OVERLAY_SUCCESS_DELAY_MS);
3082
3130
  onCompleteRef.current?.({
@@ -3106,13 +3154,11 @@ function FloPayCheckout({
3106
3154
  }
3107
3155
  })();
3108
3156
  }, [emitDecline, locale, normalizeSavedPaymentError, resolvedBillingUrl]);
3109
- const inflightRef = useRef3(/* @__PURE__ */ new Map());
3110
3157
  const initializedHashRef = useRef3(null);
3111
3158
  function hashCreateParams(params) {
3112
3159
  const key = JSON.stringify({
3113
3160
  c: params?.clientId,
3114
3161
  a: {
3115
- u: params?.account?.userId ?? "",
3116
3162
  e: params?.account?.email?.trim().toLowerCase() ?? "",
3117
3163
  country: params?.account?.country ?? ""
3118
3164
  },
@@ -3151,20 +3197,42 @@ function FloPayCheckout({
3151
3197
  const api = new PaymentAPI2(resolvedBillingUrl);
3152
3198
  let sid = typeof window !== "undefined" ? window.sessionStorage.getItem(cacheKey) : null;
3153
3199
  let realResult = null;
3200
+ console.info("[FloPay debug] resolveInlineSession enter", {
3201
+ cacheKey,
3202
+ cachedSid: sid,
3203
+ url: typeof window !== "undefined" ? window.location.href : null
3204
+ });
3154
3205
  if (sid) {
3155
3206
  try {
3156
3207
  realResult = await api.getUnifiedCheckoutSession(sid);
3157
- if (realResult.data.session?.status === "complete") {
3208
+ const status = realResult.data.session?.status;
3209
+ console.info("[FloPay debug] resolveInlineSession cache hit", {
3210
+ cacheKey,
3211
+ sid,
3212
+ status,
3213
+ recentlyCompleted: wasSessionRecentlyCompleted(sid)
3214
+ });
3215
+ if (status === "complete") {
3216
+ if (wasSessionRecentlyCompleted(sid)) {
3217
+ console.info("[FloPay debug] resolveInlineSession reuse-completed", { sid });
3218
+ return { sid, result: realResult };
3219
+ }
3220
+ console.warn("[FloPay debug] resolveInlineSession clearing stale complete cache", { sid });
3158
3221
  if (typeof window !== "undefined") window.sessionStorage.removeItem(cacheKey);
3159
3222
  sid = null;
3160
3223
  realResult = null;
3161
3224
  }
3162
- } catch {
3225
+ } catch (err) {
3226
+ console.warn("[FloPay debug] resolveInlineSession getUnifiedCheckoutSession threw", { sid, err });
3163
3227
  if (typeof window !== "undefined") window.sessionStorage.removeItem(cacheKey);
3164
3228
  sid = null;
3165
3229
  }
3166
3230
  }
3167
3231
  if (!sid) {
3232
+ console.warn("[FloPay debug] resolveInlineSession POSTing /v1/checkouts/sessions", {
3233
+ cacheKey,
3234
+ url: typeof window !== "undefined" ? window.location.href : null
3235
+ });
3168
3236
  const paramsWithAnalytics = {
3169
3237
  ...params,
3170
3238
  avsCheck: !!enableAVS,
@@ -3188,16 +3256,22 @@ function FloPayCheckout({
3188
3256
  }
3189
3257
  const mergedParams = mergeInlineSessionPatch(baseParams, patch);
3190
3258
  const cacheKey = hashCreateParams(mergedParams);
3191
- let promise = inflightRef.current.get(cacheKey);
3259
+ let promise = sessionInflightMap.get(cacheKey);
3260
+ const inflightHit = !!promise;
3192
3261
  if (!promise) {
3193
3262
  promise = resolveInlineSession(mergedParams, cacheKey);
3194
- inflightRef.current.set(cacheKey, promise);
3263
+ sessionInflightMap.set(cacheKey, promise);
3195
3264
  }
3265
+ console.info("[FloPay debug] bootstrapInlineSession", {
3266
+ cacheKey,
3267
+ inflightHit,
3268
+ url: typeof window !== "undefined" ? window.location.href : null
3269
+ });
3196
3270
  let resolved;
3197
3271
  try {
3198
3272
  resolved = await promise;
3199
3273
  } finally {
3200
- inflightRef.current.delete(cacheKey);
3274
+ sessionInflightMap.delete(cacheKey);
3201
3275
  }
3202
3276
  initializedHashRef.current = cacheKey;
3203
3277
  try {