Update design of cart and checkout sidebars (https://github.com/woocommerce/woocommerce-blocks/pull/4180)
* Update cart/coupon/shipping design * Add order summary heading * Move and style discounts on checkout sidebar * Add rate to tax lines * Ensure the option to display taxes itemised is available to Cart block * Output individual tax items below the total & add styles for this * Add success notice under coupon input on successful coupon addition * Add border to bottom of Totals footer * Show success message when adding coupon * Add padding to cart item rows * Add preview data to cart for when taxes are enabled * Add rate to cart response type * Add showRateAfterTaxName attribute to Cart block * Add control to cart block to show rate percentage after rate name * Add rate % in cart totals only if option is toggled on * Pass showRateAfterTaxName attribute down to TotalsTaxes * Add showRateAfterTaxName to Checkout block * Add control to block editor for showRateAfterTaxName on Checkout * Pass showRateAfterTaxName down to TotalsTaxes in Checkout * Change label for showing tax rates in cart and checkout blocks * Add test to ensure Taxes section shows in Cart block * Add tests for cart sidebar and rate percentages * Remove order summary title from checkout sidebar * Check if taxes are enabled before rendering the option to show rate %s * Add ShippingVia component to show the selected rate in sidebar * Remove value from individual tax rates * Remove bold from Shipping via label * Remove coupon added successfully message * Ensure panel headings that are h2s are the same colour as others * Clean up eslint warnings * Show rate %s by default * Update snapshots following design changes Co-authored-by: Mike Jolley <mike.jolley@me.com>
This commit is contained in:
parent
b14b557c91
commit
57c5b0c532
|
@ -5,6 +5,7 @@
|
|||
$no-stock-color: $alert-red;
|
||||
$low-stock-color: $alert-yellow;
|
||||
$in-stock-color: $alert-green;
|
||||
$discount-color: $alert-green;
|
||||
|
||||
$placeholder-color: var(--global--color-primary, $gray-200);
|
||||
$input-border-gray: #50575e;
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
import classNames from 'classnames';
|
||||
import { _n, sprintf } from '@wordpress/i18n';
|
||||
import { decodeEntities } from '@wordpress/html-entities';
|
||||
import Label from '@woocommerce/base-components/label';
|
||||
import Title from '@woocommerce/base-components/title';
|
||||
import type { ReactElement } from 'react';
|
||||
import type { PackageRateOption } from '@woocommerce/type-defs/shipping';
|
||||
import { Panel } from '@woocommerce/blocks-checkout';
|
||||
import Label from '@woocommerce/base-components/label';
|
||||
import { useSelectShippingRate } from '@woocommerce/base-context/hooks';
|
||||
import type { CartShippingPackageShippingRate } from '@woocommerce/type-defs/cart';
|
||||
|
||||
|
@ -77,12 +76,9 @@ export const ShippingRatesControlPackage = ( {
|
|||
const header = (
|
||||
<>
|
||||
{ ( showItems || collapsible ) && (
|
||||
<Title
|
||||
className="wc-block-components-shipping-rates-control__package-title"
|
||||
headingLevel="3"
|
||||
>
|
||||
<div className="wc-block-components-shipping-rates-control__package-title">
|
||||
{ packageData.name }
|
||||
</Title>
|
||||
</div>
|
||||
) }
|
||||
{ showItems && (
|
||||
<ul className="wc-block-components-shipping-rates-control__package-items">
|
||||
|
|
|
@ -6,12 +6,6 @@
|
|||
padding-top: em($gap-small);
|
||||
}
|
||||
|
||||
.wc-block-components-shipping-rates-control__package-title {
|
||||
@include text-heading();
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// Remove panel padding because we are adding bottom padding to `.wc-block-components-radio-control`
|
||||
// and `.wc-block-components-radio-control__option-layout` in the next ruleset.
|
||||
.wc-block-components-panel__content {
|
||||
|
|
|
@ -51,11 +51,11 @@ const TotalsCoupon = ( {
|
|||
title={
|
||||
<Label
|
||||
label={ __(
|
||||
'Coupon Code?',
|
||||
'Coupon code',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
screenReaderLabel={ __(
|
||||
'Introduce Coupon Code',
|
||||
'Apply a coupon code',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
htmlFor={ textInputId }
|
||||
|
|
|
@ -3,3 +3,7 @@
|
|||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.wc-block-components-totals-discount .wc-block-components-totals-item__value {
|
||||
color: $discount-color;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import { TotalsItem } from '@woocommerce/blocks-checkout';
|
|||
import type { Currency } from '@woocommerce/price-format';
|
||||
import type { ReactElement } from 'react';
|
||||
import { getSetting, EnteredAddress } from '@woocommerce/settings';
|
||||
import { ShippingVia } from '@woocommerce/base-components/cart-checkout/totals/shipping/shipping-via';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -146,6 +147,14 @@ const TotalsShipping = ( {
|
|||
setIsShippingCalculatorOpen,
|
||||
};
|
||||
|
||||
const selectedShippingRates = shippingRates.flatMap(
|
||||
( shippingPackage ) => {
|
||||
return shippingPackage.shipping_rates
|
||||
.filter( ( rate ) => rate.selected )
|
||||
.flatMap( ( rate ) => rate.name );
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ classnames(
|
||||
|
@ -168,11 +177,18 @@ const TotalsShipping = ( {
|
|||
description={
|
||||
<>
|
||||
{ cartHasCalculatedShipping && (
|
||||
<ShippingAddress
|
||||
shippingAddress={ shippingAddress }
|
||||
showCalculator={ showCalculator }
|
||||
{ ...calculatorButtonProps }
|
||||
/>
|
||||
<>
|
||||
<ShippingVia
|
||||
selectedShippingRates={
|
||||
selectedShippingRates
|
||||
}
|
||||
/>
|
||||
<ShippingAddress
|
||||
shippingAddress={ shippingAddress }
|
||||
showCalculator={ showCalculator }
|
||||
{ ...calculatorButtonProps }
|
||||
/>
|
||||
</>
|
||||
) }
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
export const ShippingVia = ( {
|
||||
selectedShippingRates,
|
||||
}: {
|
||||
selectedShippingRates: string[];
|
||||
} ): JSX.Element => {
|
||||
return (
|
||||
<div className="wc-block-components-totals-item__description wc-block-components-totals-shipping__via">
|
||||
{ __( 'via', 'woo-gutenberg-products-block' ) }{ ' ' }
|
||||
{ selectedShippingRates.join( ', ' ) }
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -7,6 +7,10 @@
|
|||
border: 0;
|
||||
}
|
||||
|
||||
.wc-block-components-totals-shipping__via {
|
||||
margin-bottom: $gap;
|
||||
}
|
||||
|
||||
.wc-block-components-totals-shipping__options {
|
||||
.wc-block-components-radio-control__label,
|
||||
.wc-block-components-radio-control__description,
|
||||
|
|
|
@ -52,6 +52,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.wc-block-components-sidebar .wc-block-components-panel > h2 {
|
||||
@include reset-typography();
|
||||
.wc-block-components-panel__button {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
// For Twenty Twenty we need to increase specificity a bit more.
|
||||
.theme-twentytwenty {
|
||||
.wc-block-components-sidebar .wc-block-components-panel > h2 {
|
||||
|
|
|
@ -21,6 +21,10 @@ const blockAttributes = {
|
|||
type: 'boolean',
|
||||
default: getSetting( 'hasDarkEditorStyleSupport', false ),
|
||||
},
|
||||
showRateAfterTaxName: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default blockAttributes;
|
||||
|
|
|
@ -39,6 +39,7 @@ const BlockSettings = ( { attributes, setAttributes } ) => {
|
|||
isShippingCalculatorEnabled,
|
||||
checkoutPageId,
|
||||
hasDarkControls,
|
||||
showRateAfterTaxName,
|
||||
} = attributes;
|
||||
const { currentPostId } = useEditorContext();
|
||||
const { current: savedCheckoutPageId } = useRef( checkoutPageId );
|
||||
|
@ -95,6 +96,30 @@ const BlockSettings = ( { attributes, setAttributes } ) => {
|
|||
/>
|
||||
</PanelBody>
|
||||
) }
|
||||
{ getSetting( 'taxesEnabled' ) &&
|
||||
getSetting( 'displayItemizedTaxes', false ) &&
|
||||
! getSetting( 'displayCartPricesIncludingTax', false ) && (
|
||||
<PanelBody
|
||||
title={ __( 'Taxes', 'woo-gutenberg-products-block' ) }
|
||||
>
|
||||
<ToggleControl
|
||||
label={ __(
|
||||
'Show rate after tax name',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
help={ __(
|
||||
'Show the percentage rate alongside each tax line in the summary.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
checked={ showRateAfterTaxName }
|
||||
onChange={ () =>
|
||||
setAttributes( {
|
||||
showRateAfterTaxName: ! showRateAfterTaxName,
|
||||
} )
|
||||
}
|
||||
/>
|
||||
</PanelBody>
|
||||
) }
|
||||
{ ! (
|
||||
currentPostId === CART_PAGE_ID && savedCheckoutPageId === 0
|
||||
) && (
|
||||
|
|
|
@ -48,6 +48,7 @@ interface CartAttributes {
|
|||
isShippingCalculatorEnabled: boolean;
|
||||
checkoutPageId: number;
|
||||
isPreview: boolean;
|
||||
showRateAfterTaxName: boolean;
|
||||
}
|
||||
|
||||
interface CartProps {
|
||||
|
@ -60,7 +61,11 @@ interface CartProps {
|
|||
* @param {Object} props.attributes Incoming attributes for block.
|
||||
*/
|
||||
const Cart = ( { attributes }: CartProps ) => {
|
||||
const { isShippingCalculatorEnabled, hasDarkControls } = attributes;
|
||||
const {
|
||||
isShippingCalculatorEnabled,
|
||||
hasDarkControls,
|
||||
showRateAfterTaxName,
|
||||
} = attributes;
|
||||
|
||||
const {
|
||||
cartItems,
|
||||
|
@ -141,6 +146,12 @@ const Cart = ( { attributes }: CartProps ) => {
|
|||
removeCoupon={ removeCoupon }
|
||||
values={ cartTotals }
|
||||
/>
|
||||
{ getSetting( 'couponsEnabled', true ) && (
|
||||
<TotalsCoupon
|
||||
onSubmit={ applyCoupon }
|
||||
isLoading={ isApplyingCoupon }
|
||||
/>
|
||||
) }
|
||||
{ cartNeedsShipping && (
|
||||
<TotalsShipping
|
||||
showCalculator={ isShippingCalculatorEnabled }
|
||||
|
@ -154,16 +165,12 @@ const Cart = ( { attributes }: CartProps ) => {
|
|||
false
|
||||
) && (
|
||||
<TotalsTaxes
|
||||
showRateAfterTaxName={ showRateAfterTaxName }
|
||||
currency={ totalsCurrency }
|
||||
values={ cartTotals }
|
||||
/>
|
||||
) }
|
||||
{ getSetting( 'couponsEnabled', true ) && (
|
||||
<TotalsCoupon
|
||||
onSubmit={ applyCoupon }
|
||||
isLoading={ isApplyingCoupon }
|
||||
/>
|
||||
) }
|
||||
|
||||
<TotalsFooterItem
|
||||
currency={ totalsCurrency }
|
||||
values={ cartTotals }
|
||||
|
|
|
@ -78,8 +78,17 @@ table.wc-block-cart-items {
|
|||
}
|
||||
}
|
||||
|
||||
.wc-block-cart .wc-block-components-shipping-rates-control__package {
|
||||
@include with-translucent-border(1px 0 0);
|
||||
.wc-block-cart {
|
||||
.wc-block-components-totals-taxes,
|
||||
.wc-block-components-totals-footer-item {
|
||||
@include with-translucent-border(1px 0 0);
|
||||
margin: 0;
|
||||
padding: em($gap-small) 0;
|
||||
}
|
||||
|
||||
.wc-block-components-totals-footer-item {
|
||||
@include with-translucent-border(1px 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Loading placeholder state.
|
||||
|
@ -236,13 +245,15 @@ table.wc-block-cart-items {
|
|||
}
|
||||
td {
|
||||
@include with-translucent-border(1px 0 0);
|
||||
padding: $gap $gap $gap 0;
|
||||
padding: $gap 0 $gap $gap;
|
||||
vertical-align: top;
|
||||
}
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
th:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
td:last-child {
|
||||
padding-right: $gap;
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-components-radio-control__input {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,6 +12,7 @@ import { default as fetchMock } from 'jest-fetch-mock';
|
|||
*/
|
||||
import CartBlock from '../block';
|
||||
import { defaultCartState } from '../../../../data/default-states';
|
||||
import { allSettings } from '../../../../settings/shared/settings-init';
|
||||
|
||||
describe( 'Testing cart', () => {
|
||||
beforeEach( async () => {
|
||||
|
@ -49,6 +50,59 @@ describe( 'Testing cart', () => {
|
|||
expect( console ).toHaveWarned();
|
||||
} );
|
||||
|
||||
it( 'Contains a Taxes section if Core options are set to show it', async () => {
|
||||
allSettings.displayCartPricesIncludingTax = false;
|
||||
// The criteria for showing the Taxes section is:
|
||||
// Display prices during basket and checkout: 'Excluding tax'.
|
||||
const { container } = render(
|
||||
<CartBlock
|
||||
emptyCart={ null }
|
||||
attributes={ {
|
||||
isShippingCalculatorEnabled: false,
|
||||
} }
|
||||
/>
|
||||
);
|
||||
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
|
||||
expect( container ).toMatchSnapshot();
|
||||
} );
|
||||
|
||||
it( 'Shows individual tax lines if the store is set to do so', async () => {
|
||||
allSettings.displayCartPricesIncludingTax = false;
|
||||
allSettings.displayItemizedTaxes = true;
|
||||
// The criteria for showing the lines in the Taxes section is:
|
||||
// Display prices during basket and checkout: 'Excluding tax'.
|
||||
// Display tax totals: 'Itemized';
|
||||
const { container } = render(
|
||||
<CartBlock
|
||||
emptyCart={ null }
|
||||
attributes={ {
|
||||
isShippingCalculatorEnabled: false,
|
||||
} }
|
||||
/>
|
||||
);
|
||||
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
|
||||
expect( container ).toMatchSnapshot();
|
||||
} );
|
||||
|
||||
it( 'Shows rate percentages after tax lines if the block is set to do so', async () => {
|
||||
allSettings.displayCartPricesIncludingTax = false;
|
||||
allSettings.displayItemizedTaxes = true;
|
||||
// The criteria for showing the lines in the Taxes section is:
|
||||
// Display prices during basket and checkout: 'Excluding tax'.
|
||||
// Display tax totals: 'Itemized';
|
||||
const { container } = render(
|
||||
<CartBlock
|
||||
emptyCart={ null }
|
||||
attributes={ {
|
||||
showRateAfterTaxName: true,
|
||||
isShippingCalculatorEnabled: false,
|
||||
} }
|
||||
/>
|
||||
);
|
||||
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
|
||||
expect( container ).toMatchSnapshot();
|
||||
} );
|
||||
|
||||
it( 'renders empty cart if there are no items in the cart', async () => {
|
||||
fetchMock.mockResponse( ( req ) => {
|
||||
if ( req.url.match( /wc\/store\/cart/ ) ) {
|
||||
|
|
|
@ -53,6 +53,10 @@ const blockAttributes = {
|
|||
type: 'boolean',
|
||||
default: getSetting( 'hasDarkEditorStyleSupport', false ),
|
||||
},
|
||||
showRateAfterTaxName: {
|
||||
type: 'boolean',
|
||||
default: getSetting( 'displayCartPricesIncludingTax', false ),
|
||||
},
|
||||
};
|
||||
|
||||
export default blockAttributes;
|
||||
|
|
|
@ -155,6 +155,7 @@ const Checkout = ( { attributes, scrollToTop } ) => {
|
|||
cartItems={ cartItems }
|
||||
cartTotals={ cartTotals }
|
||||
cartFees={ cartFees }
|
||||
showRateAfterTaxName={ attributes.showRateAfterTaxName }
|
||||
/>
|
||||
</Sidebar>
|
||||
</SidebarLayout>
|
||||
|
|
|
@ -52,6 +52,7 @@ const BlockSettings = ( { attributes, setAttributes } ) => {
|
|||
showReturnToCart,
|
||||
cartPageId,
|
||||
hasDarkControls,
|
||||
showRateAfterTaxName,
|
||||
} = attributes;
|
||||
const { currentPostId } = useEditorContext();
|
||||
const { current: savedCartPageId } = useRef( cartPageId );
|
||||
|
@ -298,6 +299,30 @@ const BlockSettings = ( { attributes, setAttributes } ) => {
|
|||
} }
|
||||
/>
|
||||
) }
|
||||
{ getSetting( 'taxesEnabled' ) &&
|
||||
getSetting( 'displayItemizedTaxes', false ) &&
|
||||
! getSetting( 'displayCartPricesIncludingTax', false ) && (
|
||||
<PanelBody
|
||||
title={ __( 'Taxes', 'woo-gutenberg-products-block' ) }
|
||||
>
|
||||
<ToggleControl
|
||||
label={ __(
|
||||
'Show rate after tax name',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
help={ __(
|
||||
'Show the percentage rate alongside each tax line in the summary.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
checked={ showRateAfterTaxName }
|
||||
onChange={ () =>
|
||||
setAttributes( {
|
||||
showRateAfterTaxName: ! showRateAfterTaxName,
|
||||
} )
|
||||
}
|
||||
/>
|
||||
</PanelBody>
|
||||
) }
|
||||
<PanelBody title={ __( 'Style', 'woo-gutenberg-products-block' ) }>
|
||||
<ToggleControl
|
||||
label={ __(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
|
||||
import {
|
||||
OrderSummary,
|
||||
TotalsCoupon,
|
||||
|
@ -14,6 +15,7 @@ import {
|
|||
TotalsTaxes,
|
||||
ExperimentalOrderMeta,
|
||||
} from '@woocommerce/blocks-checkout';
|
||||
|
||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||
import { useShippingDataContext } from '@woocommerce/base-context';
|
||||
import {
|
||||
|
@ -27,6 +29,7 @@ const CheckoutSidebar = ( {
|
|||
cartItems = [],
|
||||
cartFees = [],
|
||||
cartTotals = {},
|
||||
showRateAfterTaxName = false,
|
||||
} ) => {
|
||||
const {
|
||||
applyCoupon,
|
||||
|
@ -59,6 +62,13 @@ const CheckoutSidebar = ( {
|
|||
removeCoupon={ removeCoupon }
|
||||
values={ cartTotals }
|
||||
/>
|
||||
{ getSetting( 'couponsEnabled', true ) && (
|
||||
<TotalsCoupon
|
||||
onSubmit={ applyCoupon }
|
||||
initialOpen={ false }
|
||||
isLoading={ isApplyingCoupon }
|
||||
/>
|
||||
) }
|
||||
{ needsShipping && (
|
||||
<TotalsShipping
|
||||
showCalculator={ false }
|
||||
|
@ -70,16 +80,10 @@ const CheckoutSidebar = ( {
|
|||
{ ! getSetting( 'displayCartPricesIncludingTax', false ) && (
|
||||
<TotalsTaxes
|
||||
currency={ totalsCurrency }
|
||||
showRateAfterTaxName={ showRateAfterTaxName }
|
||||
values={ cartTotals }
|
||||
/>
|
||||
) }
|
||||
{ getSetting( 'couponsEnabled', true ) && (
|
||||
<TotalsCoupon
|
||||
onSubmit={ applyCoupon }
|
||||
initialOpen={ false }
|
||||
isLoading={ isApplyingCoupon }
|
||||
/>
|
||||
) }
|
||||
<TotalsFooterItem
|
||||
currency={ totalsCurrency }
|
||||
values={ cartTotals }
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Testing checkout sidebar Shows rate percentages after tax lines if the block is set to do so 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="wc-block-components-totals-item"
|
||||
>
|
||||
<span
|
||||
class="wc-block-components-totals-item__label"
|
||||
>
|
||||
Subtotal
|
||||
</span>
|
||||
<span
|
||||
class="wc-block-formatted-money-amount wc-block-components-formatted-money-amount wc-block-components-totals-item__value"
|
||||
>
|
||||
$24.00
|
||||
</span>
|
||||
<div
|
||||
class="wc-block-components-totals-item__description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="wc-block-components-totals-coupon wc-block-components-panel has-border"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
aria-expanded="false"
|
||||
class="wc-block-components-panel__button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="wc-block-components-panel__button-icon"
|
||||
focusable="false"
|
||||
height="24"
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17 9.4L12 14 7 9.4l-1 1.2 6 5.4 6-5.4z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
>
|
||||
Coupon code
|
||||
</span>
|
||||
<span
|
||||
class="screen-reader-text"
|
||||
>
|
||||
Apply a coupon code
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="wc-block-components-panel__content"
|
||||
hidden=""
|
||||
>
|
||||
<div
|
||||
class="wc-block-components-totals-coupon__content"
|
||||
>
|
||||
<form
|
||||
class="wc-block-components-totals-coupon__form"
|
||||
>
|
||||
<div
|
||||
class="wc-block-components-text-input wc-block-components-totals-coupon__input is-active"
|
||||
>
|
||||
<input
|
||||
aria-describedby="wc-block-components-totals-coupon__input-0"
|
||||
aria-label="Enter code"
|
||||
autocapitalize="off"
|
||||
autocomplete="off"
|
||||
id="wc-block-components-totals-coupon__input-0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="wc-block-components-totals-coupon__input-0"
|
||||
>
|
||||
Enter code
|
||||
</label>
|
||||
</div>
|
||||
<button
|
||||
class="components-button wc-block-components-button wc-block-components-totals-coupon__button"
|
||||
disabled=""
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="wc-block-components-button__text"
|
||||
>
|
||||
Apply
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="wc-block-components-totals-item wc-block-components-totals-taxes"
|
||||
>
|
||||
<span
|
||||
class="wc-block-components-totals-item__label"
|
||||
>
|
||||
Taxes
|
||||
</span>
|
||||
<span
|
||||
class="wc-block-formatted-money-amount wc-block-components-formatted-money-amount wc-block-components-totals-item__value"
|
||||
>
|
||||
$6.00
|
||||
</span>
|
||||
<div
|
||||
class="wc-block-components-totals-item__description"
|
||||
>
|
||||
<div
|
||||
class="wc-block-components-totals-item wc-block-components-totals-taxes__tax-line"
|
||||
>
|
||||
<span
|
||||
class="wc-block-components-totals-item__label"
|
||||
>
|
||||
Sales tax 20%
|
||||
</span>
|
||||
<div
|
||||
class="wc-block-components-totals-item__description"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="wc-block-components-totals-item wc-block-components-totals-footer-item"
|
||||
>
|
||||
<span
|
||||
class="wc-block-components-totals-item__label"
|
||||
>
|
||||
Total
|
||||
</span>
|
||||
<span
|
||||
class="wc-block-formatted-money-amount wc-block-components-formatted-money-amount wc-block-components-totals-item__value"
|
||||
>
|
||||
$30.00
|
||||
</span>
|
||||
<div
|
||||
class="wc-block-components-totals-item__description"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="wc-block-components-order-meta"
|
||||
/>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render } from '@testing-library/react';
|
||||
import { previewCart } from '@woocommerce/resource-previews';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { allSettings } from '../../../../../settings/shared/settings-init';
|
||||
import CheckoutSidebar from '../index';
|
||||
|
||||
describe( 'Testing checkout sidebar', () => {
|
||||
it( 'Shows rate percentages after tax lines if the block is set to do so', async () => {
|
||||
allSettings.displayCartPricesIncludingTax = false;
|
||||
allSettings.displayItemizedTaxes = true;
|
||||
const { totals: cartTotals, items: cartItems } = previewCart;
|
||||
const { container } = render(
|
||||
<CheckoutSidebar
|
||||
cartItems={ cartItems }
|
||||
cartTotals={ cartTotals }
|
||||
showRateAfterTaxName={ true }
|
||||
/>
|
||||
);
|
||||
expect( container ).toMatchSnapshot();
|
||||
// ["Components must be wrapped within `SlotFillProvider`. See https://developer.wordpress.org/block-editor/components/slot-fill/"]
|
||||
expect( console ).toHaveWarned();
|
||||
} );
|
||||
} );
|
|
@ -10,6 +10,12 @@
|
|||
// Required by IE11.
|
||||
flex-basis: 0;
|
||||
}
|
||||
.wc-block-components-totals-taxes,
|
||||
.wc-block-components-totals-footer-item {
|
||||
@include with-translucent-border(1px 0 0);
|
||||
margin: 0;
|
||||
padding: em($gap-small) 0;
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-checkout__actions {
|
||||
|
|
|
@ -11,6 +11,7 @@ import { getSetting } from '@woocommerce/settings';
|
|||
*/
|
||||
import { previewShippingRates } from './shipping-rates';
|
||||
|
||||
const displayWithTax = getSetting( 'displayCartPricesIncludingTax', false );
|
||||
// Sample data for cart block.
|
||||
// This closely resembles the data returned from the Store API /cart endpoint.
|
||||
// https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/src/RestApi/StoreApi#cart-api
|
||||
|
@ -66,14 +67,14 @@ export const previewCart: CartResponse = {
|
|||
currency_thousand_separator: ',',
|
||||
currency_prefix: '$',
|
||||
currency_suffix: '',
|
||||
price: '800',
|
||||
regular_price: '800',
|
||||
sale_price: '800',
|
||||
price: displayWithTax ? '800' : '640',
|
||||
regular_price: displayWithTax ? '800' : '640',
|
||||
sale_price: displayWithTax ? '800' : '640',
|
||||
raw_prices: {
|
||||
precision: 6,
|
||||
price: '8000000',
|
||||
regular_price: '8000000',
|
||||
sale_price: '8000000',
|
||||
price: displayWithTax ? '8000000' : '6400000',
|
||||
regular_price: displayWithTax ? '8000000' : '6400000',
|
||||
sale_price: displayWithTax ? '8000000' : '6400000',
|
||||
},
|
||||
},
|
||||
totals: {
|
||||
|
@ -84,10 +85,10 @@ export const previewCart: CartResponse = {
|
|||
currency_thousand_separator: ',',
|
||||
currency_prefix: '$',
|
||||
currency_suffix: '',
|
||||
line_subtotal: '1600',
|
||||
line_subtotal: displayWithTax ? '1600' : '1280',
|
||||
line_subtotal_tax: '0',
|
||||
line_total: '1600',
|
||||
line_total_tax: '0',
|
||||
line_total_tax: displayWithTax ? '0' : '320',
|
||||
},
|
||||
extensions: {},
|
||||
},
|
||||
|
@ -132,14 +133,14 @@ export const previewCart: CartResponse = {
|
|||
currency_thousand_separator: ',',
|
||||
currency_prefix: '$',
|
||||
currency_suffix: '',
|
||||
price: '1400',
|
||||
regular_price: '1600',
|
||||
sale_price: '1400',
|
||||
price: displayWithTax ? '1400' : '1120',
|
||||
regular_price: displayWithTax ? '1600' : '1280',
|
||||
sale_price: displayWithTax ? '1400' : '1120',
|
||||
raw_prices: {
|
||||
precision: 6,
|
||||
price: '14000000',
|
||||
regular_price: '16000000',
|
||||
sale_price: '14000000',
|
||||
price: displayWithTax ? '14000000' : '11200000',
|
||||
regular_price: displayWithTax ? '16000000' : '12800000',
|
||||
sale_price: displayWithTax ? '14000000' : '11200000',
|
||||
},
|
||||
},
|
||||
totals: {
|
||||
|
@ -150,10 +151,10 @@ export const previewCart: CartResponse = {
|
|||
currency_thousand_separator: ',',
|
||||
currency_prefix: '$',
|
||||
currency_suffix: '',
|
||||
line_subtotal: '1400',
|
||||
line_subtotal_tax: '0',
|
||||
line_subtotal: displayWithTax ? '1400' : '1120',
|
||||
line_subtotal_tax: displayWithTax ? '0' : '280',
|
||||
line_total: '1400',
|
||||
line_total_tax: '0',
|
||||
line_total_tax: displayWithTax ? '0' : '280',
|
||||
},
|
||||
extensions: {},
|
||||
},
|
||||
|
@ -197,7 +198,7 @@ export const previewCart: CartResponse = {
|
|||
currency_thousand_separator: ',',
|
||||
currency_prefix: '$',
|
||||
currency_suffix: '',
|
||||
total_items: '3000',
|
||||
total_items: displayWithTax ? '3000' : '2400',
|
||||
total_items_tax: '0',
|
||||
total_fees: '0',
|
||||
total_fees_tax: '0',
|
||||
|
@ -205,8 +206,14 @@ export const previewCart: CartResponse = {
|
|||
total_discount_tax: '0',
|
||||
total_shipping: '0',
|
||||
total_shipping_tax: '0',
|
||||
total_tax: '0',
|
||||
total_tax: '600',
|
||||
total_price: '3000',
|
||||
tax_lines: [],
|
||||
tax_lines: [
|
||||
{
|
||||
name: __( 'Sales tax', 'woo-gutenberg-products-block' ),
|
||||
rate: '20%',
|
||||
price: 600,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -157,6 +157,7 @@ export interface CartResponseItem {
|
|||
export interface CartResponseTotalsTaxLineItem {
|
||||
name: string;
|
||||
price: string;
|
||||
rate: string;
|
||||
}
|
||||
|
||||
export interface CartResponseFeeItemTotals extends CurrencyResponseInfo {
|
||||
|
|
|
@ -137,6 +137,7 @@ export interface CartItem {
|
|||
export interface CartTotalsTaxLineItem {
|
||||
name: string;
|
||||
price: string;
|
||||
rate: string;
|
||||
}
|
||||
|
||||
export interface CartFeeItemTotals extends CurrencyInfo {
|
||||
|
|
|
@ -12,6 +12,7 @@ import { ReactElement } from 'react';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import TotalsItem from '../item';
|
||||
import './style.scss';
|
||||
|
||||
interface Values {
|
||||
// eslint-disable-next-line camelcase
|
||||
|
@ -23,6 +24,7 @@ interface Values {
|
|||
interface TotalsTaxesProps {
|
||||
className?: string;
|
||||
currency: Currency;
|
||||
showRateAfterTaxName: boolean;
|
||||
values: Values | Record< string, never >;
|
||||
}
|
||||
|
||||
|
@ -30,6 +32,7 @@ const TotalsTaxes = ( {
|
|||
currency,
|
||||
values,
|
||||
className,
|
||||
showRateAfterTaxName,
|
||||
}: TotalsTaxesProps ): ReactElement | null => {
|
||||
const { total_tax: totalTax, tax_lines: taxLines } = values;
|
||||
|
||||
|
@ -37,8 +40,30 @@ const TotalsTaxes = ( {
|
|||
return null;
|
||||
}
|
||||
|
||||
if ( ! getSetting( 'displayItemizedTaxes', false ) ) {
|
||||
return (
|
||||
const itemisedTaxItems: ReactElement | null = getSetting(
|
||||
'displayItemizedTaxes',
|
||||
false
|
||||
) ? (
|
||||
<>
|
||||
{ taxLines.map( ( { name, rate }, i ) => {
|
||||
const label = `${ name }${
|
||||
showRateAfterTaxName ? ` ${ rate }` : ''
|
||||
}`;
|
||||
return (
|
||||
<TotalsItem
|
||||
key={ `tax-line-${ i }` }
|
||||
className="wc-block-components-totals-taxes__tax-line"
|
||||
currency={ currency }
|
||||
label={ label }
|
||||
value={ null }
|
||||
/>
|
||||
);
|
||||
} ) }{ ' ' }
|
||||
</>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TotalsItem
|
||||
className={ classnames(
|
||||
'wc-block-components-totals-taxes',
|
||||
|
@ -47,21 +72,8 @@ const TotalsTaxes = ( {
|
|||
currency={ currency }
|
||||
label={ __( 'Taxes', 'woo-gutenberg-products-block' ) }
|
||||
value={ parseInt( totalTax, 10 ) }
|
||||
description={ itemisedTaxItems }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{ taxLines.map( ( { name, price }, i ) => (
|
||||
<TotalsItem
|
||||
key={ `tax-line-${ i }` }
|
||||
className="wc-block-components-totals-taxes"
|
||||
currency={ currency }
|
||||
label={ name }
|
||||
value={ parseInt( price, 10 ) }
|
||||
/>
|
||||
) ) }{ ' ' }
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.wc-block-components-totals-item__description
|
||||
.wc-block-components-totals-item.wc-block-components-totals-taxes__tax-line {
|
||||
padding: 0;
|
||||
@include font-size(small);
|
||||
margin: $gap-smallest / 2;
|
||||
}
|
|
@ -120,6 +120,7 @@ class Cart extends AbstractBlock {
|
|||
);
|
||||
$this->asset_data_registry->add( 'baseLocation', wc_get_base_location(), true );
|
||||
$this->asset_data_registry->add( 'isShippingCalculatorEnabled', filter_var( get_option( 'woocommerce_enable_shipping_calc' ), FILTER_VALIDATE_BOOLEAN ), true );
|
||||
$this->asset_data_registry->add( 'displayItemizedTaxes', 'itemized' === get_option( 'woocommerce_tax_total_display' ), true );
|
||||
$this->asset_data_registry->add( 'displayCartPricesIncludingTax', 'incl' === get_option( 'woocommerce_tax_display_cart' ), true );
|
||||
$this->asset_data_registry->add( 'taxesEnabled', wc_tax_enabled(), true );
|
||||
$this->asset_data_registry->add( 'couponsEnabled', wc_coupons_enabled(), true );
|
||||
|
|
|
@ -3,6 +3,7 @@ namespace Automattic\WooCommerce\Blocks\StoreApi\Schemas;
|
|||
|
||||
use Automattic\WooCommerce\Blocks\StoreApi\Utilities\CartController;
|
||||
use Automattic\WooCommerce\Blocks\Domain\Services\ExtendRestApi;
|
||||
use WC_Tax;
|
||||
use WP_Error;
|
||||
|
||||
|
||||
|
@ -287,6 +288,12 @@ class CartSchema extends AbstractSchema {
|
|||
'context' => [ 'view', 'edit' ],
|
||||
'readonly' => true,
|
||||
],
|
||||
'rate' => [
|
||||
'description' => __( 'The rate at which tax is applied.', 'woo-gutenberg-products-block' ),
|
||||
'type' => 'string',
|
||||
'context' => [ 'view', 'edit' ],
|
||||
'readonly' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
@ -389,6 +396,7 @@ class CartSchema extends AbstractSchema {
|
|||
$tax_lines[] = array(
|
||||
'name' => $cart_tax_total->label,
|
||||
'price' => $this->prepare_money_response( $cart_tax_total->amount, wc_get_price_decimals() ),
|
||||
'rate' => WC_Tax::get_rate_percent( $cart_tax_total->tax_rate_id ),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -739,10 +739,10 @@ class CartController {
|
|||
$index > 1 ?
|
||||
sprintf(
|
||||
/* translators: %d: shipping package number */
|
||||
_x( 'Shipping %d', 'shipping packages', 'woo-gutenberg-products-block' ),
|
||||
_x( 'Shipping method %d', 'shipping packages', 'woo-gutenberg-products-block' ),
|
||||
$index
|
||||
) :
|
||||
_x( 'Shipping', 'shipping packages', 'woo-gutenberg-products-block' ),
|
||||
_x( 'Shipping method', 'shipping packages', 'woo-gutenberg-products-block' ),
|
||||
$package['package_id'],
|
||||
$package
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue