Show notice if merchant has legacy local pickup enabled alongside the new pickup (https://github.com/woocommerce/woocommerce-blocks/pull/7842)

* add notice when there are existing enabled legacy local pickups

* Fix PHP warning

* Link though to the settings page

* Fix setting save

* Enabling this will produce duplicate options at checkout.

Co-authored-by: Mike Jolley <mike.jolley@me.com>
This commit is contained in:
Seghir Nadir 2022-12-07 16:52:02 +01:00 committed by Nadir Seghir
parent f2318060e1
commit 3c824053d7
6 changed files with 129 additions and 35 deletions

View File

@ -2,6 +2,7 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { createInterpolateElement, useState } from '@wordpress/element';
import { ADMIN_URL } from '@woocommerce/settings'; import { ADMIN_URL } from '@woocommerce/settings';
import { CHECKOUT_PAGE_ID } from '@woocommerce/block-settings'; import { CHECKOUT_PAGE_ID } from '@woocommerce/block-settings';
import { import {
@ -9,8 +10,9 @@ import {
SelectControl, SelectControl,
TextControl, TextControl,
ExternalLink, ExternalLink,
Notice,
} from '@wordpress/components'; } from '@wordpress/components';
import { useState } from '@wordpress/element'; import styled from '@emotion/styled';
/** /**
* Internal dependencies * Internal dependencies
@ -35,13 +37,39 @@ const GeneralSettingsDescription = () => (
</> </>
); );
const StyledNotice = styled( Notice )`
margin-left: 0;
margin-right: 0;
`;
const GeneralSettings = () => { const GeneralSettings = () => {
const { settings, setSettingField } = useSettingsContext(); const { settings, setSettingField, readOnlySettings } =
useSettingsContext();
const [ showCosts, setShowCosts ] = useState( !! settings.cost ); const [ showCosts, setShowCosts ] = useState( !! settings.cost );
return ( return (
<SettingsSection Description={ GeneralSettingsDescription }> <SettingsSection Description={ GeneralSettingsDescription }>
<SettingsCard> <SettingsCard>
{ readOnlySettings.hasLegacyPickup && (
<StyledNotice status="warning" isDismissible={ false }>
{ createInterpolateElement(
__(
'Enabling this will produce duplicate options at checkout. Remove the local pickup shipping method from your <a>shipping zones</a>.',
'woo-gutenberg-products-block'
),
{
a: (
// eslint-disable-next-line jsx-a11y/anchor-has-content
<a
href={ `${ ADMIN_URL }admin.php?page=wc-settings&tab=shipping` }
target="_blank"
rel="noopener noreferrer"
/>
),
}
) }
</StyledNotice>
) }
<CheckboxControl <CheckboxControl
checked={ settings.enabled } checked={ settings.enabled }
name="local_pickup_enabled" name="local_pickup_enabled"

View File

@ -25,11 +25,14 @@ import type {
import { import {
defaultSettings, defaultSettings,
getInitialSettings, getInitialSettings,
defaultReadyOnlySettings,
readOnlySettings,
getInitialPickupLocations, getInitialPickupLocations,
} from './utils'; } from './utils';
const SettingsContext = createContext< SettingsContextType >( { const SettingsContext = createContext< SettingsContextType >( {
settings: defaultSettings, settings: defaultSettings,
readOnlySettings: defaultReadyOnlySettings,
setSettingField: () => () => void null, setSettingField: () => () => void null,
pickupLocations: [], pickupLocations: [],
setPickupLocations: () => void null, setPickupLocations: () => void null,
@ -155,6 +158,7 @@ export const SettingsProvider = ( {
const settingsData = { const settingsData = {
settings, settings,
setSettingField, setSettingField,
readOnlySettings,
pickupLocations, pickupLocations,
setPickupLocations, setPickupLocations,
toggleLocation, toggleLocation,

View File

@ -30,8 +30,13 @@ export type ShippingMethodSettings = {
cost: string; cost: string;
}; };
export type ReadOnlySettings = {
hasLegacyPickup: boolean;
};
export type SettingsContextType = { export type SettingsContextType = {
settings: ShippingMethodSettings; settings: ShippingMethodSettings;
readOnlySettings: ReadOnlySettings;
setSettingField: ( setSettingField: (
field: keyof ShippingMethodSettings field: keyof ShippingMethodSettings
) => ( value: unknown ) => void; ) => ( value: unknown ) => void;

View File

@ -2,7 +2,6 @@
* External dependencies * External dependencies
*/ */
import { cleanForSlug } from '@wordpress/url'; import { cleanForSlug } from '@wordpress/url';
import { getSetting } from '@woocommerce/settings';
/** /**
* Internal dependencies * Internal dependencies
@ -25,20 +24,35 @@ export const indexLocationsById = (
}; };
export const defaultSettings = { export const defaultSettings = {
enabled: 'yes', enabled: true,
title: '', title: '',
tax_status: 'taxable', tax_status: 'taxable',
cost: '', cost: '',
}; };
export const defaultReadyOnlySettings = {
hasLegacyPickup: false,
};
declare global {
const hydratedScreenSettings: {
pickupLocationSettings: {
enabled: string;
title: string;
tax_status: string;
cost: string;
};
pickupLocations: PickupLocation[];
readonlySettings: typeof defaultReadyOnlySettings;
};
}
export const getInitialSettings = (): ShippingMethodSettings => { export const getInitialSettings = (): ShippingMethodSettings => {
const settings = getSetting( const settings = hydratedScreenSettings.pickupLocationSettings;
'pickupLocationSettings',
defaultSettings
) as typeof defaultSettings;
return { return {
enabled: settings?.enabled === 'yes', enabled: settings?.enabled
? settings?.enabled === 'yes'
: defaultSettings.enabled,
title: settings?.title || defaultSettings.title, title: settings?.title || defaultSettings.title,
tax_status: settings?.tax_status || defaultSettings.tax_status, tax_status: settings?.tax_status || defaultSettings.tax_status,
cost: settings?.cost || defaultSettings.cost, cost: settings?.cost || defaultSettings.cost,
@ -46,4 +60,7 @@ export const getInitialSettings = (): ShippingMethodSettings => {
}; };
export const getInitialPickupLocations = (): SortablePickupLocation[] => export const getInitialPickupLocations = (): SortablePickupLocation[] =>
indexLocationsById( getSetting( 'pickupLocations', [] ) ); indexLocationsById( hydratedScreenSettings.pickupLocations || [] );
export const readOnlySettings =
hydratedScreenSettings.readonlySettings || defaultReadyOnlySettings;

View File

@ -2,6 +2,7 @@
* External dependencies * External dependencies
*/ */
import { Card, CardBody } from '@wordpress/components'; import { Card, CardBody } from '@wordpress/components';
import type { ReactNode } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
const StyledCard = styled( Card )` const StyledCard = styled( Card )`
@ -9,6 +10,8 @@ const StyledCard = styled( Card )`
`; `;
const StyledCardBody = styled( CardBody )` const StyledCardBody = styled( CardBody )`
padding: 24px;
// increasing the specificity of the styles to override the Gutenberg ones // increasing the specificity of the styles to override the Gutenberg ones
&.is-size-medium.is-size-medium { &.is-size-medium.is-size-medium {
padding: 24px; padding: 24px;
@ -21,7 +24,7 @@ const StyledCardBody = styled( CardBody )`
> * { > * {
margin-top: 0; margin-top: 0;
margin-bottom: 1em; margin-bottom: 1.5em;
// fixing the spacing on the inputs and their help text, to ensure it is consistent // fixing the spacing on the inputs and their help text, to ensure it is consistent
&:last-child { &:last-child {
@ -52,7 +55,7 @@ const SettingsCard = ( {
children, children,
...props ...props
}: { }: {
children: ( JSX.Element | null )[]; children: ReactNode;
} ): JSX.Element => ( } ): JSX.Element => (
<StyledCard> <StyledCard>
<StyledCardBody { ...props }>{ children }</StyledCardBody> <StyledCardBody { ...props }>{ children }</StyledCardBody>

View File

@ -40,29 +40,6 @@ class ShippingController {
* Initialization method. * Initialization method.
*/ */
public function init() { public function init() {
// @todo This should be moved inline for the settings page only.
$this->asset_data_registry->add(
'pickupLocationSettings',
get_option( 'woocommerce_pickup_location_settings', [] ),
true
);
$this->asset_data_registry->add(
'pickupLocations',
function() {
$locations = get_option( 'pickup_location_pickup_locations', [] );
$formatted = [];
foreach ( $locations as $location ) {
$formatted[] = [
'name' => $location['name'],
'address' => $location['address'],
'details' => $location['details'],
'enabled' => wc_string_to_bool( $location['enabled'] ),
];
}
return $formatted;
},
true
);
if ( is_admin() ) { if ( is_admin() ) {
$this->asset_data_registry->add( $this->asset_data_registry->add(
'countryStates', 'countryStates',
@ -74,6 +51,7 @@ class ShippingController {
} }
add_action( 'rest_api_init', [ $this, 'register_settings' ] ); add_action( 'rest_api_init', [ $this, 'register_settings' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'admin_scripts' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'admin_scripts' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'hydrate_client_settings' ] );
add_action( 'woocommerce_load_shipping_methods', array( $this, 'register_local_pickup' ) ); add_action( 'woocommerce_load_shipping_methods', array( $this, 'register_local_pickup' ) );
add_filter( 'woocommerce_local_pickup_methods', array( $this, 'register_local_pickup_method' ) ); add_filter( 'woocommerce_local_pickup_methods', array( $this, 'register_local_pickup_method' ) );
add_filter( 'woocommerce_customer_taxable_address', array( $this, 'filter_taxable_address' ) ); add_filter( 'woocommerce_customer_taxable_address', array( $this, 'filter_taxable_address' ) );
@ -170,6 +148,65 @@ class ShippingController {
); );
} }
/**
* Hydrate client settings
*/
public function hydrate_client_settings() {
$locations = get_option( 'pickup_location_pickup_locations', [] );
$formatted_pickup_locations = [];
foreach ( $locations as $location ) {
$formatted_pickup_locations[] = [
'name' => $location['name'],
'address' => $location['address'],
'details' => $location['details'],
'enabled' => wc_string_to_bool( $location['enabled'] ),
];
}
$has_legacy_pickup = false;
// Get all shipping zones.
$shipping_zones = \WC_Shipping_Zones::get_zones( 'admin' );
$international_shipping_zone = new \WC_Shipping_Zone( 0 );
// Loop through each shipping zone.
foreach ( $shipping_zones as $shipping_zone ) {
// Get all registered rates for this shipping zone.
$shipping_methods = $shipping_zone['shipping_methods'];
// Loop through each registered rate.
foreach ( $shipping_methods as $shipping_method ) {
if ( 'local_pickup' === $shipping_method->id && 'yes' === $shipping_method->enabled ) {
$has_legacy_pickup = true;
break 2;
}
}
}
foreach ( $international_shipping_zone->get_shipping_methods( true ) as $shipping_method ) {
if ( 'local_pickup' === $shipping_method->id ) {
$has_legacy_pickup = true;
break;
}
}
$settings = array(
'pickupLocationSettings' => get_option( 'woocommerce_pickup_location_settings', [] ),
'pickupLocations' => $formatted_pickup_locations,
'readonlySettings' => array(
'hasLegacyPickup' => $has_legacy_pickup,
),
);
wp_add_inline_script(
'wc-shipping-method-pickup-location',
sprintf(
'var hydratedScreenSettings = %s;',
wp_json_encode( $settings )
),
'before'
);
}
/** /**
* Load admin scripts. * Load admin scripts.
*/ */