* 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 PlaceOrderButton } from './place-order-button';
export { default as Policies } from './policies';
export { default as ProductBackorderBadge } from './product-backorder-badge';
export { default as ProductImage } from './product-image';
export { default as ProductLowStockBadge } from './product-low-stock-badge';
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 Label from '@woocommerce/base-components/label';
import {
ProductBackorderBadge,
ProductImage,
ProductLowStockBadge,
ProductMetadata,
@ -18,6 +19,7 @@ const OrderSummaryItem = ( { cartItem } ) => {
const {
images,
low_stock_remaining: lowStockRemaining = null,
show_backorder_badge: showBackorderBadge = false,
name,
permalink,
prices,
@ -60,7 +62,15 @@ const OrderSummaryItem = ( { cartItem } ) => {
value={ linePrice }
/>
</div>
<ProductLowStockBadge lowStockRemaining={ lowStockRemaining } />
{ showBackorderBadge ? (
<ProductBackorderBadge />
) : (
lowStockRemaining && (
<ProductLowStockBadge
lowStockRemaining={ lowStockRemaining }
/>
)
) }
<ProductMetadata
shortDescription={ shortDescription }
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);
border-radius: 2px;
border: 1px solid;

View File

@ -7,7 +7,7 @@ import PropTypes from 'prop-types';
/**
* Internal dependencies
*/
import './style.scss';
import ProductBadge from '../product-badge';
/**
* Returns a low stock badge.
@ -18,13 +18,13 @@ const ProductLowStockBadge = ( { lowStockRemaining } ) => {
}
return (
<div className="wc-block-components-product-low-stock-badge">
<ProductBadge className="wc-block-components-product-low-stock-badge">
{ sprintf(
/* translators: %d stock amount (number of items in stock for product) */
__( '%d left in stock', 'woo-gutenberg-products-block' ),
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
*/
import './style.scss';
import ProductBadge from '../product-badge';
/**
* ProductSaleBadge
@ -25,7 +25,7 @@ const ProductSaleBadge = ( { currency, saleAmount } ) => {
return null;
}
return (
<div className="wc-block-components-sale-badge">
<ProductBadge className="wc-block-components-sale-badge">
{ __experimentalCreateInterpolateElement(
/* translators: <price/> will be replaced by the discount amount */
__( '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.
*/
const ProductVariationData = ( { className, variation = [] } ) => {
if ( ! variation ) {
if ( ! variation || variation.length === 0 ) {
return null;
}

View File

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

View File

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

View File

@ -143,6 +143,10 @@
* @property {boolean} backorders_allowed True if backorders are
* allowed past stock
* 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
* this product is allowed
* for purchase in a single

View File

@ -45,80 +45,86 @@ class CartItemSchema extends ProductSchema {
*/
public function get_properties() {
return [
'key' => [
'key' => [
'description' => __( 'Unique identifier for the item within the cart.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'id' => [
'id' => [
'description' => __( 'The cart item product or variation ID.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'quantity' => [
'quantity' => [
'description' => __( 'Quantity of this item in the cart.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'quantity_limit' => [
'quantity_limit' => [
'description' => __( 'The maximum quantity than can be added to the cart at once.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'name' => [
'name' => [
'description' => __( 'Product name.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'short_description' => [
'short_description' => [
'description' => __( 'Product short description in HTML format.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'description' => [
'description' => [
'description' => __( 'Product full description in HTML format.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'sku' => [
'sku' => [
'description' => __( 'Stock keeping unit, if applicable.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'low_stock_remaining' => [
'low_stock_remaining' => [
'description' => __( 'Quantity left in stock if stock is low, or null if not applicable.', 'woo-gutenberg-products-block' ),
'type' => [ 'integer', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'backorders_allowed' => [
'backorders_allowed' => [
'description' => __( 'True if backorders are allowed past stock availability.', 'woo-gutenberg-products-block' ),
'type' => [ 'boolean' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'sold_individually' => [
'show_backorder_badge' => [
'description' => __( 'True if the product is on backorder.', 'woo-gutenberg-products-block' ),
'type' => [ 'boolean' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'sold_individually' => [
'description' => __( 'If true, only one item of this product is allowed for purchase in a single order.', 'woo-gutenberg-products-block' ),
'type' => 'boolean',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'permalink' => [
'permalink' => [
'description' => __( 'Product URL.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'format' => 'uri',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'images' => [
'images' => [
'description' => __( 'List of images.', 'woo-gutenberg-products-block' ),
'type' => 'array',
'context' => [ 'view', 'edit' ],
@ -128,7 +134,7 @@ class CartItemSchema extends ProductSchema {
'properties' => $this->image_attachment_schema->get_properties(),
],
],
'variation' => [
'variation' => [
'description' => __( 'Chosen attributes (for variations).', 'woo-gutenberg-products-block' ),
'type' => 'array',
'context' => [ 'view', 'edit' ],
@ -151,7 +157,7 @@ class CartItemSchema extends ProductSchema {
],
],
],
'prices' => [
'prices' => [
'description' => __( 'Price data for the product in the current line item, including or excluding taxes based on the "display prices during cart and checkout" setting. Provided using the smallest unit of the currency.', 'woo-gutenberg-products-block' ),
'type' => 'object',
'context' => [ 'view', 'edit' ],
@ -232,7 +238,7 @@ class CartItemSchema extends ProductSchema {
]
),
],
'totals' => [
'totals' => [
'description' => __( 'Item total amounts provided using the smallest unit of the currency.', 'woo-gutenberg-products-block' ),
'type' => 'object',
'context' => [ 'view', 'edit' ],
@ -280,22 +286,23 @@ class CartItemSchema extends ProductSchema {
$product = $cart_item['data'];
return [
'key' => $cart_item['key'],
'id' => $product->get_id(),
'quantity' => wc_stock_amount( $cart_item['quantity'] ),
'quantity_limit' => $this->get_product_quantity_limit( $product ),
'name' => $this->prepare_html_response( $product->get_title() ),
'short_description' => $this->prepare_html_response( wc_format_content( $product->get_short_description() ) ),
'description' => $this->prepare_html_response( wc_format_content( $product->get_description() ) ),
'sku' => $this->prepare_html_response( $product->get_sku() ),
'low_stock_remaining' => $this->get_low_stock_remaining( $product ),
'backorders_allowed' => (bool) $product->backorders_allowed(),
'sold_individually' => $product->is_sold_individually(),
'permalink' => $product->get_permalink(),
'images' => $this->get_images( $product ),
'variation' => $this->format_variation_data( $cart_item['variation'], $product ),
'prices' => (object) $this->prepare_product_price_response( $product, get_option( 'woocommerce_tax_display_cart' ) ),
'totals' => (object) array_merge(
'key' => $cart_item['key'],
'id' => $product->get_id(),
'quantity' => wc_stock_amount( $cart_item['quantity'] ),
'quantity_limit' => $this->get_product_quantity_limit( $product ),
'name' => $this->prepare_html_response( $product->get_title() ),
'short_description' => $this->prepare_html_response( wc_format_content( $product->get_short_description() ) ),
'description' => $this->prepare_html_response( wc_format_content( $product->get_description() ) ),
'sku' => $this->prepare_html_response( $product->get_sku() ),
'low_stock_remaining' => $this->get_low_stock_remaining( $product ),
'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(),
'permalink' => $product->get_permalink(),
'images' => $this->get_images( $product ),
'variation' => $this->format_variation_data( $cart_item['variation'], $product ),
'prices' => (object) $this->prepare_product_price_response( $product, get_option( 'woocommerce_tax_display_cart' ) ),
'totals' => (object) array_merge(
$this->get_store_currency_response(),
[
'line_subtotal' => $this->prepare_money_response( $cart_item['line_subtotal'], wc_get_price_decimals() ),

View File

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

View File

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

View File

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