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:
parent
a2945306ac
commit
abe3488861
|
@ -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' }
|
||||
|
|
|
@ -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;
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -32,6 +32,7 @@ export type ShippingMethodSettings = {
|
|||
|
||||
export type ReadOnlySettings = {
|
||||
storeCountry: string;
|
||||
storeState: string;
|
||||
hasLegacyPickup: boolean;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -302,6 +302,7 @@ class ShippingController {
|
|||
'readonlySettings' => array(
|
||||
'hasLegacyPickup' => $has_legacy_pickup,
|
||||
'storeCountry' => WC()->countries->get_base_country(),
|
||||
'storeState' => WC()->countries->get_base_state(),
|
||||
),
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue