@flopay/react 0.2.1 → 0.3.1

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.d.cts CHANGED
@@ -86,6 +86,13 @@ interface FloPayCheckoutProps {
86
86
  * `method`: `'card'` | `'paypal'` | `'apple_pay'` | `'google_pay'`
87
87
  */
88
88
  onButtonClick?: (method: string) => void;
89
+ /**
90
+ * Enable AVS (Address Verification). Shows country dropdown + ZIP/postcode input
91
+ * in the card form. When enabled, billing_details are passed to Stripe for AVS checks.
92
+ */
93
+ enableAVS?: boolean;
94
+ /** Layout for AVS fields: 'row' (side-by-side, default) or 'column' (stacked). */
95
+ avsLayout?: 'row' | 'column';
89
96
  /** Label for the submit button. */
90
97
  submitLabel?: string;
91
98
  /** Additional CSS class for the wrapper. */
@@ -129,7 +136,7 @@ interface FloPayCheckoutProps {
129
136
  * />
130
137
  * ```
131
138
  */
132
- declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: createSessionParams, billingApiUrl, appearance, locale, fallbackPublishableKey, loading: loadingNode, error: errorNode, onComplete, onError, showPayPal, showApplePay, showGooglePay, layout, buttonsTheme, buttonsStyles, onButtonClick, submitLabel, className, children, checkoutMode: checkoutModeProp, confirmLabel, renderConfirmButton, onSessionCompleted, }: FloPayCheckoutProps): React.ReactElement;
139
+ declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: createSessionParams, billingApiUrl, appearance, locale, fallbackPublishableKey, loading: loadingNode, error: errorNode, onComplete, onError, showPayPal, showApplePay, showGooglePay, layout, buttonsTheme, buttonsStyles, onButtonClick, enableAVS, avsLayout, submitLabel, className, children, checkoutMode: checkoutModeProp, confirmLabel, renderConfirmButton, onSessionCompleted, }: FloPayCheckoutProps): React.ReactElement;
133
140
 
134
141
  /**
135
142
  * Returns the current `FloPay` instance, or `null` if the provider
@@ -374,6 +381,21 @@ interface SplitCardFormProps {
374
381
  * `method`: `'card'` | `'paypal'` | `'apple_pay'` | `'google_pay'`
375
382
  */
376
383
  onButtonClick?: (method: string) => void;
384
+ /**
385
+ * Enable AVS (Address Verification). Shows country dropdown + ZIP/postcode input.
386
+ * When enabled, billing_details are passed to Stripe's createPaymentMethod for AVS checks.
387
+ */
388
+ enableAVS?: boolean;
389
+ /** Layout for AVS fields: 'row' (side-by-side, default) or 'column' (stacked). */
390
+ avsLayout?: 'row' | 'column';
391
+ /** Pre-filled country code (ISO 3166-1 alpha-2) for AVS. */
392
+ country?: string;
393
+ /** Pre-filled ZIP/postal code for AVS. */
394
+ zip?: string;
395
+ /** Callback when AVS country changes. */
396
+ onCountryChange?: (country: string) => void;
397
+ /** Callback when AVS ZIP/postal code changes. */
398
+ onZipChange?: (zip: string) => void;
377
399
  /** Total amount in cents (smallest currency unit). Used for wallet/PayPal Elements config. */
378
400
  totalAmount?: number;
379
401
  /** Currency code (used for PayPal Elements config). */
package/dist/index.d.ts CHANGED
@@ -86,6 +86,13 @@ interface FloPayCheckoutProps {
86
86
  * `method`: `'card'` | `'paypal'` | `'apple_pay'` | `'google_pay'`
87
87
  */
88
88
  onButtonClick?: (method: string) => void;
89
+ /**
90
+ * Enable AVS (Address Verification). Shows country dropdown + ZIP/postcode input
91
+ * in the card form. When enabled, billing_details are passed to Stripe for AVS checks.
92
+ */
93
+ enableAVS?: boolean;
94
+ /** Layout for AVS fields: 'row' (side-by-side, default) or 'column' (stacked). */
95
+ avsLayout?: 'row' | 'column';
89
96
  /** Label for the submit button. */
90
97
  submitLabel?: string;
91
98
  /** Additional CSS class for the wrapper. */
@@ -129,7 +136,7 @@ interface FloPayCheckoutProps {
129
136
  * />
130
137
  * ```
131
138
  */
132
- declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: createSessionParams, billingApiUrl, appearance, locale, fallbackPublishableKey, loading: loadingNode, error: errorNode, onComplete, onError, showPayPal, showApplePay, showGooglePay, layout, buttonsTheme, buttonsStyles, onButtonClick, submitLabel, className, children, checkoutMode: checkoutModeProp, confirmLabel, renderConfirmButton, onSessionCompleted, }: FloPayCheckoutProps): React.ReactElement;
139
+ declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: createSessionParams, billingApiUrl, appearance, locale, fallbackPublishableKey, loading: loadingNode, error: errorNode, onComplete, onError, showPayPal, showApplePay, showGooglePay, layout, buttonsTheme, buttonsStyles, onButtonClick, enableAVS, avsLayout, submitLabel, className, children, checkoutMode: checkoutModeProp, confirmLabel, renderConfirmButton, onSessionCompleted, }: FloPayCheckoutProps): React.ReactElement;
133
140
 
