* Show backorder notice in the Cart block

* Don't render variation <div> if empty

* Create ProductBackorderNotification component

* Add product backorder notification to the checkout block

* Fix classname and comment

* Rename notification->badge and don't show low stock badge if backorder is shown

* Use ternary to dispaly backorder/low stock badge
This commit is contained in:
Albert Juhé Lluveras 2020-07-14 17:25:53 +02:00 committed by GitHub
parent be513c8875
commit d894fed1df
16 changed files with 134 additions and 52 deletions

View File

@ -4,6 +4,7 @@ export { default as FormStep } from './form-step';
export { default as OrderSummary } from './order-summary'; export { default as OrderSummary } from './order-summary';
export { default as PlaceOrderButton } from './place-order-button'; export { default as PlaceOrderButton } from './place-order-button';
export { default as Policies } from './policies'; export { default as Policies } from './policies';
export { default as ProductBackorderBadge } from './product-backorder-badge';
export { default as ProductImage } from './product-image'; export { default as ProductImage } from './product-image';
export { default as ProductLowStockBadge } from './product-low-stock-badge'; export { default as ProductLowStockBadge } from './product-low-stock-badge';
export { default as ProductSummary } from './product-summary'; export { default as ProductSummary } from './product-summary';

View File

@ -5,6 +5,7 @@ import { __, sprintf } from '@wordpress/i18n';
import { getCurrency } from '@woocommerce/base-utils'; import { getCurrency } from '@woocommerce/base-utils';
import Label from '@woocommerce/base-components/label'; import Label from '@woocommerce/base-components/label';
import { import {
ProductBackorderBadge,
ProductImage, ProductImage,
ProductLowStockBadge, ProductLowStockBadge,
ProductMetadata, ProductMetadata,
@ -18,6 +19,7 @@ const OrderSummaryItem = ( { cartItem } ) => {
const { const {
images, images,
low_stock_remaining: lowStockRemaining = null, low_stock_remaining: lowStockRemaining = null,
show_backorder_badge: showBackorderBadge = false,
name, name,
permalink, permalink,
prices, prices,
@ -60,7 +62,15 @@ const OrderSummaryItem = ( { cartItem } ) => {
value={ linePrice } value={ linePrice }
/> />
</div> </div>
<ProductLowStockBadge lowStockRemaining={ lowStockRemaining } /> { showBackorderBadge ? (
<ProductBackorderBadge />
) : (
lowStockRemaining && (
<ProductLowStockBadge
lowStockRemaining={ lowStockRemaining }
/>
)
) }
<ProductMetadata <ProductMetadata
shortDescription={ shortDescription } shortDescription={ shortDescription }
fullDescription={ fullDescription } fullDescription={ fullDescription }

View File

@ -0,0 +1,22 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import ProductBadge from '../product-badge';
/**
* Returns a backorder badge.
*/
const ProductBackorderBadge = () => {
return (
<ProductBadge className="wc-block-components-product-backorder-badge">
{ __( 'Available on backorder', 'woo-gutenberg-products-block' ) }
</ProductBadge>
);
};
export default ProductBackorderBadge;

View File

@ -0,0 +1,29 @@
/**
* External dependencies
*/
import classNames from 'classnames';
import PropTypes from 'prop-types';
/**
* Internal dependencies
*/
import './style.scss';
const ProductBadge = ( { children, className } ) => {
return (
<div
className={ classNames(
'wc-block-components-product-badge',
className
) }
>
{ children }
</div>
);
};
ProductBadge.propTypes = {
className: PropTypes.string,
};
export default ProductBadge;

View File

@ -1,4 +1,4 @@
.wc-block-components-sale-badge { .wc-block-components-product-badge {
@include font-size(smaller); @include font-size(smaller);
border-radius: 2px; border-radius: 2px;
border: 1px solid; border: 1px solid;

View File

@ -7,7 +7,7 @@ import PropTypes from 'prop-types';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import './style.scss'; import ProductBadge from '../product-badge';
/** /**
* Returns a low stock badge. * Returns a low stock badge.
@ -18,13 +18,13 @@ const ProductLowStockBadge = ( { lowStockRemaining } ) => {
} }
return ( return (
<div className="wc-block-components-product-low-stock-badge"> <ProductBadge className="wc-block-components-product-low-stock-badge">
{ sprintf( { sprintf(
/* translators: %d stock amount (number of items in stock for product) */ /* translators: %d stock amount (number of items in stock for product) */
__( '%d left in stock', 'woo-gutenberg-products-block' ), __( '%d left in stock', 'woo-gutenberg-products-block' ),
lowStockRemaining lowStockRemaining
) } ) }
</div> </ProductBadge>
); );
}; };

View File

@ -1,10 +0,0 @@
.wc-block-components-product-low-stock-badge {
@include font-size(smaller);
border-radius: 2px;
border: 1px solid;
display: inline-block;
font-weight: 600;
padding: 0 0.66em;
text-transform: uppercase;
white-space: nowrap;
}

