diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/index.js b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/index.js index d4632a7cbe9..2c81b4b39c7 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/index.js @@ -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'; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/order-summary/order-summary-item.js b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/order-summary/order-summary-item.js index 7f76b2af1a6..43036eb64a2 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/order-summary/order-summary-item.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/order-summary/order-summary-item.js @@ -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 } /> - + { showBackorderBadge ? ( + + ) : ( + lowStockRemaining && ( + + ) + ) } { + return ( + + { __( 'Available on backorder', 'woo-gutenberg-products-block' ) } + + ); +}; + +export default ProductBackorderBadge; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-badge/index.js b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-badge/index.js new file mode 100644 index 00000000000..6db060f16e0 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-badge/index.js @@ -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 ( +
+ { children } +
+ ); +}; + +ProductBadge.propTypes = { + className: PropTypes.string, +}; + +export default ProductBadge; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-sale-badge/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-badge/style.scss similarity index 83% rename from plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-sale-badge/style.scss rename to plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-badge/style.scss index ae02c6ec7ff..1b5c3957d3a 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-sale-badge/style.scss +++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-badge/style.scss @@ -1,4 +1,4 @@ -.wc-block-components-sale-badge { +.wc-block-components-product-badge { @include font-size(smaller); border-radius: 2px; border: 1px solid; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-low-stock-badge/index.js b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-low-stock-badge/index.js index 189387e2d56..a4a7c4f0e15 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-low-stock-badge/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-low-stock-badge/index.js @@ -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 ( -
+ { sprintf( /* translators: %d stock amount (number of items in stock for product) */ __( '%d left in stock', 'woo-gutenberg-products-block' ), lowStockRemaining ) } -
+ ); }; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-low-stock-badge/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-low-stock-badge/style.scss deleted file mode 100644 index 324d27915f1..00000000000 --- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-low-stock-badge/style.scss +++ /dev/null @@ -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; -} diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-sale-badge/index.js b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-sale-badge/index.js index 14396a3ed08..9a0dae52510 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-sale-badge/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-sale-badge/index.js @@ -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 ( -
+ { __experimentalCreateInterpolateElement( /* translators: will be replaced by the discount amount */ __( 'Save ', 'woo-gutenberg-products-block' ), @@ -38,7 +38,7 @@ const ProductSaleBadge = ( { currency, saleAmount } ) => { ), } ) } -
+ ); }; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-variation-data/index.js b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-variation-data/index.js index 79108ddf86b..123493e8997 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-variation-data/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/product-variation-data/index.js @@ -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; } diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/cart-line-item-row.js b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/cart-line-item-row.js index e573587ab73..74501e70bbd 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/cart-line-item-row.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/cart-line-item-row.js @@ -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 } /> - + { showBackorderBadge ? ( + + ) : ( + lowStockRemaining && ( + + ) + ) } + { showBackorderBadge && } [ + '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() ), diff --git a/plugins/woocommerce-blocks/src/StoreApi/docs/cart-items.md b/plugins/woocommerce-blocks/src/StoreApi/docs/cart-items.md index 7798bf9ab1c..d4a01ce1c3e 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/docs/cart-items.md +++ b/plugins/woocommerce-blocks/src/StoreApi/docs/cart-items.md @@ -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": [ diff --git a/plugins/woocommerce-blocks/src/StoreApi/docs/cart.md b/plugins/woocommerce-blocks/src/StoreApi/docs/cart.md index f49bf8c9e18..1ab32fafc0b 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/docs/cart.md +++ b/plugins/woocommerce-blocks/src/StoreApi/docs/cart.md @@ -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": [ diff --git a/plugins/woocommerce-blocks/tests/php/StoreApi/Routes/CartItems.php b/plugins/woocommerce-blocks/tests/php/StoreApi/Routes/CartItems.php index 079b1d88ee3..806881d4ae9 100644 --- a/plugins/woocommerce-blocks/tests/php/StoreApi/Routes/CartItems.php +++ b/plugins/woocommerce-blocks/tests/php/StoreApi/Routes/CartItems.php @@ -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 ); }