134
141
  /**
135
142
  * Returns the current `FloPay` instance, or `null` if the provider
@@ -374,6 +381,21 @@ interface SplitCardFormProps {
374
381
  * `method`: `'card'` | `'paypal'` | `'apple_pay'` | `'google_pay'`
375
382
  */
376
383
  onButtonClick?: (method: string) => void;
384
+ /**
385
+ * Enable AVS (Address Verification). Shows country dropdown + ZIP/postcode input.
386
+ * When enabled, billing_details are passed to Stripe's createPaymentMethod for AVS checks.
387
+ */
388
+ enableAVS?: boolean;
389
+ /** Layout for AVS fields: 'row' (side-by-side, default) or 'column' (stacked). */
390
+ avsLayout?: 'row' | 'column';
391
+ /** Pre-filled country code (ISO 3166-1 alpha-2) for AVS. */
392
+ country?: string;
393
+ /** Pre-filled ZIP/postal code for AVS. */
394
+ zip?: string;
395
+ /** Callback when AVS country changes. */
396
+ onCountryChange?: (country: string) => void;
397
+ /** Callback when AVS ZIP/postal code changes. */
398
+ onZipChange?: (zip: string) => void;
377
399
  /** Total amount in cents (smallest currency unit). Used for wallet/PayPal Elements config. */
378
400
  totalAmount?: number;
379
401
  /** Currency code (used for PayPal Elements config). */
package/dist/index.mjs CHANGED
@@ -138,7 +138,7 @@ import {
138
138
  useElements as useStripeElements,
139
139
  useStripe as useStripeRaw
140
140
  } from "@stripe/react-stripe-js";