View File

@ -9,7 +9,7 @@ import PropTypes from 'prop-types';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import './style.scss'; import ProductBadge from '../product-badge';
/** /**
* ProductSaleBadge * ProductSaleBadge
@ -25,7 +25,7 @@ const ProductSaleBadge = ( { currency, saleAmount } ) => {
return null; return null;
} }
return ( return (
<div className="wc-block-components-sale-badge"> <ProductBadge className="wc-block-components-sale-badge">
{ __experimentalCreateInterpolateElement( { __experimentalCreateInterpolateElement(
/* translators: <price/> will be replaced by the discount amount */ /* translators: <price/> will be replaced by the discount amount */
__( 'Save <price/>', 'woo-gutenberg-products-block' ), __( 'Save <price/>', 'woo-gutenberg-products-block' ),
@ -38,7 +38,7 @@ const ProductSaleBadge = ( { currency, saleAmount } ) => {
), ),
} }
) } ) }
</div> </ProductBadge>
); );
}; };

View File

@ -9,7 +9,7 @@ import classNames from 'classnames';
* Returns a formatted element containing variation details. * Returns a formatted element containing variation details.
*/ */
const ProductVariationData = ( { className, variation = [] } ) => { const ProductVariationData = ( { className, variation = [] } ) => {
if ( ! variation ) { if ( ! variation || variation.length === 0 ) {
return null; return null;
} }

View File

@ -9,6 +9,7 @@ import { getCurrency } from '@woocommerce/base-utils';
import { useStoreCartItemQuantity } from '@woocommerce/base-hooks'; import { useStoreCartItemQuantity } from '@woocommerce/base-hooks';
import { Icon, trash } from '@woocommerce/icons'; import { Icon, trash } from '@woocommerce/icons';
import { import {
ProductBackorderBadge,
ProductImage, ProductImage,
ProductLowStockBadge, ProductLowStockBadge,
ProductMetadata, ProductMetadata,
@ -45,6 +46,7 @@ const CartLineItemRow = ( { lineItem = {} } ) => {
short_description: shortDescription = '', short_description: shortDescription = '',
description: fullDescription = '', description: fullDescription = '',
low_stock_remaining: lowStockRemaining = null, low_stock_remaining: lowStockRemaining = null,
show_backorder_badge: showBackorderBadge = false,
quantity_limit: quantityLimit = 99, quantity_limit: quantityLimit = 99,
permalink = '', permalink = '',
images = [], images = [],
@ -111,7 +113,16 @@ const CartLineItemRow = ( { lineItem = {} } ) => {
name={ name } name={ name }
disabled={ isPendingDelete } disabled={ isPendingDelete }
/> />
<ProductLowStockBadge lowStockRemaining={ lowStockRemaining } /> { showBackorderBadge ? (
<ProductBackorderBadge />
) : (
lowStockRemaining && (
<ProductLowStockBadge
lowStockRemaining={ lowStockRemaining }
/>
)
) }
{ showBackorderBadge && <ProductBackorderBadge /> }
<ProductMetadata <ProductMetadata
shortDescription={ shortDescription } shortDescription={ shortDescription }
fullDescription={ fullDescription } fullDescription={ fullDescription }

View File

@ -35,6 +35,7 @@ export const previewCart = {
permalink: 'https://example.org', permalink: 'https://example.org',
low_stock_remaining: 2, low_stock_remaining: 2,
backorders_allowed: false, backorders_allowed: false,
show_backorder_badge: false,
sold_individually: false, sold_individually: false,
images: [ images: [
{ {
@ -103,6 +104,7 @@ export const previewCart = {
sku: 'woo-cap', sku: 'woo-cap',
permalink: 'https://example.org', permalink: 'https://example.org',
backorders_allowed: false, backorders_allowed: false,
show_backorder_badge: false,
sold_individually: false, sold_individually: false,
images: [ images: [
{ {

View File

@ -143,6 +143,10 @@
* @property {boolean} backorders_allowed True if backorders are * @property {boolean} backorders_allowed True if backorders are
* allowed past stock * allowed past stock
* availability. * availability.
* @property {boolean} show_backorder_badge Whether a notification
* should be shown about the
* product being available on
* backorder.
* @property {boolean} sold_individually If true, only one item of * @property {boolean} sold_individually If true, only one item of
* this product is allowed * this product is allowed
* for purchase in a single * for purchase in a single

View File

@ -105,6 +105,12 @@ class CartItemSchema extends ProductSchema {
'context' => [ 'view', 'edit' ], 'context' => [ 'view', 'edit' ],
'readonly' => true, 'readonly' => true,
], ],
'show_backorder_badge' => [
'description' => __( 'True if the product is on backorder.', 'woo-gutenberg-products-block' ),
'type' => [ 'boolean' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'sold_individually' => [ 'sold_individually' => [
'description' => __( 'If true, only one item of this product is allowed for purchase in a single order.', 'woo-gutenberg-products-block' ), 'description' => __( 'If true, only one item of this product is allowed for purchase in a single order.', 'woo-gutenberg-products-block' ),
'type' => 'boolean', 'type' => 'boolean',
@ -290,6 +296,7 @@ class CartItemSchema extends ProductSchema {
'sku' => $this->prepare_html_response( $product->get_sku() ), 'sku' => $this->prepare_html_response( $product->get_sku() ),
'low_stock_remaining' => $this->get_low_stock_remaining( $product ), 'low_stock_remaining' => $this->get_low_stock_remaining( $product ),
'backorders_allowed' => (bool) $product->backorders_allowed(), 'backorders_allowed' => (bool) $product->backorders_allowed(),
'show_backorder_badge' => (bool) $product->backorders_require_notification() && $product->is_on_backorder( $cart_item['quantity'] ),
'sold_individually' => $product->is_sold_individually(), 'sold_individually' => $product->is_sold_individually(),
'permalink' => $product->get_permalink(), 'permalink' => $product->get_permalink(),
'images' => $this->get_images( $product ), 'images' => $this->get_images( $product ),

View File

@ -35,6 +35,7 @@ curl "https://example-store.com/wp-json/wc/store/cart/items"
"sku": "woo-beanie", "sku": "woo-beanie",
"low_stock_remaining": null, "low_stock_remaining": null,
"backorders_allowed": false, "backorders_allowed": false,
"show_backorder_badge": false,
"sold_individually": false, "sold_individually": false,
"permalink": "https:\/\/local.wordpress.test\/product\/beanie\/", "permalink": "https:\/\/local.wordpress.test\/product\/beanie\/",
"images": [ "images": [
@ -106,6 +107,7 @@ curl "https://example-store.com/wp-json/wc/store/cart/items"
"sku": "wp-pennant", "sku": "wp-pennant",
"low_stock_remaining": null, "low_stock_remaining": null,
"backorders_allowed": false, "backorders_allowed": false,
"show_backorder_badge": false,
"sold_individually": false, "sold_individually": false,
"permalink": "https:\/\/local.wordpress.test\/product\/wordpress-pennant\/", "permalink": "https:\/\/local.wordpress.test\/product\/wordpress-pennant\/",
"images": [ "images": [
@ -199,6 +201,7 @@ curl "https://example-store.com/wp-json/wc/store/cart/items/e369853df766fa44e1ed
"sku": "wp-pennant", "sku": "wp-pennant",
"low_stock_remaining": null, "low_stock_remaining": null,
"backorders_allowed": false, "backorders_allowed": false,
"show_backorder_badge": false,
"sold_individually": false, "sold_individually": false,
"permalink": "https:\/\/local.wordpress.test\/product\/wordpress-pennant\/", "permalink": "https:\/\/local.wordpress.test\/product\/wordpress-pennant\/",
"images": [ "images": [

View File

@ -115,6 +115,7 @@ All endpoints under `/cart` (listed in this doc) return responses in the same fo
"sku": "woo-beanie", "sku": "woo-beanie",
"low_stock_remaining": null, "low_stock_remaining": null,
"backorders_allowed": false, "backorders_allowed": false,
"show_backorder_badge": false,
"sold_individually": false, "sold_individually": false,
"permalink": "https:\/\/local.wordpress.test\/product\/beanie\/", "permalink": "https:\/\/local.wordpress.test\/product\/beanie\/",
"images": [ "images": [
@ -174,6 +175,7 @@ All endpoints under `/cart` (listed in this doc) return responses in the same fo
"sku": "wp-pennant", "sku": "wp-pennant",
"low_stock_remaining": null, "low_stock_remaining": null,
"backorders_allowed": false, "backorders_allowed": false,
"show_backorder_badge": false,
"sold_individually": false, "sold_individually": false,
"permalink": "https:\/\/local.wordpress.test\/product\/wordpress-pennant\/", "permalink": "https:\/\/local.wordpress.test\/product\/wordpress-pennant\/",
"images": [ "images": [

View File

@ -229,6 +229,7 @@ class CartItems extends TestCase {
$this->assertArrayHasKey( 'variation', $data ); $this->assertArrayHasKey( 'variation', $data );
$this->assertArrayHasKey( 'low_stock_remaining', $data ); $this->assertArrayHasKey( 'low_stock_remaining', $data );
$this->assertArrayHasKey( 'backorders_allowed', $data ); $this->assertArrayHasKey( 'backorders_allowed', $data );
$this->assertArrayHasKey( 'show_backorder_badge', $data );
$this->assertArrayHasKey( 'short_description', $data ); $this->assertArrayHasKey( 'short_description', $data );
} }