@flopay/react 0.3.15 → 0.3.17

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/README.md CHANGED
@@ -131,14 +131,16 @@ Use `onButtonClick` to track button interactions, `onDecline` to track declines/
131
131
  createSession={{
132
132
  clientId: 'your-client-id',
133
133
  items: [{ providerItemId: 'product-1', providerItemName: 'Widget', totalAmount: 29.99, currency: 'EUR' }],
134
- account: { userId: 'user_1' },
134
+ account: { userId: 'user_1', email: 'test@email.com' },
135
135
  successUrl: '/success',
136
136
  cancelUrl: '/cancel',
137
137
  }}
138
- onBeforeButtonClick={async ({ method }) => {
138
+ onBeforeButtonClick={async ({ method, createSession }) => {
139
139
  if (method !== 'card') return;
140
140
 
141
- const email = await openEmailCaptureModal();
141
+ const email = await openEmailCaptureModal({
142
+ initialEmail: createSession?.account.email ?? '',
143
+ });
142
144
  if (!email) return false;
143
145
 
144
146
  return {
@@ -178,7 +180,7 @@ Skip the backend API route — create the session directly in the component:
178
180
 
179
181
  The component POSTs to the billing API, gets the full session back, and renders the form — zero backend code needed.
180
182
 
181
- When you use `onBeforeButtonClick`, `createSession.account.email` can still be filled in later for the card-button flow. PayPal and wallet buttons still bootstrap normally, but this hook does not run for them, so collect any data those methods require before the user uses them.
183
+ When you use `onBeforeButtonClick`, `createSession.account.email` should still be present when checkout renders. If you only have a temporary address such as `test@email.com`, pass it first and replace it in `onBeforeButtonClick` before the card flow continues. PayPal and wallet buttons still bootstrap normally, but this hook does not run for them, so collect any data those methods require before the user uses them.
182
184
 
183
185
  ### Advanced: Manual Provider Setup
184
186
 
package/dist/index.cjs CHANGED
@@ -405,6 +405,52 @@ function toCssWeight(value) {
405
405
  if (typeof value === "number" || typeof value === "string") return value;
406
406
  return void 0;
407
407
  }
408
+ function resolveExpressCheckoutLoadState(event, methods) {
409
+ const available = event.availablePaymentMethods;
410
+ if (!available) return "unavailable";
411
+ return methods.some((method) => available[method]) ? "ready" : "unavailable";
412
+ }
413
+ function ExpressCheckoutReadySwap({
414
+ state,
415
+ placeholderTestId,
416
+ children
417
+ }) {
418
+ if (state === "unavailable") return null;
419
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { position: "relative", minHeight: 44 }, children: [
420
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
421
+ "div",
422
+ {
423
+ "data-testid": placeholderTestId,
424
+ "aria-hidden": state === "ready",
425
+ style: {
426
+ position: "absolute",
427
+ inset: 0,
428
+ height: 44,
429
+ borderRadius: 8,
430
+ background: "#e5e7eb",
431
+ animation: state === "ready" ? void 0 : "flopay-pulse 1.5s ease-in-out infinite",
432
+ opacity: state === "ready" ? 0 : 1,
433
+ transform: state === "ready" ? "scale(0.985)" : "scale(1)",
434
+ transition: "opacity 140ms ease-out, transform 140ms ease-out",
435
+ pointerEvents: "none"
436
+ }
437
+ }
438
+ ),
439
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
440
+ "div",
441
+ {
442
+ style: {
443
+ minHeight: 44,
444
+ opacity: state === "ready" ? 1 : 0,
445
+ transform: state === "ready" ? "translateY(0)" : "translateY(2px)",
446
+ transition: "opacity 140ms ease-out, transform 140ms ease-out",
447
+ pointerEvents: state === "ready" ? "auto" : "none"
448
+ },
449
+ children
450
+ }
451
+ )
452
+ ] });
453
+ }
408
454
  function ProcessingOverlay({ status, errorMessage }) {
409
455
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: {
410
456
  position: "fixed",
@@ -522,7 +568,7 @@ function PayPalButtonInner({
522
568
  }) {
523
569
  const stripe = (0, import_react_stripe_js.useStripe)();
524
570
  const elements = (0, import_react_stripe_js.useElements)();
525
- const [ready, setReady] = (0, import_react6.useState)(false);
571
+ const [loadState, setLoadState] = (0, import_react6.useState)("loading");
526
572
  const [submitting, setSubmitting] = (0, import_react6.useState)(false);
527
573
  const paypalResumeAttempted = (0, import_react6.useRef)(false);
528
574
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
@@ -634,12 +680,11 @@ function PayPalButtonInner({
634
680
  }
635
681
  }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]);
636
682
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
637
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
683
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
638
684
  import_react_stripe_js.ExpressCheckoutElement,
639
685
  {
640
- onReady: () => setReady(true),
641
- onLoadError: () => {
642
- },
686
+ onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
687
+ onLoadError: () => setLoadState("unavailable"),
643
688
  onConfirm: handlePayPalConfirm,
644
689
  onCancel: () => {
645
690
  onDecline?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
@@ -671,7 +716,7 @@ function WalletButtonInner({
671
716
  }) {
672
717
  const stripe = (0, import_react_stripe_js.useStripe)();
673
718
  const elements = (0, import_react_stripe_js.useElements)();
674
- const [ready, setReady] = (0, import_react6.useState)(false);
719
+ const [loadState, setLoadState] = (0, import_react6.useState)("loading");
675
720
  const [submitting, setSubmitting] = (0, import_react6.useState)(false);
676
721
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
677
722
  const lastWalletMethodRef = (0, import_react6.useRef)("card");
@@ -737,12 +782,11 @@ function WalletButtonInner({
737
782
  [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]
738
783
  );
739
784
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
740
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
785
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
741
786
  import_react_stripe_js.ExpressCheckoutElement,
742
787
  {
743
- onReady: () => setReady(true),
744
- onLoadError: () => {
745
- },
788
+ onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"])),
789
+ onLoadError: () => setLoadState("unavailable"),
746
790
  onClick: (event) => {
747
791
  lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
748
792
  event.resolve();
@@ -786,6 +830,7 @@ function SplitCardFormInner({
786
830
  isProcessing: externalProcessing,
787
831
  error: externalError,
788
832
  onErrorChange,
833
+ onFullNameChange,
789
834
  onFirstNameChange,
790
835
  onLastNameChange,
791
836
  showPayPal = true,
@@ -904,10 +949,11 @@ function SplitCardFormInner({
904
949
  const showWallets = showApplePay || showGooglePay;
905
950
  const handleNameChange = (0, import_react6.useCallback)((value) => {
906
951
  setFullName(value);
952
+ onFullNameChange?.(value);
907
953
  const parts = value.trim().split(/\s+/);
908
954
  onFirstNameChange?.(parts[0] ?? "");
909
955
  onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
910
- }, [onFirstNameChange, onLastNameChange]);
956
+ }, [onFullNameChange, onFirstNameChange, onLastNameChange]);
911
957
  const runBeforeCardButtonClick = (0, import_react6.useCallback)(async () => {
912
958
  if (!onBeforeButtonClick) return true;
913
959
  try {
@@ -1669,6 +1715,9 @@ function FloPayCheckout({
1669
1715
  onComplete,
1670
1716
  onError,
1671
1717
  onDecline,
1718
+ onFullNameChange,
1719
+ onCountryChange,
1720
+ onZipChange,
1672
1721
  showPayPal = true,
1673
1722
  showApplePay = true,
1674
1723
  showGooglePay = true,
@@ -2267,6 +2316,7 @@ function FloPayCheckout({
2267
2316
  onComplete,
2268
2317
  onError,
2269
2318
  onDecline,
2319
+ onFullNameChange,
2270
2320
  showPayPal,
2271
2321
  showApplePay,
2272
2322
  showGooglePay,
@@ -2281,6 +2331,8 @@ function FloPayCheckout({
2281
2331
  enableAVS,
2282
2332
  avsLayout,
2283
2333
  country: session?.customer?.country,
2334
+ onCountryChange,
2335
+ onZipChange,
2284
2336
  submitLabel,
2285
2337
  className
2286
2338
  }