Add subtotal to cart and checkout and update the CartLineItem component with new styles (https://github.com/woocommerce/woocommerce-blocks/pull/3734)

* Create new vars to differentiate between single and multiple item price

This is because we need to display the subtotal of the item AND the total (subtotal * quantity)

* Add subtotal and move quantity picker

As per the new designs, the quantity picker should be moved below the product metadata, and the product subtotals should appear below the product name.

* Move line item total to top of grid on mobile/medium/small

* Remove CSS for trash icon that is no longer used.

* Remove link style colour override from product name and make total bold

* Remove quantity column from CartLineItem

This is because the quantity picker is now displayed below the product metadata and name.

* Fix margins around quantity picker and its width

* Always disable link to product in OrderSummaryItem

* Add single price below product name in OrderSummaryItem

* Add styles for new OrderItemSummary design

* Move total into its own "column"

This is to stop product description text flowing under the total and making it look untidy.

* Add styles to cater for total price being its own column

* Convert precision after multiplication instead of before

* Remove unnecessary div from OrderSummaryItem

* Remove line height from product names on order summary

* Add more margin to the bottom of the product metadata div

* Delete trash icon

* Only remove margin from the bottom of last product-details

* Move quantity input to below product name in cart skeleton

* Add placeholder for individual price to Cart skeleton
This commit is contained in:
Thomas Roberts 2021-01-27 11:34:59 +00:00 committed by GitHub
parent dfac8d7ca7
commit 49a56e27ee
11 changed files with 151 additions and 148 deletions

View File

@ -20,7 +20,6 @@ import ProductMetadata from '../product-metadata';
const OrderSummaryItem = ( { cartItem } ) => { const OrderSummaryItem = ( { cartItem } ) => {
const { const {
images, images,
catalog_visibility: catalogVisibility = '',
low_stock_remaining: lowStockRemaining = null, low_stock_remaining: lowStockRemaining = null,
show_backorder_badge: showBackorderBadge = false, show_backorder_badge: showBackorderBadge = false,
name, name,
@ -34,15 +33,23 @@ const OrderSummaryItem = ( { cartItem } ) => {
} = cartItem; } = cartItem;
const currency = getCurrency( prices ); const currency = getCurrency( prices );
const linePrice = Dinero( { const regularPriceSingle = Dinero( {
amount: parseInt( prices.raw_prices.price, 10 ), amount: parseInt( prices.raw_prices.regular_price, 10 ),
precision: parseInt( prices.raw_prices.precision, 10 ), precision: parseInt( prices.raw_prices.precision, 10 ),
} ) } )
.convertPrecision( currency.minorUnit )
.getAmount();
const unconvertedLinePrice = Dinero( {
amount: parseInt( prices.raw_prices.price, 10 ),
precision: parseInt( prices.raw_prices.precision, 10 ),
} );
const linePriceSingle = unconvertedLinePrice
.convertPrecision( currency.minorUnit )
.getAmount();
const linePrice = unconvertedLinePrice
.multiply( quantity ) .multiply( quantity )
.convertPrecision( currency.minorUnit ) .convertPrecision( currency.minorUnit )
.getAmount(); .getAmount();
const isProductHiddenFromCatalog =
catalogVisibility === 'hidden' || catalogVisibility === 'search';
return ( return (
<div className="wc-block-components-order-summary-item"> <div className="wc-block-components-order-summary-item">
@ -60,18 +67,19 @@ const OrderSummaryItem = ( { cartItem } ) => {
<ProductImage image={ images.length ? images[ 0 ] : {} } /> <ProductImage image={ images.length ? images[ 0 ] : {} } />
</div> </div>
<div className="wc-block-components-order-summary-item__description"> <div className="wc-block-components-order-summary-item__description">
<div className="wc-block-components-order-summary-item__header"> <ProductName
<ProductName disabled={ true }
disabled={ isProductHiddenFromCatalog } name={ name }
name={ name } permalink={ permalink }
permalink={ permalink } />
/> <ProductPrice
<ProductPrice currency={ currency }
currency={ currency } price={ linePriceSingle }
price={ linePrice } regularPrice={ regularPriceSingle }
priceClassName="wc-block-components-order-summary-item__total-price" className="wc-block-components-order-summary-item__individual-prices"
/> priceClassName="wc-block-components-order-summary-item__individual-price"
</div> regularPriceClassName="wc-block-components-order-summary-item__regular-individual-price"
/>
{ showBackorderBadge ? ( { showBackorderBadge ? (
<ProductBackorderBadge /> <ProductBackorderBadge />
) : ( ) : (
@ -88,6 +96,9 @@ const OrderSummaryItem = ( { cartItem } ) => {
variation={ variation } variation={ variation }
/> />
</div> </div>
<div className="wc-block-components-order-summary-item__total-price">
<ProductPrice currency={ currency } price={ linePrice } />
</div>
</div> </div>
); );
}; };

View File

@ -12,8 +12,10 @@
.wc-block-components-order-summary-item { .wc-block-components-order-summary-item {
@include with-translucent-border(0 0 1px); @include with-translucent-border(0 0 1px);
display: table-row; @include font-size(small);
display: flex;
padding-bottom: 1px; padding-bottom: 1px;
padding-top: $gap;
width: 100%; width: 100%;
&:last-child { &:last-child {
@ -25,6 +27,10 @@
display: none; display: none;
} }
} }
.wc-block-components-product-metadata {
@include font-size(regular);
}
} }
.wc-block-components-order-summary-item__image, .wc-block-components-order-summary-item__image,
@ -35,7 +41,6 @@
.wc-block-components-order-summary-item__image { .wc-block-components-order-summary-item__image {
width: #{$gap-large * 2}; width: #{$gap-large * 2};
padding-top: $gap;
padding-bottom: $gap; padding-bottom: $gap;
position: relative; position: relative;
@ -46,7 +51,6 @@
} }
.wc-block-components-order-summary-item__quantity { .wc-block-components-order-summary-item__quantity {
@include font-size(smaller);
align-items: center; align-items: center;
background: #fff; background: #fff;
border: 2px solid; border: 2px solid;
@ -69,9 +73,7 @@
.wc-block-components-order-summary-item__description { .wc-block-components-order-summary-item__description {
padding-left: $gap-large; padding-left: $gap-large;
padding-top: $gap;
padding-bottom: $gap; padding-bottom: $gap;
line-height: 1.375;
p, p,
.wc-block-components-product-metadata { .wc-block-components-product-metadata {
@ -80,8 +82,12 @@
} }
} }
.wc-block-components-order-summary-item__header { .wc-block-components-order-summary-item__total-price {
display: flex; font-weight: bold;
flex-wrap: wrap; margin-left: auto;
justify-content: space-between; }
.wc-block-components-order-summary-item__individual-prices {
display: block;
} }

View File

@ -3,6 +3,10 @@
list-style: none; list-style: none;
margin: 0.5em 0; margin: 0.5em 0;
padding: 0; padding: 0;
&:last-of-type {
margin-bottom: 0;
}
} }
.wc-block-components-product-details__name, .wc-block-components-product-details__name,

View File

@ -3,6 +3,6 @@
.wc-block-components-product-metadata__description > p, .wc-block-components-product-metadata__description > p,
.wc-block-components-product-metadata__variation-data { .wc-block-components-product-metadata__variation-data {
margin: 0.25em 0 0 0; margin: 0.25em 0;
} }
} }

View File

@ -12,12 +12,13 @@
.wc-block-components-quantity-selector { .wc-block-components-quantity-selector {
display: flex; display: flex;
min-width: 100px; width: 107px;
border: 1px solid $gray-300; border: 1px solid $gray-300;
background: #fff; background: #fff;
border-radius: 4px; border-radius: 4px;
// needed so that buttons fill the container. // needed so that buttons fill the container.
box-sizing: content-box; box-sizing: content-box;
margin: 0 0 0.25em 0;
.has-dark-controls & { .has-dark-controls & {
background-color: transparent; background-color: transparent;

View File

@ -8,7 +8,6 @@ import QuantitySelector from '@woocommerce/base-components/quantity-selector';
import ProductPrice from '@woocommerce/base-components/product-price'; import ProductPrice from '@woocommerce/base-components/product-price';
import ProductName from '@woocommerce/base-components/product-name'; import ProductName from '@woocommerce/base-components/product-name';
import { useStoreCartItemQuantity } from '@woocommerce/base-hooks'; import { useStoreCartItemQuantity } from '@woocommerce/base-hooks';
import { Icon, trash } from '@woocommerce/icons';
import { import {
ProductBackorderBadge, ProductBackorderBadge,
ProductImage, ProductImage,
@ -82,14 +81,19 @@ const CartLineItemRow = ( { lineItem = {} } ) => {
} = useStoreCartItemQuantity( lineItem ); } = useStoreCartItemQuantity( lineItem );
const currency = getCurrency( prices ); const currency = getCurrency( prices );
const regularAmount = Dinero( { const regularAmountSingle = Dinero( {
amount: parseInt( prices.raw_prices.regular_price, 10 ), amount: parseInt( prices.raw_prices.regular_price, 10 ),
precision: parseInt( prices.raw_prices.precision, 10 ), precision: parseInt( prices.raw_prices.precision, 10 ),
} ).multiply( quantity ); } );
const purchaseAmount = Dinero( { const purchaseAmountSingle = Dinero( {
amount: parseInt( prices.raw_prices.price, 10 ), amount: parseInt( prices.raw_prices.price, 10 ),
precision: parseInt( prices.raw_prices.precision, 10 ), precision: parseInt( prices.raw_prices.precision, 10 ),
} ).multiply( quantity ); } );
const regularAmount = regularAmountSingle.multiply( quantity );
const purchaseAmount = purchaseAmountSingle.multiply( quantity );
const saleAmountSingle = regularAmountSingle.subtract(
purchaseAmountSingle
);
const saleAmount = regularAmount.subtract( purchaseAmount ); const saleAmount = regularAmount.subtract( purchaseAmount );
const firstImage = images.length ? images[ 0 ] : {}; const firstImage = images.length ? images[ 0 ] : {};
const isProductHiddenFromCatalog = const isProductHiddenFromCatalog =
@ -130,51 +134,68 @@ const CartLineItemRow = ( { lineItem = {} } ) => {
/> />
) )
) } ) }
<div className="wc-block-cart-item__prices">
<ProductPrice
currency={ currency }
regularPrice={ getAmountFromRawPrice(
regularAmountSingle,
currency
) }
price={ getAmountFromRawPrice(
purchaseAmountSingle,
currency
) }
/>
</div>
<ProductSaleBadge
currency={ currency }
saleAmount={ getAmountFromRawPrice(
saleAmountSingle,
currency
) }
/>
<ProductMetadata <ProductMetadata
shortDescription={ shortDescription } shortDescription={ shortDescription }
fullDescription={ fullDescription } fullDescription={ fullDescription }
itemData={ itemData } itemData={ itemData }
variation={ variation } variation={ variation }
/> />
</td>
<td className="wc-block-cart-item__quantity"> <div className="wc-block-cart-item__quantity">
<QuantitySelector <QuantitySelector
disabled={ isPendingDelete } disabled={ isPendingDelete }
quantity={ quantity } quantity={ quantity }
maximum={ quantityLimit } maximum={ quantityLimit }
onChange={ changeQuantity } onChange={ changeQuantity }
itemName={ name } itemName={ name }
/> />
<button <button
className="wc-block-cart-item__remove-link" className="wc-block-cart-item__remove-link"
onClick={ removeItem } onClick={ removeItem }
disabled={ isPendingDelete } disabled={ isPendingDelete }
> >
{ __( 'Remove item', 'woo-gutenberg-products-block' ) }
</button>
<button
className="wc-block-cart-item__remove-icon"
onClick={ removeItem }
>
<span className="screen-reader-text">
{ __( 'Remove item', 'woo-gutenberg-products-block' ) } { __( 'Remove item', 'woo-gutenberg-products-block' ) }
</span> </button>
<Icon srcElement={ trash } /> </div>
</button>
</td> </td>
<td className="wc-block-cart-item__total"> <td className="wc-block-cart-item__total">
<ProductPrice <ProductPrice
currency={ currency } currency={ currency }
regularPrice={ getAmountFromRawPrice(
regularAmount,
currency
) }
price={ getAmountFromRawPrice( purchaseAmount, currency ) } price={ getAmountFromRawPrice( purchaseAmount, currency ) }
/> />
<ProductSaleBadge
currency={ currency } { quantity > 1 && (
saleAmount={ getAmountFromRawPrice( saleAmount, currency ) } <ProductSaleBadge
/> currency={ currency }
saleAmount={ getAmountFromRawPrice(
saleAmount,
currency
) }
/>
) }
</td> </td>
</tr> </tr>
); );

View File

@ -39,11 +39,6 @@ const CartLineItemsTable = ( { lineItems = [], isLoading = false } ) => {
{ __( 'Details', 'woo-gutenberg-products-block' ) } { __( 'Details', 'woo-gutenberg-products-block' ) }
</span> </span>
</th> </th>
<th className="wc-block-cart-items__header-quantity">
<span>
{ __( 'Quantity', 'woo-gutenberg-products-block' ) }
</span>
</th>
<th className="wc-block-cart-items__header-total"> <th className="wc-block-cart-items__header-total">
<span> <span>
{ __( 'Total', 'woo-gutenberg-products-block' ) } { __( 'Total', 'woo-gutenberg-products-block' ) }

View File

@ -3,9 +3,6 @@
white-space: nowrap; white-space: nowrap;
} }
.wc-block-components-product-name {
color: inherit;
}
.wc-block-components-address-form { .wc-block-components-address-form {
.wc-block-components-text-input, .wc-block-components-text-input,
.wc-block-components-country-input, .wc-block-components-country-input,
@ -64,15 +61,6 @@ table.wc-block-cart-items {
text-transform: none; text-transform: none;
white-space: nowrap; white-space: nowrap;
} }
.wc-block-cart-item__remove-icon {
@include link-button;
fill: currentColor;
position: absolute;
top: $gap;
right: 0;
display: none;
}
} }
.wc-block-components-product-name { .wc-block-components-product-name {
display: block; display: block;
@ -86,8 +74,12 @@ table.wc-block-cart-items {
.wc-block-components-product-price__regular, .wc-block-components-product-price__regular,
.wc-block-components-product-price__value { .wc-block-components-product-price__value {
display: block; display: block;
font-weight: bold;
} }
} }
.wc-block-components-product-metadata {
margin-bottom: 0.75em;
}
&.is-disabled { &.is-disabled {
opacity: 0.5; opacity: 0.5;
@ -112,6 +104,7 @@ table.wc-block-cart-items {
.wc-block-cart-items { .wc-block-cart-items {
.wc-block-cart-items__row { .wc-block-cart-items__row {
.wc-block-cart-item__price, .wc-block-cart-item__price,
.wc-block-cart-item__individual-price,
.wc-block-cart-item__product-metadata, .wc-block-cart-item__product-metadata,
.wc-block-cart-item__image > *, .wc-block-cart-item__image > *,
.wc-block-components-quantity-selector { .wc-block-components-quantity-selector {
@ -127,13 +120,18 @@ table.wc-block-cart-items {
margin-top: 0.25em; margin-top: 0.25em;
min-width: 8em; min-width: 8em;
} }
.wc-block-cart-item__remove-link, .wc-block-cart-item__remove-link {
.wc-block-cart-item__remove-icon {
visibility: hidden; visibility: hidden;
} }
.wc-block-cart-item__image a { .wc-block-cart-item__image a {
display: block; display: block;
} }
.wc-block-cart-item__individual-price {
@include force-content();
max-width: 3em;
display: block;
margin-top: 0.25em;
}
.wc-block-cart-item__total { .wc-block-cart-item__total {
> span, > span,
> div { > div {
@ -192,10 +190,9 @@ table.wc-block-cart-items {
} }
.wc-block-cart-item__product { .wc-block-cart-item__product {
grid-column-start: 2; grid-column-start: 2;
grid-column-end: 4; grid-column-end: 3;
grid-row-start: 1; grid-row-start: 1;
justify-self: stretch; justify-self: stretch;
margin-right: 24px;
padding-bottom: $gap; padding-bottom: $gap;
} }
.wc-block-cart-item__quantity { .wc-block-cart-item__quantity {
@ -205,20 +202,9 @@ table.wc-block-cart-items {
padding-right: $gap; padding-right: $gap;
align-self: end; align-self: end;
padding-top: $gap; padding-top: $gap;
.wc-block-cart-item__remove-link {
display: none;
}
.wc-block-cart-item__remove-icon {
display: block;
}
} }
.wc-block-cart-item__total { .wc-block-cart-item__total {
grid-column: 2 / span 2; grid-row-start: 1;
grid-row-start: 2;
align-self: end;
justify-self: end;
padding-bottom: 0.375em;
.wc-block-components-formatted-money-amount { .wc-block-components-formatted-money-amount {
display: inline-block; display: inline-block;

View File

@ -42,7 +42,6 @@ export { default as tag } from './library/tag';
export { default as tags } from './library/tags'; export { default as tags } from './library/tags';
export { default as thumbUp } from './library/thumb-up'; export { default as thumbUp } from './library/thumb-up';
export { default as toggle } from './library/toggle'; export { default as toggle } from './library/toggle';
export { default as trash } from './library/trash';
export { default as truck } from './library/truck'; export { default as truck } from './library/truck';
export { default as widgets } from './library/widgets'; export { default as widgets } from './library/widgets';
export { default as woo } from './library/woo'; export { default as woo } from './library/woo';

View File

@ -1,16 +0,0 @@
/**
* External dependencies
*/
import { SVG } from 'wordpress-components';
// This uses `delete_outline` icon from Material.
// https://material.io/resources/icons/?icon=delete_outline&style=baseline
// We are using it as `trash` or `trashcan` or `remove-item`.
const trash = (
<SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM8 9h8v10H8V9zm7.5-5l-1-1h-5l-1 1H5v2h14V4z" />
<path fill="none" d="M0 0h24v24H0V0z" />
</SVG>
);
export default trash;

View File

@ -148,7 +148,6 @@ class Cart extends AbstractBlock {
<tr class="wc-block-cart-items__header"> <tr class="wc-block-cart-items__header">
<th class="wc-block-cart-items__header-image"><span /></th> <th class="wc-block-cart-items__header-image"><span /></th>
<th class="wc-block-cart-items__header-product"><span /></th> <th class="wc-block-cart-items__header-product"><span /></th>
<th class="wc-block-cart-items__header-quantity"><span /></th>
<th class="wc-block-cart-items__header-total"><span /></th> <th class="wc-block-cart-items__header-total"><span /></th>
</tr> </tr>
</thead> </thead>
@ -159,33 +158,13 @@ class Cart extends AbstractBlock {
</td> </td>
<td class="wc-block-cart-item__product"> <td class="wc-block-cart-item__product">
<div class="wc-block-cart-item__product-name"></div> <div class="wc-block-cart-item__product-name"></div>
<div class="wc-block-cart-item__individual-price"></div>
<div class="wc-block-cart-item__product-metadata"></div> <div class="wc-block-cart-item__product-metadata"></div>
</td> <div class="wc-block-components-quantity-selector">
<td class="wc-block-cart-item__quantity"> <input class="wc-block-components-quantity-selector__input" type="number" step="1" min="0" value="1" />
<div class="wc-block-components-quantity-selector"> <button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--minus"></button>
<input class="wc-block-components-quantity-selector__input" type="number" step="1" min="0" value="1" /> <button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--plus"></button>
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--minus"></button> </div>
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--plus"></button>
</div>
</td>
<td class="wc-block-cart-item__total">
<div class="wc-block-cart-item__price"></div>
</td>
</tr>
<tr class="wc-block-cart-items__row">
<td class="wc-block-cart-item__image">
<div><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=" width="1" height="1" /></div>
</td>
<td class="wc-block-cart-item__product">
<div class="wc-block-cart-item__product-name">&nbsp;</div>
<div class="wc-block-cart-item__product-metadata">&nbsp;</div>
</td>
<td class="wc-block-cart-item__quantity">
<div class="wc-block-components-quantity-selector">
<input class="wc-block-components-quantity-selector__input" type="number" step="1" min="0" value="1" />
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--minus"></button>
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--plus"></button>
</div>
</td> </td>
<td class="wc-block-cart-item__total"> <td class="wc-block-cart-item__total">
<div class="wc-block-cart-item__price"></div> <div class="wc-block-cart-item__price"></div>
@ -197,14 +176,31 @@ class Cart extends AbstractBlock {
</td> </td>
<td class="wc-block-cart-item__product"> <td class="wc-block-cart-item__product">
<div class="wc-block-cart-item__product-name"></div> <div class="wc-block-cart-item__product-name"></div>
<div class="wc-block-cart-item__individual-price"></div>
<div class="wc-block-cart-item__product-metadata"></div> <div class="wc-block-cart-item__product-metadata"></div>
<div class="wc-block-components-quantity-selector">
<input class="wc-block-components-quantity-selector__input" type="number" step="1" min="0" value="1" />
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--minus"></button>
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--plus"></button>
</div>
</td> </td>
<td class="wc-block-cart-item__quantity"> <td class="wc-block-cart-item__total">
<div class="wc-block-components-quantity-selector"> <div class="wc-block-cart-item__price"></div>
<input class="wc-block-components-quantity-selector__input" type="number" step="1" min="0" value="1" /> </td>
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--minus"></button> </tr>
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--plus"></button> <tr class="wc-block-cart-items__row">
</div> <td class="wc-block-cart-item__image">
<div><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=" width="1" height="1" /></div>
</td>
<td class="wc-block-cart-item__product">
<div class="wc-block-cart-item__product-name"></div>
<div class="wc-block-cart-item__individual-price"></div>
<div class="wc-block-cart-item__product-metadata"></div>
<div class="wc-block-components-quantity-selector">
<input class="wc-block-components-quantity-selector__input" type="number" step="1" min="0" value="1" />
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--minus"></button>
<button class="wc-block-components-quantity-selector__button wc-block-components-quantity-selector__button--plus"></button>
</div>
</td> </td>
<td class="wc-block-cart-item__total"> <td class="wc-block-cart-item__total">
<div class="wc-block-cart-item__price"></div> <div class="wc-block-cart-item__price"></div>