From d231cc1ab7289e92751ab71a461bfbf7aa68e65f Mon Sep 17 00:00:00 2001 From: Luis Sanchez Date: Mon, 25 May 2020 16:43:17 +1000 Subject: [PATCH] feat(common): CHECKOUT-4642 Expose Save Address checkbox --- package-lock.json | 6 +- package.json | 2 +- src/app/address/AddressForm.spec.tsx | 7 ++ src/app/address/AddressForm.tsx | 78 +++++++++++-------- src/app/address/isEqualAddress.spec.ts | 1 + src/app/address/isEqualAddress.ts | 2 +- .../address/mapAddressFromFormValues.spec.ts | 3 +- src/app/address/mapAddressFromFormValues.ts | 2 + src/app/address/mapAddressToFormValues.ts | 8 +- src/app/billing/Billing.spec.tsx | 1 + src/app/billing/Billing.tsx | 2 + src/app/billing/BillingForm.spec.tsx | 2 + src/app/billing/BillingForm.tsx | 5 +- src/app/locale/translations/en.json | 4 +- src/app/shipping/Shipping.tsx | 4 + src/app/shipping/ShippingAddress.tsx | 3 + src/app/shipping/ShippingAddressForm.tsx | 3 + src/app/shipping/ShippingForm.tsx | 3 + src/app/shipping/SingleShippingForm.tsx | 3 + src/app/shipping/shipping-addresses.mock.ts | 1 + 20 files changed, 95 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index d07a9b5937..2e5bec3d38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1595,9 +1595,9 @@ } }, "@bigcommerce/checkout-sdk": { - "version": "1.71.0", - "resolved": "https://registry.npmjs.org/@bigcommerce/checkout-sdk/-/checkout-sdk-1.71.0.tgz", - "integrity": "sha512-u0cbASrqbIRvGZ489lGO9zuojAd3TN8uNov8a+z9stxxX7QvOZ1MJj9I81J847vWMDc8Ki++J4MrYXvCvF25iw==", + "version": "1.72.0", + "resolved": "https://registry.npmjs.org/@bigcommerce/checkout-sdk/-/checkout-sdk-1.72.0.tgz", + "integrity": "sha512-8u4w+9Dw9lldhxL3nBvGOvZRWp8OuVwe/rfxqQ9+MlhMn6djqevktdOElty4cCttmPqtplmqYQFLSNAOJFtTYw==", "requires": { "@babel/polyfill": "^7.4.4", "@bigcommerce/bigpay-client": "^5.7.0", diff --git a/package.json b/package.json index 5603b848ca..97f019ac7f 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/bigcommerce/checkout-js#readme", "dependencies": { - "@bigcommerce/checkout-sdk": "^1.71.0", + "@bigcommerce/checkout-sdk": "^1.72.0", "@bigcommerce/citadel": "^2.15.1", "@bigcommerce/form-poster": "^1.2.2", "@bigcommerce/memoize": "^1.0.0", diff --git a/src/app/address/AddressForm.spec.tsx b/src/app/address/AddressForm.spec.tsx index 1d8c73f753..75754c789c 100644 --- a/src/app/address/AddressForm.spec.tsx +++ b/src/app/address/AddressForm.spec.tsx @@ -42,6 +42,9 @@ describe('AddressForm Component', () => { ); + expect(component.find('[name="address.shouldSaveAddress"]').exists()) + .toEqual(false); + expect(component.find(AddressFormField).length).toEqual(formFields.length); }); @@ -55,6 +58,7 @@ describe('AddressForm Component', () => { @@ -67,6 +71,9 @@ describe('AddressForm Component', () => { }) ); + expect(component.find('[name="address.shouldSaveAddress"]').exists()) + .toEqual(true); + expect(component.find(AddressFormField).at(0).prop('field')).toEqual( expect.objectContaining({ id: 'field_14', diff --git a/src/app/address/AddressForm.tsx b/src/app/address/AddressForm.tsx index 452874889c..d0211f96b7 100644 --- a/src/app/address/AddressForm.tsx +++ b/src/app/address/AddressForm.tsx @@ -3,8 +3,9 @@ import { memoize } from '@bigcommerce/memoize'; import { forIn, noop } from 'lodash'; import React, { createRef, Component, ReactNode, RefObject } from 'react'; -import { withLanguage, WithLanguageProps } from '../locale'; +import { withLanguage, TranslatedString, WithLanguageProps } from '../locale'; import { AutocompleteItem } from '../ui/autocomplete'; +import { CheckboxFormField, Fieldset } from '../ui/form'; import { mapToAddress, GoogleAutocompleteFormField } from './googleAutocomplete'; import './AddressForm.scss'; @@ -19,6 +20,7 @@ export interface AddressFormProps { countries?: Country[]; formFields: FormField[]; googleMapsApiKey?: string; + shouldShowSaveAddress?: boolean; onAutocompleteSelect?(address: Partial
): void; onAutocompleteToggle?(state: { inputValue: string; isOpen: boolean }): void; onChange?(fieldName: string, value: string | string[]): void; @@ -58,46 +60,54 @@ class AddressForm extends Component { countryCode, googleMapsApiKey, onAutocompleteToggle, + shouldShowSaveAddress, } = this.props; - return ( -
}> - { formFields.map(field => { - const addressFieldName = field.name; - const translatedPlaceholderId = PLACEHOLDER[addressFieldName]; + return (<> +
+
}> + { formFields.map(field => { + const addressFieldName = field.name; + const translatedPlaceholderId = PLACEHOLDER[addressFieldName]; + + if (addressFieldName === 'address1' && googleMapsApiKey && countriesWithAutocomplete) { + return ( + + ); + } - if (addressFieldName === 'address1' && googleMapsApiKey && countriesWithAutocomplete) { return ( - ); - } - - return ( - - ); - }) } -
- ); + }) } +
+ + { shouldShowSaveAddress && + } + name={ fieldName ? `${fieldName}.shouldSaveAddress` : 'shouldSaveAddress' } + /> } + ); } private handleAutocompleteChange: (value: string, isOpen: boolean) => void = (value, isOpen) => { diff --git a/src/app/address/isEqualAddress.spec.ts b/src/app/address/isEqualAddress.spec.ts index e8d89d2545..04a51e882f 100644 --- a/src/app/address/isEqualAddress.spec.ts +++ b/src/app/address/isEqualAddress.spec.ts @@ -11,6 +11,7 @@ describe('isEqualAddress', () => { stateOrProvinceCode: 'w', id: 'x', email: 'y', + shouldSaveAddress: false, type: 'z', })).toBeTruthy(); }); diff --git a/src/app/address/isEqualAddress.ts b/src/app/address/isEqualAddress.ts index 8ba04dff17..f09ca170ad 100644 --- a/src/app/address/isEqualAddress.ts +++ b/src/app/address/isEqualAddress.ts @@ -16,7 +16,7 @@ export default function isEqualAddress(address1?: ComparableAddress, address2?: } function normalizeAddress(address: ComparableAddress) { - const ignoredFields: ComparableAddressFields[] = ['id', 'stateOrProvinceCode', 'type', 'email']; + const ignoredFields: ComparableAddressFields[] = ['id', 'shouldSaveAddress', 'stateOrProvinceCode', 'type', 'email']; return omit( { diff --git a/src/app/address/mapAddressFromFormValues.spec.ts b/src/app/address/mapAddressFromFormValues.spec.ts index e928dcba21..6f55ea05e6 100644 --- a/src/app/address/mapAddressFromFormValues.spec.ts +++ b/src/app/address/mapAddressFromFormValues.spec.ts @@ -12,7 +12,8 @@ describe('mapAddressFromFormValues', () => { customFields: {}, }; - expect(mapAddressFromFormValues(formValues)).toMatchObject(getShippingAddress()); + expect(mapAddressFromFormValues(formValues)) + .toMatchObject(getShippingAddress()); }); it('converts formats date values to YYYY-MM-DD format', () => { diff --git a/src/app/address/mapAddressFromFormValues.ts b/src/app/address/mapAddressFromFormValues.ts index 60de99a1d2..4d38c64186 100644 --- a/src/app/address/mapAddressFromFormValues.ts +++ b/src/app/address/mapAddressFromFormValues.ts @@ -5,6 +5,7 @@ import { AddressFormValues } from './mapAddressToFormValues'; export default function mapAddressFromFormValues(formValues: AddressFormValues): Address { const { customFields: customFieldsObject, ...address } = formValues; + const shouldSaveAddress = formValues.shouldSaveAddress; const customFields: Array<{fieldId: string; fieldValue: string}> = []; forIn(customFieldsObject, (value, key) => { @@ -26,6 +27,7 @@ export default function mapAddressFromFormValues(formValues: AddressFormValues): return { ...address, + shouldSaveAddress, customFields, }; } diff --git a/src/app/address/mapAddressToFormValues.ts b/src/app/address/mapAddressToFormValues.ts index 055851d195..f7e321e649 100644 --- a/src/app/address/mapAddressToFormValues.ts +++ b/src/app/address/mapAddressToFormValues.ts @@ -36,6 +36,10 @@ export default function mapAddressToFormValues(fields: FormField[], address?: Ad ), }); + values.shouldSaveAddress = address && address.shouldSaveAddress !== undefined ? + address.shouldSaveAddress : + true; + // Manually backfill stateOrProvince to avoid Formik warning (uncontrolled to controlled input) if (values.stateOrProvince === undefined) { values.stateOrProvince = ''; @@ -72,6 +76,6 @@ function getDefaultValue(fieldType?: string, defaultValue?: string): string | st return defaultValue || ''; } -function isSystemAddressFieldName(fieldName: string): fieldName is Exclude { - return fieldName !== 'customFields'; +function isSystemAddressFieldName(fieldName: string): fieldName is Exclude { + return fieldName !== 'customFields' && fieldName !== 'shouldSaveAddress'; } diff --git a/src/app/billing/Billing.spec.tsx b/src/app/billing/Billing.spec.tsx index 581c90e39a..f550682f4e 100644 --- a/src/app/billing/Billing.spec.tsx +++ b/src/app/billing/Billing.spec.tsx @@ -168,6 +168,7 @@ describe('Billing Component', () => { stateOrProvinceCode: '', firstName: 'foo', lastName: 'Tester', + shouldSaveAddress: true, }); expect(defaultProps.navigateNextStep).toHaveBeenCalled(); diff --git a/src/app/billing/Billing.tsx b/src/app/billing/Billing.tsx index 56e886560f..248172d437 100644 --- a/src/app/billing/Billing.tsx +++ b/src/app/billing/Billing.tsx @@ -27,6 +27,7 @@ export interface WithCheckoutBillingProps { googleMapsApiKey: string; isInitializing: boolean; isUpdating: boolean; + hasSaveAddressFeature: boolean; shouldShowOrderComments: boolean; getFields(countryCode?: string): FormField[]; initialize(): Promise; @@ -166,6 +167,7 @@ function mapToBillingProps({ initialize: checkoutService.loadBillingAddressFields, isInitializing: isLoadingBillingCountries(), isUpdating: isUpdatingBillingAddress() || isUpdatingCheckout(), + hasSaveAddressFeature: features['CHECKOUT-4642.uco_save_address_checkbox'], shouldShowOrderComments: enableOrderComments && getShippableItemsCount(cart) < 1, updateAddress: checkoutService.updateBillingAddress, updateCheckout: checkoutService.updateCheckout, diff --git a/src/app/billing/BillingForm.spec.tsx b/src/app/billing/BillingForm.spec.tsx index 9659e74204..86698652af 100644 --- a/src/app/billing/BillingForm.spec.tsx +++ b/src/app/billing/BillingForm.spec.tsx @@ -31,6 +31,7 @@ describe('BillingForm Component', () => { customer: getCustomer(), countries: getCountries(), googleMapsApiKey: 'key', + hasSaveAddressFeature: true, getFields: () => getFormFields(), onUnhandledError: jest.fn(), updateAddress: jest.fn(), @@ -111,6 +112,7 @@ describe('BillingForm Component', () => { stateOrProvinceCode: '', firstName: 'foo', lastName: 'Tester', + shouldSaveAddress: true, }); }); diff --git a/src/app/billing/BillingForm.tsx b/src/app/billing/BillingForm.tsx index c0693e25d0..b4341a2594 100644 --- a/src/app/billing/BillingForm.tsx +++ b/src/app/billing/BillingForm.tsx @@ -20,6 +20,7 @@ export interface BillingFormProps { countriesWithAutocomplete: string[]; googleMapsApiKey: string; isUpdating: boolean; + hasSaveAddressFeature: boolean; shouldShowOrderComments: boolean; getFields(countryCode?: string): FormField[]; onUnhandledError(error: Error): void; @@ -43,12 +44,13 @@ class BillingForm extends PureComponent } diff --git a/src/app/locale/translations/en.json b/src/app/locale/translations/en.json index d5d94db3ae..4bfb448138 100644 --- a/src/app/locale/translations/en.json +++ b/src/app/locale/translations/en.json @@ -28,6 +28,7 @@ "phone_number_required_error": "Phone Number is required", "postal_code_label": "Postal Code", "postal_code_required_error": "Postal Code is required", + "save_in_addressbook": "Save this address in my address book.", "select_country_action": "Select a country", "select_state_action": "Select a state", "state_label": "State/Province", @@ -41,7 +42,7 @@ "billing_heading": "Billing", "save_billing_address_error": "An error occurred while saving the billing address to your price quote. Please try again.", "billing_address_amazon": "Same as the Billing address set by you in your Amazon account.", - "use_shipping_address_label": "My Billing address is the same as my Shipping address" + "use_shipping_address_label": "My billing address is the same as my shipping address." }, "cart": { "billed_amount_text": "*You will be charged and invoiced {total} ({code}) for this order.", @@ -145,7 +146,6 @@ "send": "Send", "error_temporary_disabled": "Sign-in link functionality is temporary unavailable. Please sign in by entering your password.", "resend_link": "Didn't get the email? Resend the link", - "use_password_action": "Use Password Instead", "use_password_link": " or sign in using your password instead." }, "embedded_checkout": { diff --git a/src/app/shipping/Shipping.tsx b/src/app/shipping/Shipping.tsx index d3af7b459e..196dbf5c98 100644 --- a/src/app/shipping/Shipping.tsx +++ b/src/app/shipping/Shipping.tsx @@ -36,6 +36,7 @@ export interface WithCheckoutShippingProps { customer: Customer; customerMessage: string; googleMapsApiKey: string; + hasSaveAddressFeature: boolean; isGuest: boolean; isInitializing: boolean; isLoading: boolean; @@ -102,6 +103,7 @@ class Shipping extends Component @@ -322,6 +325,7 @@ export function mapToShippingProps({ googleMapsApiKey, initializeShippingMethod: checkoutService.initializeShipping, isGuest: customer.isGuest, + hasSaveAddressFeature: features['CHECKOUT-4642.uco_save_address_checkbox'], isInitializing: isLoadingShippingCountries() || isLoadingShippingOptions(), isLoading, loadShippingAddressFields: checkoutService.loadShippingAddressFields, diff --git a/src/app/shipping/ShippingAddress.tsx b/src/app/shipping/ShippingAddress.tsx index 6e67e83661..405a48e912 100644 --- a/src/app/shipping/ShippingAddress.tsx +++ b/src/app/shipping/ShippingAddress.tsx @@ -18,6 +18,7 @@ export interface ShippingAddressProps { isLoading: boolean; methodId?: string; shippingAddress?: Address; + shouldShowSaveAddress?: boolean; hasRequestedShippingOptions: boolean; deinitialize(options: ShippingRequestOptions): Promise; initialize(options: ShippingInitializeOptions): Promise; @@ -44,6 +45,7 @@ const ShippingAddress: FunctionComponent = props => { shippingAddress, hasRequestedShippingOptions, addresses, + shouldShowSaveAddress, onUnhandledError = noop, } = props; @@ -102,6 +104,7 @@ const ShippingAddress: FunctionComponent = props => { onAddressSelect={ onAddressSelect } onFieldChange={ handleFieldChange } onUseNewAddress={ onUseNewAddress } + shouldShowSaveAddress={ shouldShowSaveAddress } /> ); }; diff --git a/src/app/shipping/ShippingAddressForm.tsx b/src/app/shipping/ShippingAddressForm.tsx index 6e3f3f7e39..ee944d2839 100644 --- a/src/app/shipping/ShippingAddressForm.tsx +++ b/src/app/shipping/ShippingAddressForm.tsx @@ -17,6 +17,7 @@ export interface ShippingAddressFormProps { googleMapsApiKey?: string; isLoading: boolean; formFields: FormField[]; + shouldShowSaveAddress?: boolean; onUseNewAddress(): void; onFieldChange(fieldName: string, value: string): void; onAddressSelect(address: Address): void; @@ -31,6 +32,7 @@ class ShippingAddressForm extends Component } diff --git a/src/app/shipping/ShippingForm.tsx b/src/app/shipping/ShippingForm.tsx index 789be9c76b..6f52e39bf2 100644 --- a/src/app/shipping/ShippingForm.tsx +++ b/src/app/shipping/ShippingForm.tsx @@ -21,6 +21,7 @@ export interface ShippingFormProps { isMultiShippingMode: boolean; methodId?: string; shippingAddress?: Address; + shouldShowSaveAddress?: boolean; shouldShowOrderComments: boolean; assignItem(consignment: ConsignmentAssignmentRequestBody): Promise; deinitialize(options: ShippingRequestOptions): Promise; @@ -64,6 +65,7 @@ class ShippingForm extends Component { onUseNewAddress, shippingAddress, shouldShowOrderComments, + shouldShowSaveAddress, signOut, updateAddress, } = this.props; @@ -105,6 +107,7 @@ class ShippingForm extends Component { onUnhandledError={ onUnhandledError } shippingAddress={ shippingAddress } shouldShowOrderComments={ shouldShowOrderComments } + shouldShowSaveAddress={ shouldShowSaveAddress } signOut={ signOut } updateAddress={ updateAddress } />; diff --git a/src/app/shipping/SingleShippingForm.tsx b/src/app/shipping/SingleShippingForm.tsx index b1ad914b84..2c8b8fd742 100644 --- a/src/app/shipping/SingleShippingForm.tsx +++ b/src/app/shipping/SingleShippingForm.tsx @@ -26,6 +26,7 @@ export interface SingleShippingFormProps { isMultiShippingMode: boolean; methodId?: string; shippingAddress?: Address; + shouldShowSaveAddress?: boolean; shouldShowOrderComments: boolean; deinitialize(options: ShippingRequestOptions): Promise; deleteConsignments(): Promise
; @@ -92,6 +93,7 @@ class SingleShippingForm extends PureComponent { shouldShowBillingSameAsShipping &&
diff --git a/src/app/shipping/shipping-addresses.mock.ts b/src/app/shipping/shipping-addresses.mock.ts index 1ef238d49b..fdcb918a91 100644 --- a/src/app/shipping/shipping-addresses.mock.ts +++ b/src/app/shipping/shipping-addresses.mock.ts @@ -10,6 +10,7 @@ export function getShippingAddress(): Address { city: 'Some City', stateOrProvince: 'California', stateOrProvinceCode: 'CA', + shouldSaveAddress: true, country: 'United States', countryCode: 'US', postalCode: '95555',