141
- import { resolveButtonsLayoutTheme } from "@flopay/shared";
141
+ import { resolveButtonsLayoutTheme, getPostalCodeLabel, COUNTRY_OPTIONS } from "@flopay/shared";
142
142
  import { forwardRef, useCallback, useEffect as useEffect3, useImperativeHandle, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
143
143
 
144
144
  // src/hooks.ts
@@ -542,6 +542,12 @@ function SplitCardFormInner({
542
542
  buttonsTheme,
543
543
  buttonsStyles: buttonsStylesOverride,
544
544
  onButtonClick,
545
+ enableAVS = false,
546
+ avsLayout: avsLayoutProp = "row",
547
+ country: countryProp,
548
+ zip: zipProp,
549
+ onCountryChange,
550
+ onZipChange,
545
551
  totalAmount = 0,
546
552
  currency = "usd",
547
553
  innerRef
@@ -552,6 +558,10 @@ function SplitCardFormInner({
552
558
  const [processing, setProcessing] = useState2(false);
553
559
  const [error, setError] = useState2(null);
554
560
  const [is3DSActive, setIs3DSActive] = useState2(false);
561
+ const [selectedCountry, setSelectedCountry] = useState2(countryProp ?? "US");
562
+ const [zipCode, setZipCode] = useState2(zipProp ?? "");
563
+ const zipCodeRef = useRef2(zipProp ?? "");
564
+ const selectedCountryRef = useRef2(countryProp ?? "US");
555
565
  const [viewState, setViewState] = useState2("buttons");
556
566
  const showCardForm = viewState === "expanding" || viewState === "card";
557
567
  const TRANSITION_MS = 280;
@@ -639,7 +649,8 @@ function SplitCardFormInner({
639
649
  userId: userId ?? "",
640
650
  email: email ?? "",
641
651
  firstName: firstName ?? fullName.trim().split(/\s+/)[0] ?? "",
642
- lastName: lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? ""
652
+ lastName: lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? "",
653
+ ...enableAVS ? { zip: zipCodeRef.current, country: selectedCountryRef.current } : {}
643
654
  },
644
655
  chv
645
656
  })
@@ -800,13 +811,24 @@ function SplitCardFormInner({
800
811
  updateError(null);
801
812
  let handedOff = false;
802
813
  try {
814
+ if (enableAVS && !zipCodeRef.current.trim()) {
815
+ updateError(getPostalCodeLabel(selectedCountryRef.current) + " is required");
816
+ return;
817
+ }
803
818
  const submitResult = await flopay.submitElements();
804
819
  if (submitResult.error) {
805
820
  updateError(submitResult.error.message);
806
821
  onError?.(submitResult.error);
807
822
  return;
808
823
  }
809
- const pmResult = await flopay.createPaymentMethod();
824
+ const billingDetails = enableAVS ? {
825
+ name: fullName,
826
+ address: {
827
+ country: selectedCountryRef.current,
828
+ postal_code: zipCodeRef.current
829
+ }
830
+ } : void 0;
831
+ const pmResult = await flopay.createPaymentMethod(billingDetails);
810
832
  if (pmResult.error || !pmResult.paymentMethodId) {
811
833
  updateError(pmResult.error?.message ?? "Failed to create payment method.");
812
834
  return;
@@ -988,6 +1010,83 @@ function SplitCardFormInner({
988
1010
  }
989
1011
  }
990
1012
  ) }),
1013
+ enableAVS && /* @__PURE__ */ jsxs("div", { style: {
1014
+ display: "flex",
1015
+ flexDirection: avsLayoutProp === "column" ? "column" : "row",
1016
+ gap: avsLayoutProp === "column" ? "0.5rem" : "0",
1017
+ marginTop: "0.5rem"
1018
+ }, children: [
1019
+ /* @__PURE__ */ jsx3("div", { style: {
1020
+ flex: avsLayoutProp === "row" ? 1 : void 0,
1021
+ backgroundColor: cardInputBg,
1022
+ border: `1px solid ${resolvedBorder}`,
1023
+ padding: "10px",
1024
+ ...avsLayoutProp === "row" ? { borderRadius: "0", borderTopLeftRadius: "8px", borderBottomLeftRadius: "8px", borderRight: "none" } : { borderRadius: "8px" },
1025
+ ...isButtons && bStyles.countrySelect ? bStyles.countrySelect : {}
1026
+ }, children: /* @__PURE__ */ jsx3(
1027
+ "select",
1028
+ {
1029
+ value: selectedCountry,
1030
+ onChange: (e) => {
1031
+ selectedCountryRef.current = e.target.value;
1032
+ setSelectedCountry(e.target.value);
1033
+ onCountryChange?.(e.target.value);
1034
+ },
1035
+ disabled: isSubmitting,
1036
+ autoComplete: "country",
1037
+ "data-testid": "flopay-country",
1038
+ style: {
1039
+ width: "100%",
1040
+ border: "none",
1041
+ outline: "none",
1042
+ background: "transparent",
1043
+ fontSize: bStyles.cardInputFontSize ?? "16px",
1044
+ fontFamily: "Poppins, sans-serif",
1045
+ color: bStyles.cardInputColor ?? "#262833",
1046
+ cursor: "pointer",
1047
+ ...isButtons && bStyles.nameInput ? bStyles.nameInput : {}
1048
+ },
1049
+ children: COUNTRY_OPTIONS.map((c) => /* @__PURE__ */ jsxs("option", { value: c.code, children: [
1050
+ c.flag,
1051
+ " ",
1052
+ c.name
1053
+ ] }, c.code))
1054
+ }
1055
+ ) }),
1056
+ /* @__PURE__ */ jsx3("div", { style: {
1057
+ flex: avsLayoutProp === "row" ? 1 : void 0,
1058
+ backgroundColor: cardInputBg,
1059
+ border: `1px solid ${resolvedBorder}`,
1060
+ padding: "10px",
1061
+ ...avsLayoutProp === "row" ? { borderRadius: "0", borderTopRightRadius: "8px", borderBottomRightRadius: "8px" } : { borderRadius: "8px" },
1062
+ ...isButtons && bStyles.zipInput ? bStyles.zipInput : {}
1063
+ }, children: /* @__PURE__ */ jsx3(
1064
+ "input",
1065
+ {
1066
+ placeholder: getPostalCodeLabel(selectedCountry),
1067
+ autoComplete: "postal-code",
1068
+ value: zipCode,
1069
+ onChange: (e) => {
1070
+ zipCodeRef.current = e.target.value;
1071
+ setZipCode(e.target.value);
1072
+ onZipChange?.(e.target.value);
1073
+ },
1074
+ disabled: isSubmitting,
1075
+ required: true,
1076
+ "data-testid": "flopay-zip",
1077
+ style: {
1078
+ width: "100%",
1079
+ border: "none",
1080
+ outline: "none",
1081
+ background: "transparent",
1082
+ fontSize: bStyles.cardInputFontSize ?? "16px",
1083
+ fontFamily: "Poppins, sans-serif",
1084
+ color: bStyles.cardInputColor ?? "#262833",
1085
+ ...isButtons && bStyles.nameInput ? bStyles.nameInput : {}
1086
+ }
1087
+ }
1088
+ ) })
1089
+ ] }),
991
1090
  displayError && /* @__PURE__ */ jsxs("div", { role: "alert", "data-testid": "flopay-error", style: {
992
1091
  margin: "0.75rem 0",
993
1092
  padding: "0.625rem 0.875rem",
@@ -1213,6 +1312,8 @@ function FloPayCheckout({
1213
1312
  buttonsTheme,
1214
1313
  buttonsStyles,
1215
1314
  onButtonClick,
1315
+ enableAVS,
1316
+ avsLayout,
1216
1317
  submitLabel,
1217
1318
  className,
1218
1319
  children,
@@ -1754,6 +1855,10 @@ function FloPayCheckout({
1754
1855
  buttonsTheme,
1755
1856
  buttonsStyles,
1756
1857
  onButtonClick,
1858
+ enableAVS,
1859
+ avsLayout,
1860
+ country: session?.customer?.country,
1861
+ zip: session?.customer?.zip,
1757
1862
  submitLabel,
1758
1863
  className
1759
1864
  }