diff --git a/packages/core/src/app/shipping/PayPalFastlaneShippingAddress.test.tsx b/packages/core/src/app/shipping/PayPalFastlaneShippingAddress.test.tsx
new file mode 100644
index 0000000000..b186a879c9
--- /dev/null
+++ b/packages/core/src/app/shipping/PayPalFastlaneShippingAddress.test.tsx
@@ -0,0 +1,160 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import {getAddress, getCustomer} from '@bigcommerce/checkout/test-mocks';
+import {CheckoutSelectors, CheckoutService, createCheckoutService} from '@bigcommerce/checkout-sdk';
+import { PayPalFastlaneShippingAddress, PayPalFastlaneShippingAddressProps } from './PayPalFastlaneShippingAddress';
+import { createLocaleContext, LocaleContext, LocaleContextType } from '@bigcommerce/checkout/locale';
+import { CheckoutContext } from '@bigcommerce/checkout/payment-integration-api';
+import { getStoreConfig } from '../config/config.mock';
+import { usePayPalFastlaneAddress } from '@bigcommerce/checkout/paypal-fastlane-integration';
+import { noop } from 'lodash';
+import { Formik } from 'formik';
+
+jest.mock('@bigcommerce/checkout/paypal-fastlane-integration', () => ({
+ ...jest.requireActual('@bigcommerce/checkout/paypal-fastlane-integration'),
+ usePayPalFastlaneAddress: jest.fn(() => ({
+ isPayPalFastlaneEnabled: false,
+ paypalFastlaneAddresses: [],
+ })),
+}));
+
+describe('PayPalFastlaneShippingAddress', () => {
+ let component;
+ let defaultProps: PayPalFastlaneShippingAddressProps;
+ let checkoutService: CheckoutService;
+ let checkoutState: CheckoutSelectors;
+ let localeContext: LocaleContextType;
+
+ beforeEach(() => {
+ localeContext = createLocaleContext(getStoreConfig());
+ checkoutService = createCheckoutService();
+ checkoutState = checkoutService.getState();
+
+ const paypalFastlaneAddresses = [{
+ ...getAddress(),
+ address1: 'PP Fastlane address'
+ }];
+
+ (usePayPalFastlaneAddress as jest.Mock).mockReturnValue({
+ isPayPalFastlaneEnabled: true,
+ paypalFastlaneAddresses,
+ shouldShowPayPalFastlaneShippingForm: true,
+ });
+
+ defaultProps = {
+ consignments:[],
+ countriesWithAutocomplete: [],
+ handleFieldChange: jest.fn(),
+ isShippingStepPending: false,
+ hasRequestedShippingOptions: false,
+ onUseNewAddress: jest.fn(),
+ addresses: getCustomer().addresses,
+ shippingAddress: getCustomer().addresses[0],
+ formFields: [
+ {
+ custom: false,
+ default: 'NO PO BOX',
+ id: 'field_18',
+ label: 'Address Line 1',
+ name: 'address1',
+ required: true,
+ },
+ {
+ custom: true,
+ default: '',
+ id: 'field_19',
+ label: 'Address Line 2',
+ name: 'address2',
+ required: false,
+ },
+ ],
+ isLoading: false,
+ methodId: 'paypalcommerceacceleratedcheckout',
+ deinitialize: jest.fn(),
+ initialize: jest.fn(),
+ onAddressSelect: jest.fn(),
+ onFieldChange: jest.fn(),
+ onUnhandledError: jest.fn(),
+ countries: [
+ {
+ code: 'US',
+ name: 'United States',
+ hasPostalCodes: true,
+ requiresState: true,
+ subdivisions: [
+ { code: 'CA', name: 'California' },
+ { code: 'TX', name: 'Texas' },
+ ],
+ }
+ ],
+ };
+ })
+
+ it('renders PayPalFastlaneShippingAddress edit button', async () => {
+ component = render(
+
+
+
+ );
+
+
+
+ );
+
+ const fastlaneEditButton = await screen.findByTestId('step-edit-button');
+
+ expect(fastlaneEditButton).toBeInTheDocument();
+ });
+
+ it('initializes fastlane shipping strategy', async () => {
+ const initializeMock = jest.fn();
+
+ component = render(
+
+
+
+ );
+
+
+
+ );
+
+ expect(initializeMock).toHaveBeenCalled();
+ });
+
+ it('renders regular shipping form if shouldShowPayPalFastlaneShippingForm false', async () => {
+ const paypalFastlaneAddresses = [{
+ ...getAddress(),
+ address1: 'PP Fastlane address'
+ }];
+ (usePayPalFastlaneAddress as jest.Mock).mockReturnValue({
+ isPayPalFastlaneEnabled: true,
+ paypalFastlaneAddresses,
+ shouldShowPayPalFastlaneShippingForm: false,
+ });
+
+ component = render(
+
+
+
+ );
+
+
+
+ );
+
+ try {
+ await screen.findByTestId('step-edit-button');
+ } catch (error) {
+ expect(error).toBeDefined();
+ }
+
+ const countryText = await screen.findByText('United States');
+ const stateText = await screen.findByText('California,');
+ const streetText = await screen.findByText('12345 Testing Way');
+
+ expect(countryText).toBeInTheDocument();
+ expect(streetText).toBeInTheDocument();
+ expect(stateText).toBeInTheDocument();
+ });
+});
diff --git a/packages/core/src/app/shipping/PayPalFastlaneShippingAddress.tsx b/packages/core/src/app/shipping/PayPalFastlaneShippingAddress.tsx
index 3d058782c8..b7ef33a8a0 100644
--- a/packages/core/src/app/shipping/PayPalFastlaneShippingAddress.tsx
+++ b/packages/core/src/app/shipping/PayPalFastlaneShippingAddress.tsx
@@ -1,13 +1,41 @@
-import { Address } from '@bigcommerce/checkout-sdk';
-import React, { FC } from 'react';
+import {
+ Address,
+ Consignment,
+ Country,
+ CustomerAddress,
+ FormField,
+ ShippingInitializeOptions
+} from '@bigcommerce/checkout-sdk';
+import React, { FC, useEffect, useRef } from 'react';
+import hasSelectedShippingOptions from './hasSelectedShippingOptions';
-import { PayPalFastlaneShippingAddressForm } from '@bigcommerce/checkout/paypal-fastlane-integration';
+import {
+ isPayPalCommerceFastlaneMethod,
+ isPayPalFastlaneMethod,
+ PayPalFastlaneShippingAddressForm,
+ usePayPalFastlaneAddress,
+} from '@bigcommerce/checkout/paypal-fastlane-integration';
import { ShippingAddressProps } from './ShippingAddress';
-interface PayPalFastlaneShippingAddressProps extends ShippingAddressProps {
- methodId: string,
- shippingAddress: Address,
+import ShippingAddressForm from './ShippingAddressForm';
+import { LoadingOverlay } from '../ui/loading';
+
+export interface PayPalFastlaneShippingAddressProps extends ShippingAddressProps {
+ methodId?: string,
+ shippingAddress?: Address,
+ isGuest?: boolean,
+ consignments: Consignment[];
+ countries?: Country[];
+ countriesWithAutocomplete: string[];
+ formFields: FormField[],
+ googleMapsApiKey?: string;
+ handleFieldChange(fieldName: string, value: string): void,
+ onAddressSelect(address: Address): void;
+}
+
+interface PayPalFastlaneAddressComponentRef {
+ showAddressSelector?: () => Promise;
}
export const PayPalFastlaneShippingAddress: FC = (props) => {
@@ -22,20 +50,110 @@ export const PayPalFastlaneShippingAddress: FC({});
+ const paypalCommerceFastlaneOptions = {
+ paypalcommercefastlane: {
+ onPayPalFastlaneAddressChange: (
+ showPayPalFastlaneAddressSelector: PayPalFastlaneAddressComponentRef['showAddressSelector'],
+ ) => {
+ paypalFastlaneShippingComponent.current.showAddressSelector =
+ showPayPalFastlaneAddressSelector;
+ },
+ },
+ };
- return (
-
+ const braintreeFastlaneOptions = {
+ braintreefastlane: {
+ onPayPalFastlaneAddressChange: (
+ showPayPalFastlaneAddressSelector: PayPalFastlaneAddressComponentRef['showAddressSelector'],
+ ) => {
+ paypalFastlaneShippingComponent.current.showAddressSelector =
+ showPayPalFastlaneAddressSelector;
+ },
+ },
+ };
+
+ const initializationOptions: ShippingInitializeOptions = isPayPalCommerceFastlaneMethod(
+ methodId,
)
+ ? paypalCommerceFastlaneOptions
+ : braintreeFastlaneOptions;
+
+ const initializeShippingStrategyOrThrow = async () => {
+ try {
+ await initialize({
+ methodId,
+ ...initializationOptions,
+ });
+ } catch (error) {
+ if (typeof onUnhandledError === 'function' && error instanceof Error) {
+ onUnhandledError(error);
+ }
+ }
+ };
+
+ const deinitializeShippingStrategyOrThrow = async () => {
+ try {
+ await deinitialize({ methodId });
+ } catch (error) {
+ if (typeof onUnhandledError === 'function' && error instanceof Error) {
+ onUnhandledError(error);
+ }
+ }
+ };
+
+ useEffect(() => {
+ void initializeShippingStrategyOrThrow();
+
+ return () => {
+ void deinitializeShippingStrategyOrThrow();
+ };
+ }, []);
+
+ const { isPayPalFastlaneEnabled, paypalFastlaneAddresses, shouldShowPayPalFastlaneShippingForm } = usePayPalFastlaneAddress();
+
+ const shippingAddresses = isPayPalFastlaneEnabled && isGuest
+ ? paypalFastlaneAddresses
+ : addresses;
+
+ return (
+
+ {methodId && isPayPalFastlaneMethod(methodId) && shippingAddress && shouldShowPayPalFastlaneShippingForm ? (
+
+ ) : (
+
+ )}
+
+ );
};
diff --git a/packages/core/src/app/shipping/ShippingAddress.spec.tsx b/packages/core/src/app/shipping/ShippingAddress.spec.tsx
index d7bae8e983..d32cfebde7 100644
--- a/packages/core/src/app/shipping/ShippingAddress.spec.tsx
+++ b/packages/core/src/app/shipping/ShippingAddress.spec.tsx
@@ -1,5 +1,5 @@
import { CheckoutService, createCheckoutService } from '@bigcommerce/checkout-sdk';
-import { mount, ReactWrapper, shallow } from 'enzyme';
+import { mount, ReactWrapper } from 'enzyme';
import { Formik } from 'formik';
import { noop } from 'lodash';
import React, { FunctionComponent } from 'react';
@@ -116,5 +116,19 @@ describe('ShippingAddress Component', () => {
expect(component.find(StaticAddressEditable)).toHaveLength(1);
});
+
+ it('calls initialize function when fastlane enabled and shouldShowPayPalFastlaneShippingForm false', () => {
+ const initializeMock = jest.fn();
+ const shippingFormProps = {
+ ...defaultProps,
+ initialize: initializeMock,
+ };
+
+ mount(
+ ,
+ );
+
+ expect(initializeMock).toHaveBeenCalled();
+ });
});
});
diff --git a/packages/core/src/app/shipping/ShippingAddress.tsx b/packages/core/src/app/shipping/ShippingAddress.tsx
index 2733767eec..348b9c9d83 100644
--- a/packages/core/src/app/shipping/ShippingAddress.tsx
+++ b/packages/core/src/app/shipping/ShippingAddress.tsx
@@ -10,12 +10,12 @@ import {
} from '@bigcommerce/checkout-sdk';
import React, { FunctionComponent, memo, useContext } from 'react';
-import { isPayPalFastlaneMethod, usePayPalFastlaneAddress } from '@bigcommerce/checkout/paypal-fastlane-integration';
import { FormContext } from '@bigcommerce/checkout/ui';
import { AmazonPayShippingAddress } from './AmazonPayShippingAddress';
import { PayPalFastlaneShippingAddress } from './PayPalFastlaneShippingAddress';
-import ShippingAddressForm from './ShippingAddressForm';
+import { isPayPalFastlaneMethod } from '@bigcommerce/checkout/paypal-fastlane-integration';
+import ShippingAddressForm from "./ShippingAddressForm";
export interface ShippingAddressProps {
addresses: CustomerAddress[];
@@ -24,6 +24,7 @@ export interface ShippingAddressProps {
countriesWithAutocomplete: string[];
formFields: FormField[];
googleMapsApiKey?: string;
+ isGuest?: boolean;
isLoading: boolean;
isShippingStepPending: boolean;
methodId?: string;
@@ -56,9 +57,9 @@ const ShippingAddress: FunctionComponent = (props) => {
addresses,
shouldShowSaveAddress,
isFloatingLabelEnabled,
+ isGuest,
} = props;
- const { shouldShowPayPalFastlaneShippingForm } = usePayPalFastlaneAddress();
const { setSubmitted } = useContext(FormContext);
const handleFieldChange: (fieldName: string, value: string) => void = (fieldName, value) => {
@@ -69,42 +70,42 @@ const ShippingAddress: FunctionComponent = (props) => {
onFieldChange(fieldName, value);
};
- if (methodId === 'amazonpay' && shippingAddress) {
+ if (methodId && isPayPalFastlaneMethod(methodId) && shippingAddress) {
return (
-
- );
+ )
}
- if (methodId && isPayPalFastlaneMethod(methodId) && shippingAddress && shouldShowPayPalFastlaneShippingForm) {
+ if (methodId === 'amazonpay' && shippingAddress) {
return (
-
- )
+ );
}
- return (
-
- );
+ return
};
export default memo(ShippingAddress);
diff --git a/packages/core/src/app/shipping/ShippingForm.spec.tsx b/packages/core/src/app/shipping/ShippingForm.spec.tsx
index 97e0170117..8bc6eecd91 100644
--- a/packages/core/src/app/shipping/ShippingForm.spec.tsx
+++ b/packages/core/src/app/shipping/ShippingForm.spec.tsx
@@ -393,7 +393,7 @@ describe('ShippingForm Component', () => {
-
+
,
diff --git a/packages/core/src/app/shipping/ShippingForm.tsx b/packages/core/src/app/shipping/ShippingForm.tsx
index b72c37ebfd..7bde4c516d 100644
--- a/packages/core/src/app/shipping/ShippingForm.tsx
+++ b/packages/core/src/app/shipping/ShippingForm.tsx
@@ -17,12 +17,12 @@ import {
import React from 'react';
import { withLanguage, WithLanguageProps } from '@bigcommerce/checkout/locale';
-import { usePayPalFastlaneAddress } from '@bigcommerce/checkout/paypal-fastlane-integration';
import MultiShippingForm, { MultiShippingFormValues } from './MultiShippingForm';
import MultiShippingFormV2 from './MultiShippingFormV2';
import MultiShippingGuestForm from './MultiShippingGuestForm';
import SingleShippingForm, { SingleShippingFormValues } from './SingleShippingForm';
+import { usePayPalFastlaneAddress } from '@bigcommerce/checkout/paypal-fastlane-integration';
export interface ShippingFormProps {
addresses: CustomerAddress[];
@@ -153,6 +153,7 @@ const ShippingForm = ({
getMultiShippingForm()
) : (