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
This commit is contained in:
Saad Tarhi 2023-03-14 14:49:31 +01:00 committed by GitHub
parent a2945306ac
commit abe3488861
6 changed files with 139 additions and 90 deletions

View File

@ -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 (
<form ref={ formRef }>
<TextControl
@ -97,42 +96,77 @@ const Form = ( {
onChange={ setLocationAddressField( 'postcode' ) }
autoComplete="off"
/>
<StateControl
label={ __( 'State', 'woo-gutenberg-products-block' ) }
name={ 'location_state' }
hideLabelFromVision={ true }
placeholder={ __( 'State', 'woo-gutenberg-products-block' ) }
value={ values.address.state }
{ ! countryHasStates && (
<TextControl
placeholder={ __(
'State',
'woo-gutenberg-products-block'
) }
value={ selectedState }
onChange={ setLocationAddressField( 'state' ) }
autoComplete="off"
states={ states }
currentCountry={ values.address.country }
/>
) }
<SelectControl
label={ __( 'Country', 'woo-gutenberg-products-block' ) }
name={ 'location_country' }
name="location_country_state"
label={ __(
'Country / State',
'woo-gutenberg-products-block'
) }
hideLabelFromVision={ true }
placeholder={ __( 'Country', 'woo-gutenberg-products-block' ) }
value={ values.address.country }
placeholder={ __(
'Country / State',
'woo-gutenberg-products-block'
) }
value={ ( () => {
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 (
<optgroup
key={ option.label }
label={ option.label }
>
{ option.options.map( ( subOption ) => (
<option
key={ subOption.value }
value={ subOption.value }
>
{ subOption.label }
</option>
) ) }
</optgroup>
);
}
return (
<option
key={ option.options[ 0 ].value }
value={ option.options[ 0 ].value }
>
{ option.options[ 0 ].label }
</option>
);
} ) }
</SelectControl>
<TextControl
label={ __( 'Pickup details', 'woo-gutenberg-products-block' ) }
name={ 'pickup_details' }

View File

@ -1,45 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { SelectControl, TextControl } from '@wordpress/components';
const StateControl = ( {
states,
currentCountry,
...props
}: {
states: Record< string, Record< string, string > >;
currentCountry: string;
} ): JSX.Element | null => {
const filteredStates = states[ currentCountry ] || [];
if ( filteredStates.length === 0 ) {
return (
<TextControl
{ ...props }
disabled={ ! currentCountry || props.disabled }
/>
);
}
return (
<SelectControl
{ ...props }
options={ [
{
value: '',
disabled: true,
label: __( 'State', 'woo-gutenberg-products-block' ),
},
...Object.entries( filteredStates ).map(
( [ code, state ] ) => ( {
value: code,
label: state,
} )
),
] }
/>
);
};
export default StateControl;

View File

@ -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 }
<StyledAddress>
{ isObject( row.address ) &&
Object.values( row.address )
.filter( ( value ) => value !== '' )
.join( ', ' ) }
{ getUserFriendlyAddress( row.address ) }
</StyledAddress>
</>
),
@ -137,7 +135,7 @@ const LocationSettings = () => {
address: {
address_1: '',
city: '',
state: '',
state: readOnlySettings.storeState,
postcode: '',
country: readOnlySettings.storeCountry,
},

View File

@ -32,6 +32,7 @@ export type ShippingMethodSettings = {
export type ReadOnlySettings = {
storeCountry: string;
storeState: string;
hasLegacyPickup: boolean;
};

View File

@ -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();

View File

@ -302,6 +302,7 @@ class ShippingController {
'readonlySettings' => array(
'hasLegacyPickup' => $has_legacy_pickup,
'storeCountry' => WC()->countries->get_base_country(),
'storeState' => WC()->countries->get_base_state(),
),
);