/** * External dependencies */ import { ValidatedTextInput } from '@woocommerce/base-components/text-input'; import { BillingCountryInput, ShippingCountryInput, } from '@woocommerce/base-components/country-input'; import { BillingStateInput, ShippingStateInput, } from '@woocommerce/base-components/state-input'; import { useValidationContext } from '@woocommerce/base-context'; import { useEffect, useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { withInstanceId } from '@wordpress/compose'; import { useShallowEqual } from '@woocommerce/base-hooks'; import { AddressField, AddressFields, AddressType, defaultAddressFields, EnteredAddress, } from '@woocommerce/settings'; /** * Internal dependencies */ import prepareAddressFields from './prepare-address-fields'; // If it's the shipping address form and the user starts entering address // values without having set the country first, show an error. const validateShippingCountry = ( values: EnteredAddress, setValidationErrors: ( errors: Record< string, unknown > ) => void, clearValidationError: ( error: string ) => void, hasValidationError: boolean ): void => { if ( ! hasValidationError && ! values.country && ( values.city || values.state || values.postcode ) ) { setValidationErrors( { 'shipping-missing-country': { message: __( 'Please select a country to calculate rates.', 'woo-gutenberg-products-block' ), hidden: false, }, } ); } if ( hasValidationError && values.country ) { clearValidationError( 'shipping-missing-country' ); } }; interface AddressFormProps { // Id for component. id?: string; // Unique id for form. instanceId: string; // Array of fields in form. fields: ( keyof AddressFields )[]; // Field configuration for fields in form. fieldConfig?: Record< keyof AddressFields, Partial< AddressField > >; // Function to all for an form onChange event. onChange: ( newValue: EnteredAddress ) => void; // Type of form. type?: AddressType; // Values for fields. values: EnteredAddress; } /** * Checkout address form. */ const AddressForm = ( { id = '', fields = ( Object.keys( defaultAddressFields ) as unknown ) as ( keyof AddressFields )[], fieldConfig = {} as Record< keyof AddressFields, Partial< AddressField > >, instanceId, onChange, type = 'shipping', values, }: AddressFormProps ): JSX.Element => { const { getValidationError, setValidationErrors, clearValidationError, } = useValidationContext(); const currentFields = useShallowEqual( fields ); const countryValidationError = ( getValidationError( 'shipping-missing-country' ) || {} ) as { message: string; hidden: boolean; }; const addressFormFields = useMemo( () => { return prepareAddressFields( currentFields, fieldConfig, values.country ); }, [ currentFields, fieldConfig, values.country ] ); // Clear values for hidden fields. useEffect( () => { addressFormFields.forEach( ( field ) => { if ( field.hidden && values[ field.key ] ) { onChange( { ...values, [ field.key ]: '', } ); } } ); }, [ addressFormFields, onChange, values ] ); useEffect( () => { if ( type === 'shipping' ) { validateShippingCountry( values, setValidationErrors, clearValidationError, !! countryValidationError.message && ! countryValidationError.hidden ); } }, [ values, countryValidationError.message, countryValidationError.hidden, setValidationErrors, clearValidationError, type, ] ); id = id || instanceId; return (
{ addressFormFields.map( ( field ) => { if ( field.hidden ) { return null; } if ( field.key === 'country' ) { const Tag = type === 'shipping' ? ShippingCountryInput : BillingCountryInput; return ( onChange( { ...values, country: newValue, state: '', } ) } errorId={ type === 'shipping' ? 'shipping-missing-country' : null } errorMessage={ field.errorMessage } required={ field.required } /> ); } if ( field.key === 'state' ) { const Tag = type === 'shipping' ? ShippingStateInput : BillingStateInput; return ( onChange( { ...values, state: newValue, } ) } errorMessage={ field.errorMessage } required={ field.required } /> ); } return ( onChange( { ...values, [ field.key ]: newValue, } ) } errorMessage={ field.errorMessage } required={ field.required } /> ); } ) }
); }; export default withInstanceId( AddressForm );