Enhancement: Tax settings conflict warning (#36010)
* Add WIP error handling when conflicting settings chosen * add: enhance tax settings conflict warning * Fix WC_Settings_Tax_Test::test_get_settings_for_default_section * Wrap texts in i18n method * Add snackbar Co-authored-by: Adrian Duffell <9312929+adrianduffell@users.noreply.github.com> Co-authored-by: Chi-Hsuan Huang <chihsuan.tw@gmail.com>
This commit is contained in:
parent
c79de94c0f
commit
cc9f4b65fc
|
@ -17,6 +17,7 @@ import { PageLayout, EmbedLayout, PrimaryLayout as NoticeArea } from './layout';
|
||||||
import { CustomerEffortScoreTracksContainer } from './customer-effort-score-tracks';
|
import { CustomerEffortScoreTracksContainer } from './customer-effort-score-tracks';
|
||||||
import { EmbeddedBodyLayout } from './embedded-body-layout';
|
import { EmbeddedBodyLayout } from './embedded-body-layout';
|
||||||
import { WcAdminPaymentsGatewaysBannerSlot } from './payments/payments-settings-banner-slotfill';
|
import { WcAdminPaymentsGatewaysBannerSlot } from './payments/payments-settings-banner-slotfill';
|
||||||
|
import { WcAdminConflictErrorSlot } from './settings/conflict-error-slotfill.js';
|
||||||
|
|
||||||
// Modify webpack pubilcPath at runtime based on location of WordPress Plugin.
|
// Modify webpack pubilcPath at runtime based on location of WordPress Plugin.
|
||||||
// eslint-disable-next-line no-undef,camelcase
|
// eslint-disable-next-line no-undef,camelcase
|
||||||
|
@ -94,6 +95,12 @@ if ( appRoot ) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isTaxPage = document.getElementById( 'wc_conflict_error_slotfill' );
|
||||||
|
|
||||||
|
if ( isTaxPage ) {
|
||||||
|
render( WcAdminConflictErrorSlot(), isTaxPage );
|
||||||
|
}
|
||||||
|
|
||||||
const wrap =
|
const wrap =
|
||||||
wpBody.querySelector( '.wrap.woocommerce' ) ||
|
wpBody.querySelector( '.wrap.woocommerce' ) ||
|
||||||
document.querySelector( '#wpbody-content > .woocommerce' ) ||
|
document.querySelector( '#wpbody-content > .woocommerce' ) ||
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.57465 3.21635L1.51632 14.9997C1.37079 15.2517 1.29379 15.5374 1.29298 15.8284C1.29216 16.1195 1.36756 16.4056 1.51167 16.6585C1.65579 16.9113 1.86359 17.122 2.11441 17.2696C2.36523 17.4171 2.65032 17.4965 2.94132 17.4997H17.058C17.349 17.4965 17.6341 17.4171 17.8849 17.2696C18.1357 17.122 18.3435 16.9113 18.4876 16.6585C18.6317 16.4056 18.7071 16.1195 18.7063 15.8284C18.7055 15.5374 18.6285 15.2517 18.483 14.9997L11.4247 3.21635C11.2761 2.97144 11.0669 2.76895 10.8173 2.62842C10.5677 2.48789 10.2861 2.41406 9.99965 2.41406C9.71321 2.41406 9.43159 2.48789 9.18199 2.62842C8.93238 2.76895 8.72321 2.97144 8.57465 3.21635V3.21635Z" stroke="#E65054" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10 7.5V10.8333" stroke="#E65054" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10 14.168H10.0083" stroke="#E65054" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1,200 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { registerPlugin, PluginArea } from '@wordpress/plugins';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import interpolateComponents from '@automattic/interpolate-components';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CardBody,
|
||||||
|
createSlotFill,
|
||||||
|
SlotFillProvider,
|
||||||
|
} from '@wordpress/components';
|
||||||
|
import { Icon, closeSmall } from '@wordpress/icons';
|
||||||
|
import { useEffect, useState } from '@wordpress/element';
|
||||||
|
import { useDispatch } from '@wordpress/data';
|
||||||
|
import { store as noticesStore } from '@wordpress/notices';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './conflict-error-slotfill.scss';
|
||||||
|
import warningIcon from './alert-triangle-icon.svg';
|
||||||
|
|
||||||
|
const { Fill, Slot } = createSlotFill( '__EXPERIMENTAL__WcAdminConflictError' );
|
||||||
|
|
||||||
|
const LearnMore = () => (
|
||||||
|
<Button
|
||||||
|
href="https://woocommerce.com/document/setting-up-taxes-in-woocommerce/"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{ __( 'Learn more', 'woocommerce' ) }
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
|
||||||
|
const SettingsErrorFill = () => {
|
||||||
|
const [ dismissedConflictWarning, setDismissedConflictWarning ] =
|
||||||
|
useState( false );
|
||||||
|
|
||||||
|
const [ pricesEnteredWithTaxSetting, setMainVal ] = useState(
|
||||||
|
document.forms.mainform.elements.woocommerce_prices_include_tax
|
||||||
|
.value === 'yes'
|
||||||
|
? 'incl'
|
||||||
|
: 'excl'
|
||||||
|
);
|
||||||
|
const [ displayPricesInShopWithTaxSetting, setDisplayShop ] = useState(
|
||||||
|
/** We're using jQuery in this file because the select boxes are implemented using select2 and can only be interacted with using jQuery */
|
||||||
|
window.jQuery( '#woocommerce_tax_display_shop' ).val()
|
||||||
|
);
|
||||||
|
const [ displayPricesInCartWithTaxSetting, setDisplayCart ] = useState(
|
||||||
|
/** We're using jQuery in this file because the select boxes are implemented using select2 and can only be interacted with using jQuery */
|
||||||
|
window.jQuery( '#woocommerce_tax_display_cart' ).val()
|
||||||
|
);
|
||||||
|
|
||||||
|
const { createNotice } = useDispatch( noticesStore );
|
||||||
|
|
||||||
|
const handleApplyRecommendedSettings = () => {
|
||||||
|
/** We're using jQuery in this file because the select boxes are implemented using select2 and can only be interacted with using jQuery */
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
window
|
||||||
|
.jQuery( '#woocommerce_tax_display_shop' )
|
||||||
|
.val( pricesEnteredWithTaxSetting )
|
||||||
|
.trigger( 'change' );
|
||||||
|
window
|
||||||
|
.jQuery( '#woocommerce_tax_display_cart' )
|
||||||
|
.val( pricesEnteredWithTaxSetting )
|
||||||
|
.trigger( 'change' );
|
||||||
|
|
||||||
|
createNotice(
|
||||||
|
'success',
|
||||||
|
__( 'Recommended settings applied.', 'woocommerce' )
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ApplyRecommendedSettingsButton = () => (
|
||||||
|
<Button variant="primary" onClick={ handleApplyRecommendedSettings }>
|
||||||
|
{ __( 'Use recommended settings', 'woocommerce' ) }
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
document
|
||||||
|
.querySelectorAll( "input[name='woocommerce_prices_include_tax']" )
|
||||||
|
.forEach( ( input ) => {
|
||||||
|
input.addEventListener( 'change', () =>
|
||||||
|
setMainVal(
|
||||||
|
document.forms.mainform.elements
|
||||||
|
.woocommerce_prices_include_tax.value === 'yes'
|
||||||
|
? 'incl'
|
||||||
|
: 'excl'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}, [] );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
window
|
||||||
|
.jQuery( '#woocommerce_tax_display_shop' )
|
||||||
|
.on( 'click change', () =>
|
||||||
|
setDisplayShop(
|
||||||
|
document.getElementById( 'woocommerce_tax_display_shop' )
|
||||||
|
.value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}, [] );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
window
|
||||||
|
.jQuery( '#woocommerce_tax_display_cart' )
|
||||||
|
.on( 'click change', () =>
|
||||||
|
setDisplayCart(
|
||||||
|
document.getElementById( 'woocommerce_tax_display_cart' )
|
||||||
|
.value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}, [] );
|
||||||
|
|
||||||
|
const [ isConflict, setIsConflict ] = useState( false );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
if (
|
||||||
|
displayPricesInShopWithTaxSetting === pricesEnteredWithTaxSetting &&
|
||||||
|
displayPricesInCartWithTaxSetting === pricesEnteredWithTaxSetting
|
||||||
|
) {
|
||||||
|
setIsConflict( false );
|
||||||
|
} else {
|
||||||
|
setIsConflict( true );
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
displayPricesInCartWithTaxSetting,
|
||||||
|
displayPricesInShopWithTaxSetting,
|
||||||
|
pricesEnteredWithTaxSetting,
|
||||||
|
] );
|
||||||
|
|
||||||
|
if ( ! isConflict || dismissedConflictWarning ) {
|
||||||
|
return <Fill></Fill>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fill>
|
||||||
|
<div className="woocommerce_tax_settings_conflict_error">
|
||||||
|
<Card>
|
||||||
|
<CardBody className="woocommerce_tax_settings_conflict_error_card_body">
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
className="woocommerce_tax_settings_conflict_error_card_body__warning_icon"
|
||||||
|
src={ warningIcon }
|
||||||
|
alt="Warning Icon"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="woocommerce_tax_settings_conflict_error_card_body__body_text">
|
||||||
|
<p style={ { fontSize: 13 } }>
|
||||||
|
{ interpolateComponents( {
|
||||||
|
mixedString: __(
|
||||||
|
'{{b}}Inconsistent tax settings:{{/b}} To avoid possible rounding errors, prices should be entered and displayed consistently in all locations either including, or excluding taxes.',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
components: {
|
||||||
|
b: <b />,
|
||||||
|
},
|
||||||
|
} ) }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="woocommerce_tax_settings_conflict_error_card_body__buttons">
|
||||||
|
<ApplyRecommendedSettingsButton /> <LearnMore />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
className="woocommerce_tax_settings_conflict_error_card_body__close_icon"
|
||||||
|
onClick={ () =>
|
||||||
|
setDismissedConflictWarning( true )
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon icon={ closeSmall } />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</Fill>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WcAdminConflictErrorSlot = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SlotFillProvider>
|
||||||
|
<Slot />
|
||||||
|
<PluginArea scope="woocommerce-settings" />
|
||||||
|
</SlotFillProvider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
registerPlugin( 'woocommerce-admin-tax-settings-conflict-warning', {
|
||||||
|
scope: 'woocommerce-settings',
|
||||||
|
render: SettingsErrorFill,
|
||||||
|
} );
|
|
@ -0,0 +1,39 @@
|
||||||
|
.woocommerce_tax_settings_conflict_error {
|
||||||
|
padding: 15px 10px;
|
||||||
|
min-width: 400px;
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce_tax_settings_conflict_error_card_body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding-right: 16px !important; // override core styles
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce_tax_settings_conflict_error_card_body__warning_icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-block: 10px;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce_tax_settings_conflict_error_card_body__body_text {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce_tax_settings_conflict_error_card_body__close_icon {
|
||||||
|
padding: 0;
|
||||||
|
height: 24px;
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce_admin_tax_settings_slotfill_th,
|
||||||
|
.woocommerce_admin_tax_settings_slotfill_td {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[aria-labelledby='select2-woocommerce_tax_display_shop-container'].is-conflict {
|
||||||
|
border: #f00 !important;
|
||||||
|
border-style: solid !important;
|
||||||
|
border-width: 1px !important;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: enhancement
|
||||||
|
|
||||||
|
Add warning banner that informs the user if they have conflicting tax display settings
|
|
@ -27,7 +27,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
$this->label = __( 'Tax', 'woocommerce' );
|
$this->label = __( 'Tax', 'woocommerce' );
|
||||||
|
|
||||||
add_filter( 'woocommerce_settings_tabs_array', array( $this, 'add_settings_page' ), 20 );
|
add_filter( 'woocommerce_settings_tabs_array', array( $this, 'add_settings_page' ), 20 );
|
||||||
|
add_action( 'woocommerce_admin_field_conflict_error', array( $this, 'conflict_error' ) );
|
||||||
if ( wc_tax_enabled() ) {
|
if ( wc_tax_enabled() ) {
|
||||||
add_action( 'woocommerce_sections_' . $this->id, array( $this, 'output_sections' ) );
|
add_action( 'woocommerce_sections_' . $this->id, array( $this, 'output_sections' ) );
|
||||||
add_action( 'woocommerce_settings_' . $this->id, array( $this, 'output' ) );
|
add_action( 'woocommerce_settings_' . $this->id, array( $this, 'output' ) );
|
||||||
|
@ -35,6 +35,21 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the React mount point for the embedded banner.
|
||||||
|
*/
|
||||||
|
public function conflict_error() {
|
||||||
|
?>
|
||||||
|
<tr valign="top">
|
||||||
|
<th scope="row" class="titledesc woocommerce_admin_tax_settings_slotfill_th">
|
||||||
|
</th>
|
||||||
|
<td class="forminp forminp-text woocommerce_admin_tax_settings_slotfill_td">
|
||||||
|
<div id="wc_conflict_error_slotfill"> </div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add this page to settings.
|
* Add this page to settings.
|
||||||
*
|
*
|
||||||
|
|
|
@ -97,6 +97,8 @@ $settings = array(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
array( 'type' => 'conflict_error' ), // React mount point for embedded banner slotfill.
|
||||||
|
|
||||||
array(
|
array(
|
||||||
'title' => __( 'Price display suffix', 'woocommerce' ),
|
'title' => __( 'Price display suffix', 'woocommerce' ),
|
||||||
'id' => 'woocommerce_price_display_suffix',
|
'id' => 'woocommerce_price_display_suffix',
|
||||||
|
|
|
@ -64,6 +64,7 @@ class WC_Settings_Tax_Test extends WC_Settings_Unit_Test_Case {
|
||||||
'woocommerce_tax_display_cart' => 'select',
|
'woocommerce_tax_display_cart' => 'select',
|
||||||
'woocommerce_price_display_suffix' => 'text',
|
'woocommerce_price_display_suffix' => 'text',
|
||||||
'woocommerce_tax_total_display' => 'select',
|
'woocommerce_tax_total_display' => 'select',
|
||||||
|
'' => 'conflict_error',
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals( $expected, $settings_ids_and_types );
|
$this->assertEquals( $expected, $settings_ids_and_types );
|
||||||
|
|
Loading…
Reference in New Issue