Product variation quantity status indicator (#35982)

* Add variation status indicator

* Add changelog

* Add tests

* Fix style

* Rename enum

* Fix lint

Co-authored-by: Fernando Marichal <contacto@fernandomarichal.com>
This commit is contained in:
Fernando Marichal 2022-12-15 15:20:21 -03:00 committed by GitHub
parent b904fd428d
commit 44cf396be6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 187 additions and 1 deletions

View File

@ -22,6 +22,19 @@
} }
} }
&__status-dot {
margin-right: $gap-smaller;
&.green {
color: $alert-green;
}
&.yellow {
color: $alert-yellow;
}
&.red {
color: $alert-red;
}
}
.woocommerce-list-item { .woocommerce-list-item {
display: grid; display: grid;
grid-template-columns: 38px 25% 25% 25%; grid-template-columns: 38px 25% 25% 25%;

View File

@ -11,12 +11,16 @@ import { ListItem, Pagination, Sortable, Tag } from '@woocommerce/components';
import { useContext, useState } from '@wordpress/element'; import { useContext, useState } from '@wordpress/element';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { useSelect } from '@wordpress/data'; import { useSelect } from '@wordpress/data';
import classnames from 'classnames';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { CurrencyContext } from '../../../lib/currency-context'; import { CurrencyContext } from '../../../lib/currency-context';
import { getProductStockStatus } from '../../utils/get-product-stock-status'; import {
getProductStockStatus,
getProductStockStatusClass,
} from '../../utils/get-product-stock-status';
import './variations.scss'; import './variations.scss';
/** /**
@ -102,6 +106,14 @@ export const Variations: React.FC = () => {
{ formatAmount( variation.price ) } { formatAmount( variation.price ) }
</div> </div>
<div className="woocommerce-product-variations__quantity"> <div className="woocommerce-product-variations__quantity">
<span
className={ classnames(
'woocommerce-product-variations__status-dot',
getProductStockStatusClass( variation )
) }
>
</span>
{ getProductStockStatus( variation ) } { getProductStockStatus( variation ) }
</div> </div>
</ListItem> </ListItem>

View File

@ -13,6 +13,15 @@ export enum PRODUCT_STOCK_STATUS_KEYS {
outofstock = 'outofstock', outofstock = 'outofstock',
} }
/**
* Product stock status colors.
*/
export enum PRODUCT_STOCK_STATUS_CLASSES {
instock = 'green',
onbackorder = 'yellow',
outofstock = 'red',
}
/** /**
* Labels for product stock statuses. * Labels for product stock statuses.
*/ */
@ -47,3 +56,27 @@ export const getProductStockStatus = (
return PRODUCT_STOCK_STATUS_LABELS.instock; return PRODUCT_STOCK_STATUS_LABELS.instock;
}; };
/**
* Get the product stock status class.
*
* @param product Product instance.
* @return {PRODUCT_STOCK_STATUS_CLASSES} Product stock status class.
*/
export const getProductStockStatusClass = (
product: PartialProduct | Partial< ProductVariation >
): string => {
if ( product.manage_stock ) {
const stockQuantity: number = product.stock_quantity || 0;
if ( stockQuantity >= 10 ) {
return PRODUCT_STOCK_STATUS_CLASSES.instock;
}
if ( stockQuantity < 10 && stockQuantity > 2 ) {
return PRODUCT_STOCK_STATUS_CLASSES.onbackorder;
}
return PRODUCT_STOCK_STATUS_CLASSES.outofstock;
}
return product.stock_status
? PRODUCT_STOCK_STATUS_CLASSES[ product.stock_status ]
: '';
};

View File

@ -0,0 +1,124 @@
/**
* External dependencies
*/
import { PartialProduct } from '@woocommerce/data';
/**
* Internal dependencies
*/
import {
getProductStockStatus,
getProductStockStatusClass,
} from '../get-product-stock-status';
const products = [
{
status: 'publish',
} as PartialProduct,
{
status: 'publish',
stock_status: 'outofstock',
} as PartialProduct,
{
manage_stock: true,
stock_quantity: 15,
status: 'publish',
stock_status: 'instock',
} as PartialProduct,
{
manage_stock: true,
status: 'publish',
stock_status: 'instock',
} as PartialProduct,
{
manage_stock: true,
stock_quantity: 5,
status: 'publish',
stock_status: 'instock',
} as PartialProduct,
{
manage_stock: true,
stock_quantity: 1,
status: 'publish',
stock_status: 'instock',
} as PartialProduct,
{
manage_stock: false,
status: 'publish',
stock_status: 'instock',
} as PartialProduct,
{
manage_stock: false,
status: 'publish',
stock_status: 'onbackorder',
} as PartialProduct,
{
manage_stock: false,
status: 'publish',
stock_status: 'outofstock',
} as PartialProduct,
];
describe( 'getProductStockStatus', () => {
it( 'should return `In stock` status when the stock is not being managed and there is no stock status', () => {
const status = getProductStockStatus( products[ 0 ] );
expect( status ).toBe( 'In stock' );
} );
it( 'should return the stock status when there is a stock status and the stock is not being managed', () => {
const status = getProductStockStatus( products[ 1 ] );
expect( status ).toBe( 'Out of stock' );
} );
it( 'should return the stock quantity when the stock is being managed', () => {
const status = getProductStockStatus( products[ 2 ] );
expect( status ).toBe( 15 );
} );
it( 'should return stock quantity = 0 when the stock is being managed but there is no a stock quantity', () => {
const status = getProductStockStatus( products[ 3 ] );
expect( status ).toBe( 0 );
} );
} );
describe( 'getProductStockStatusClass', () => {
it( 'should return an emtpy string when the stock is not being managed and there is no stock status', () => {
const status = getProductStockStatusClass( products[ 0 ] );
expect( status ).toBe( '' );
} );
it( 'should return `green` when the stock is being managed and the stock quantity is higher or equal than 10', () => {
const status = getProductStockStatusClass( products[ 2 ] );
expect( status ).toBe( 'green' );
} );
it( 'should return `yellow` when the stock is being managed and the stock quantity is lower than 10 but higher than 2', () => {
const status = getProductStockStatusClass( products[ 4 ] );
expect( status ).toBe( 'yellow' );
} );
it( 'should return `red` when the stock is being managed and the stock quantity is lower or equal than 2', () => {
const status = getProductStockStatusClass( products[ 5 ] );
expect( status ).toBe( 'red' );
} );
it( 'should return `red` when the stock is being managed but there is no a stock quantity', () => {
const status = getProductStockStatusClass( products[ 3 ] );
expect( status ).toBe( 'red' );
} );
it( 'should return `green` when the stock is not being managed and the stock status is `instock`', () => {
const status = getProductStockStatusClass( products[ 6 ] );
expect( status ).toBe( 'green' );
} );
it( 'should return `yellow` when the stock is not being managed and the stock status is `onbackorder`', () => {
const status = getProductStockStatusClass( products[ 7 ] );
expect( status ).toBe( 'yellow' );
} );
it( 'should return `red` when the stock is not being managed and the stock status is `outofstock`', () => {
const status = getProductStockStatusClass( products[ 8 ] );
expect( status ).toBe( 'red' );
} );
} );

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Product variation quantity status indicator