Manage default variation option (#39570)

* Add default attributes property to the Product type

* Add change log file

* Set default attributes when click add from the attribute options modal

* Add Set default value checkbox to the edit attribute modal

* Manage default attributes when update or delete an attribute option

* Show Set default value only when the editing attribute is used for variations

* Add change log file
This commit is contained in:
Maikel David Pérez Gómez 2023-08-08 10:41:26 -04:00 committed by GitHub
parent 9c13c21ec8
commit b546e4fb17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 154 additions and 28 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add default attributes property to the Product type

View File

@ -36,6 +36,24 @@ export type ProductAttribute = {
options: string[];
};
/**
* Product - Default attributes properties
*/
export type ProductDefaultAttribute = {
/**
* Attribute ID.
*/
id: number;
/**
* Attribute name.
*/
name: string;
/**
* Selected attribute term name.
*/
option: string;
};
export type ProductDimensions = {
width: string;
height: string;
@ -66,6 +84,7 @@ export type Product< Status = ProductStatus, Type = ProductType > = Omit<
date_modified_gmt: string;
date_on_sale_from_gmt: string | null;
date_on_sale_to_gmt: string | null;
default_attributes: ProductDefaultAttribute[];
description: string;
dimensions: ProductDimensions;
download_expiry: number;

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add set default value checkbox to the edit attribute options modal

View File

@ -3,8 +3,12 @@
*/
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import { createElement, createInterpolateElement } from '@wordpress/element';
import { ProductAttribute } from '@woocommerce/data';
import {
createElement,
createInterpolateElement,
useMemo,
} from '@wordpress/element';
import { Product, ProductAttribute } from '@woocommerce/data';
import { Link } from '@woocommerce/components';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore No types for this exist yet.
@ -14,9 +18,31 @@ import { useEntityProp, useEntityId } from '@wordpress/core-data';
/**
* Internal dependencies
*/
import { useProductAttributes } from '../../hooks/use-product-attributes';
import {
EnhancedProductAttribute,
useProductAttributes,
} from '../../hooks/use-product-attributes';
import { AttributeControl } from '../../components/attribute-control';
function manageDefaultAttributes( values: EnhancedProductAttribute[] ) {
return values.reduce< Product[ 'default_attributes' ] >(
( prevDefaultAttributes, currentAttribute ) => {
if ( currentAttribute.isDefault ) {
return [
...prevDefaultAttributes,
{
id: currentAttribute.id,
name: currentAttribute.name,
option: currentAttribute.options[ 0 ],
},
];
}
return prevDefaultAttributes;
},
[]
);
}
export function Edit() {
const blockProps = useBlockProps();
@ -24,17 +50,41 @@ export function Edit() {
ProductAttribute[]
>( 'postType', 'product', 'attributes' );
const [ entityDefaultAttributes, setEntityDefaultAttributes ] =
useEntityProp< Product[ 'default_attributes' ] >(
'postType',
'product',
'default_attributes'
);
const { attributes, handleChange } = useProductAttributes( {
allAttributes: entityAttributes,
onChange: setEntityAttributes,
isVariationAttributes: true,
productId: useEntityId( 'postType', 'product' ),
onChange( values ) {
setEntityAttributes( values );
setEntityDefaultAttributes( manageDefaultAttributes( values ) );
},
} );
function mapDefaultAttributes() {
return attributes.map( ( attribute ) => ( {
...attribute,
isDefault: entityDefaultAttributes.some(
( defaultAttribute ) =>
defaultAttribute.id === attribute.id ||
defaultAttribute.name === attribute.name
),
} ) );
}
return (
<div { ...blockProps }>
<AttributeControl
value={ attributes }
value={ useMemo( mapDefaultAttributes, [
attributes,
entityDefaultAttributes,
] ) }
onChange={ handleChange }
uiStrings={ {
globalAttributeHelperMessage: '',

View File

@ -41,6 +41,16 @@ function hasAttributesUsedForVariations(
return productAttributes.some( ( { variation } ) => variation );
}
function getFirstOptionFromEachAttribute(
attributes: Product[ 'attributes' ]
): Product[ 'default_attributes' ] {
return attributes.map( ( attribute ) => ( {
id: attribute.id,
name: attribute.name,
option: attribute.options[ 0 ],
} ) );
}
export function Edit( {
attributes,
}: BlockEditProps< VariationsBlockAttributes > ) {
@ -50,13 +60,21 @@ export function Edit( {
const [ productAttributes, setProductAttributes ] = useEntityProp<
Product[ 'attributes' ]
>( 'postType', 'product', 'attributes' );
const [ , setDefaultProductAttributes ] = useEntityProp<
Product[ 'default_attributes' ]
>( 'postType', 'product', 'default_attributes' );
const { attributes: variationOptions, handleChange } = useProductAttributes(
{
allAttributes: productAttributes,
onChange: setProductAttributes,
isVariationAttributes: true,
productId: useEntityId( 'postType', 'product' ),
onChange( values ) {
setProductAttributes( values );
setDefaultProductAttributes(
getFirstOptionFromEachAttribute( values )
);
},
}
);

View File

@ -32,7 +32,7 @@ import { AttributeListItem } from '../attribute-list-item';
import { NewAttributeModal } from './new-attribute-modal';
type AttributeControlProps = {
value: ProductAttribute[];
value: EnhancedProductAttribute[];
onAdd?: ( attribute: EnhancedProductAttribute[] ) => void;
onChange: ( value: ProductAttribute[] ) => void;
onEdit?: ( attribute: ProductAttribute ) => void;
@ -189,7 +189,7 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
const currentAttribute = value.find(
( attr ) => getAttributeId( attr ) === currentAttributeId
) as EnhancedProductAttribute;
);
return (
<div className="woocommerce-attribute-field">

View File

@ -14,7 +14,8 @@
width: 500px;
max-width: 100%;
.woocommerce-experimental-select-control + .woocommerce-experimental-select-control {
.woocommerce-experimental-select-control
+ .woocommerce-experimental-select-control {
margin-top: 1.3em;
}
@ -30,6 +31,10 @@
display: flex;
flex-direction: row;
align-items: center;
.components-checkbox-control .components-base-control__field {
margin-bottom: 0;
}
}
.woocommerce-attribute-term-field {

View File

@ -27,6 +27,8 @@ type EditAttributeModalProps = {
customAttributeHelperMessage?: string;
termsLabel?: string;
termsPlaceholder?: string;
isDefaultLabel?: string;
isDefaultTooltip?: string;
visibleLabel?: string;
visibleTooltip?: string;
cancelAccessibleLabel?: string;
@ -48,6 +50,11 @@ export const EditAttributeModal: React.FC< EditAttributeModalProps > = ( {
),
termsLabel = __( 'Values', 'woocommerce' ),
termsPlaceholder = __( 'Search or create value', 'woocommerce' ),
isDefaultLabel = __( 'Set default value', 'woocommerce' ),
isDefaultTooltip = __(
'Check to preselect the first choice when customers enter the product page.',
'woocommerce'
),
visibleLabel = __( 'Visible to customers', 'woocommerce' ),
visibleTooltip = __(
'Show or hide this attribute on the product page',
@ -120,18 +127,36 @@ export const EditAttributeModal: React.FC< EditAttributeModalProps > = ( {
/>
) }
<div className="woocommerce-edit-attribute-modal__option-container">
<CheckboxControl
onChange={ ( val ) =>
setEditableAttribute( {
...( editableAttribute as EnhancedProductAttribute ),
visible: val,
} )
}
checked={ editableAttribute?.visible }
label={ visibleLabel }
/>
<Tooltip text={ visibleTooltip } />
<div className="woocommerce-edit-attribute-modal__options">
{ attribute.variation && (
<div className="woocommerce-edit-attribute-modal__option-container">
<CheckboxControl
onChange={ ( checked ) =>
setEditableAttribute( {
...( editableAttribute as EnhancedProductAttribute ),
isDefault: checked,
} )
}
checked={ editableAttribute?.isDefault }
label={ isDefaultLabel }
/>
<Tooltip text={ isDefaultTooltip } />
</div>
) }
<div className="woocommerce-edit-attribute-modal__option-container">
<CheckboxControl
onChange={ ( val ) =>
setEditableAttribute( {
...( editableAttribute as EnhancedProductAttribute ),
visible: val,
} )
}
checked={ editableAttribute?.visible }
label={ visibleLabel }
/>
<Tooltip text={ visibleTooltip } />
</div>
</div>
</div>
<div className="woocommerce-edit-attribute-modal__buttons">

View File

@ -14,18 +14,19 @@ import { useCallback, useEffect, useState } from '@wordpress/element';
*/
import { sift } from '../utils';
export type EnhancedProductAttribute = ProductAttribute & {
isDefault?: boolean;
terms?: ProductAttributeTerm[];
visible?: boolean;
};
type useProductAttributesProps = {
allAttributes: ProductAttribute[];
isVariationAttributes?: boolean;
onChange: ( attributes: ProductAttribute[] ) => void;
onChange: ( attributes: EnhancedProductAttribute[] ) => void;
productId?: number;
};
export type EnhancedProductAttribute = ProductAttribute & {
terms?: ProductAttributeTerm[];
visible?: boolean;
};
const getFilteredAttributes = (
attr: ProductAttribute[],
isVariationAttributes: boolean
@ -89,7 +90,7 @@ export function useProductAttributes( {
} ) );
};
const handleChange = ( newAttributes: ProductAttribute[] ) => {
const handleChange = ( newAttributes: EnhancedProductAttribute[] ) => {
let otherAttributes = isVariationAttributes
? allAttributes.filter( ( attribute ) => ! attribute.variation )
: allAttributes.filter( ( attribute ) => !! attribute.variation );