From abe348886131eea5267d85e6cab96ca54d9471a5 Mon Sep 17 00:00:00 2001 From: Saad Tarhi Date: Tue, 14 Mar 2023 14:49:31 +0100 Subject: [PATCH] Local Pickup: merge country and state into same field in location modal (https://github.com/woocommerce/woocommerce-blocks/pull/8408) * Get the default store state We are merging the Country & State fields. So, we should get both default values * Merge the Country & State fields We merged both fields in the Pickup Location form modal We can see a similar example in `WooCommerce -> Settings -> General` * Clean up the code * Show the state text field above the country select * Create some util functions * Refactor the Form component * Display a user friendly country and state in admin * Fix country defaulting to "Afghan" bug --- .../pickup-location/edit-location/form.tsx | 112 ++++++++++++------ .../edit-location/state-control.tsx | 45 ------- .../pickup-location/location-settings.tsx | 10 +- .../shipping-methods/pickup-location/types.ts | 1 + .../shipping-methods/pickup-location/utils.ts | 60 ++++++++++ .../src/Shipping/ShippingController.php | 1 + 6 files changed, 139 insertions(+), 90 deletions(-) delete mode 100644 plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/edit-location/state-control.tsx diff --git a/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/edit-location/form.tsx b/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/edit-location/form.tsx index 4fe9675e286..4df31be4c05 100644 --- a/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/edit-location/form.tsx +++ b/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/edit-location/form.tsx @@ -3,13 +3,12 @@ */ import { __ } from '@wordpress/i18n'; import { SelectControl, TextControl } from '@wordpress/components'; -import { getSetting } from '@woocommerce/settings'; /** * Internal dependencies */ import type { PickupLocation } from '../types'; -import StateControl from './state-control'; +import { countryStateOptions, states } from '../utils'; const Form = ( { formRef, @@ -20,11 +19,7 @@ const Form = ( { values: PickupLocation; setValues: React.Dispatch< React.SetStateAction< PickupLocation > >; } ) => { - const countries = getSetting< Record< string, string > >( 'countries', [] ); - const states = getSetting< Record< string, Record< string, string > > >( - 'countryStates', - [] - ); + const { country: selectedCountry, state: selectedState } = values.address; const setLocationField = ( field: keyof PickupLocation ) => ( newValue: string | boolean ) => { setValues( ( prevValue: PickupLocation ) => ( { @@ -45,6 +40,10 @@ const Form = ( { } ) ); }; + const countryHasStates = + states[ selectedCountry ] && + Object.keys( states[ selectedCountry ] ).length > 0; + return (
- + { ! countryHasStates && ( + + ) } { + if ( ! selectedState && countryHasStates ) { + return `${ selectedCountry }:${ + Object.keys( states[ selectedCountry ] )[ 0 ] + }`; + } + + return `${ selectedCountry }${ + selectedState && + states[ selectedCountry ]?.[ selectedState ] + ? ':' + selectedState + : '' + }`; + } )() } onChange={ ( val: string ) => { - setLocationAddressField( 'state' )( '' ); - setLocationAddressField( 'country' )( val ); + const [ country, state = '' ] = val.split( ':' ); + setLocationAddressField( 'country' )( country ); + setLocationAddressField( 'state' )( state ); } } - autoComplete="off" - options={ [ - { - value: '', - disabled: true, - label: __( 'Country', 'woo-gutenberg-products-block' ), - }, - ...Object.entries( countries ).map( - ( [ code, country ] ) => ( { - value: code, - label: country, - } ) - ), - ] } - /> + > + { countryStateOptions.options.map( ( option ) => { + if ( option.label ) { + return ( + + { option.options.map( ( subOption ) => ( + + ) ) } + + ); + } + + return ( + + ); + } ) } + + >; - currentCountry: string; -} ): JSX.Element | null => { - const filteredStates = states[ currentCountry ] || []; - - if ( filteredStates.length === 0 ) { - return ( - - ); - } - return ( - ( { - value: code, - label: state, - } ) - ), - ] } - /> - ); -}; - -export default StateControl; diff --git a/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/location-settings.tsx b/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/location-settings.tsx index 0eaaeaa85bf..963ae74fdbf 100644 --- a/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/location-settings.tsx +++ b/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/location-settings.tsx @@ -4,7 +4,7 @@ import { __ } from '@wordpress/i18n'; import { useState } from '@wordpress/element'; import type { UniqueIdentifier } from '@dnd-kit/core'; -import { isObject, isBoolean } from '@woocommerce/types'; +import { isBoolean } from '@woocommerce/types'; import { ToggleControl, Button, ExternalLink } from '@wordpress/components'; import styled from '@emotion/styled'; @@ -19,6 +19,7 @@ import { import EditLocation from './edit-location'; import type { SortablePickupLocation } from './types'; import { useSettingsContext } from './settings-context'; +import { getUserFriendlyAddress } from './utils'; const LocationSettingsDescription = () => ( <> @@ -62,10 +63,7 @@ const LocationSettings = () => { <> { row.name } - { isObject( row.address ) && - Object.values( row.address ) - .filter( ( value ) => value !== '' ) - .join( ', ' ) } + { getUserFriendlyAddress( row.address ) } ), @@ -137,7 +135,7 @@ const LocationSettings = () => { address: { address_1: '', city: '', - state: '', + state: readOnlySettings.storeState, postcode: '', country: readOnlySettings.storeCountry, }, diff --git a/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/types.ts b/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/types.ts index 57741f3b69b..daa50364545 100644 --- a/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/types.ts +++ b/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/types.ts @@ -32,6 +32,7 @@ export type ShippingMethodSettings = { export type ReadOnlySettings = { storeCountry: string; + storeState: string; hasLegacyPickup: boolean; }; diff --git a/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/utils.ts b/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/utils.ts index 99900025868..43dfba322fe 100644 --- a/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/utils.ts +++ b/plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/utils.ts @@ -3,6 +3,8 @@ */ import { cleanForSlug } from '@wordpress/url'; import { __ } from '@wordpress/i18n'; +import { isObject } from '@woocommerce/types'; +import { getSetting } from '@woocommerce/settings'; /** * Internal dependencies */ @@ -33,6 +35,7 @@ export const defaultSettings = { export const defaultReadyOnlySettings = { hasLegacyPickup: false, storeCountry: '', + storeState: '', }; declare global { const hydratedScreenSettings: { @@ -65,3 +68,60 @@ export const getInitialPickupLocations = (): SortablePickupLocation[] => export const readOnlySettings = hydratedScreenSettings.readonlySettings || defaultReadyOnlySettings; + +export const countries = getSetting< Record< string, string > >( + 'countries', + [] +); +export const states = getSetting< Record< string, Record< string, string > > >( + 'countryStates', + [] +); +export const getUserFriendlyAddress = ( address: unknown ) => { + const updatedAddress = isObject( address ) && { + ...address, + country: + typeof address.country === 'string' && countries[ address.country ], + state: + typeof address.country === 'string' && + typeof address.state === 'string' && + states[ address.country ]?.[ address.state ] + ? states[ address.country ][ address.state ] + : address.state, + }; + + return Object.values( updatedAddress ) + .filter( ( value ) => value !== '' ) + .join( ', ' ); +}; + +// Outputs the list of countries and states in a single dropdown select. +const countryStateDropdownOptions = () => { + const countryStateOptions = Object.keys( countries ).map( ( country ) => { + const countryStates = states[ country ] || {}; + + if ( Object.keys( countryStates ).length === 0 ) { + return { + options: [ + { + value: country, + label: countries[ country ], + }, + ], + }; + } + + const stateOptions = Object.keys( countryStates ).map( ( state ) => ( { + value: `${ country }:${ state }`, + label: `${ countries[ country ] } — ${ countryStates[ state ] }`, + } ) ); + return { + label: countries[ country ], + options: [ ...stateOptions ], + }; + } ); + return { + options: countryStateOptions, + }; +}; +export const countryStateOptions = countryStateDropdownOptions(); diff --git a/plugins/woocommerce-blocks/src/Shipping/ShippingController.php b/plugins/woocommerce-blocks/src/Shipping/ShippingController.php index d0bdae7e910..5c7686be569 100644 --- a/plugins/woocommerce-blocks/src/Shipping/ShippingController.php +++ b/plugins/woocommerce-blocks/src/Shipping/ShippingController.php @@ -302,6 +302,7 @@ class ShippingController { 'readonlySettings' => array( 'hasLegacyPickup' => $has_legacy_pickup, 'storeCountry' => WC()->countries->get_base_country(), + 'storeState' => WC()->countries->get_base_state(), ), );