Request attributes conditionally (#47361)
* Request terms conditionally * Add changelog * Add used context * Transform fetchAttributes into a hook * Call fetchAttributes inside Attributes component * Fix tests * Remove useless useEntityId and fix dependency * Refactor attriburtes component * Add AttributeControl to Attributes component * Add warning comment to Attributes component
This commit is contained in:
parent
8da8a70839
commit
b3e76c41b4
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: dev
|
||||
|
||||
Request attributes conditionally #47361
|
|
@ -22,5 +22,6 @@
|
|||
"lock": false,
|
||||
"__experimentalToolbar": false
|
||||
},
|
||||
"usesContext": [ "isInSelectedTab" ],
|
||||
"editorStyle": "file:./editor.css"
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { BlockAttributes } from '@wordpress/blocks';
|
||||
import { createElement } from '@wordpress/element';
|
||||
import { createElement, useEffect } from '@wordpress/element';
|
||||
import { useWooBlockProps } from '@woocommerce/block-templates';
|
||||
import { ProductProductAttribute } from '@woocommerce/data';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore No types for this exist yet.
|
||||
// eslint-disable-next-line @woocommerce/dependency-group
|
||||
|
@ -13,11 +15,13 @@ import { useEntityProp, useEntityId } from '@wordpress/core-data';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Attributes as AttributesContainer } from '../../../components/attributes/attributes';
|
||||
import { AttributeControl } from '../../../components/attribute-control';
|
||||
import { ProductEditorBlockEditProps } from '../../../types';
|
||||
import { useProductAttributes } from '../../../hooks/use-product-attributes';
|
||||
|
||||
export function AttributesBlockEdit( {
|
||||
attributes,
|
||||
context: { isInSelectedTab },
|
||||
}: ProductEditorBlockEditProps< BlockAttributes > ) {
|
||||
const [ entityAttributes, setEntityAttributes ] = useEntityProp<
|
||||
ProductProductAttribute[]
|
||||
|
@ -27,12 +31,77 @@ export function AttributesBlockEdit( {
|
|||
|
||||
const blockProps = useWooBlockProps( attributes );
|
||||
|
||||
const {
|
||||
attributes: attributeList,
|
||||
fetchAttributes,
|
||||
handleChange,
|
||||
} = useProductAttributes( {
|
||||
allAttributes: entityAttributes,
|
||||
onChange: setEntityAttributes,
|
||||
productId,
|
||||
} );
|
||||
|
||||
useEffect( () => {
|
||||
if ( isInSelectedTab ) {
|
||||
fetchAttributes();
|
||||
}
|
||||
}, [ entityAttributes, isInSelectedTab ] );
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<AttributesContainer
|
||||
productId={ productId }
|
||||
value={ entityAttributes }
|
||||
onChange={ setEntityAttributes }
|
||||
<AttributeControl
|
||||
value={ attributeList }
|
||||
disabledAttributeIds={ entityAttributes
|
||||
.filter( ( attr ) => !! attr.variation )
|
||||
.map( ( attr ) => attr.id ) }
|
||||
uiStrings={ {
|
||||
disabledAttributeMessage: __(
|
||||
'Already used in Variations',
|
||||
'woocommerce'
|
||||
),
|
||||
} }
|
||||
onAdd={ () => {
|
||||
recordEvent(
|
||||
'product_add_attributes_modal_add_button_click'
|
||||
);
|
||||
} }
|
||||
onChange={ handleChange }
|
||||
onNewModalCancel={ () => {
|
||||
recordEvent(
|
||||
'product_add_attributes_modal_cancel_button_click'
|
||||
);
|
||||
} }
|
||||
onNewModalOpen={ () => {
|
||||
if ( ! attributeList.length ) {
|
||||
recordEvent(
|
||||
'product_add_first_attribute_button_click'
|
||||
);
|
||||
return;
|
||||
}
|
||||
recordEvent( 'product_add_attribute_button' );
|
||||
} }
|
||||
onAddAnother={ () => {
|
||||
recordEvent(
|
||||
'product_add_attributes_modal_add_another_attribute_button_click'
|
||||
);
|
||||
} }
|
||||
onRemoveItem={ () => {
|
||||
recordEvent(
|
||||
'product_add_attributes_modal_remove_attribute_button_click'
|
||||
);
|
||||
} }
|
||||
onRemove={ () =>
|
||||
recordEvent(
|
||||
'product_remove_attribute_confirmation_confirm_click'
|
||||
)
|
||||
}
|
||||
onRemoveCancel={ () =>
|
||||
recordEvent(
|
||||
'product_remove_attribute_confirmation_cancel_click'
|
||||
)
|
||||
}
|
||||
termsAutoSelection="first"
|
||||
defaultVisibility={ true }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -22,5 +22,6 @@
|
|||
"lock": false,
|
||||
"__experimentalToolbar": false
|
||||
},
|
||||
"usesContext": [ "postType", "isInSelectedTab" ],
|
||||
"editorStyle": "file:./editor.css"
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Button } from '@wordpress/components';
|
|||
import {
|
||||
createElement,
|
||||
createInterpolateElement,
|
||||
useEffect,
|
||||
useMemo,
|
||||
} from '@wordpress/element';
|
||||
import { useWooBlockProps } from '@woocommerce/block-templates';
|
||||
|
@ -37,7 +38,7 @@ import { ProductTShirt } from './images';
|
|||
|
||||
export function Edit( {
|
||||
attributes: blockAttributes,
|
||||
context,
|
||||
context: { postType, isInSelectedTab },
|
||||
}: ProductEditorBlockEditProps< BlockAttributes > ) {
|
||||
const blockProps = useWooBlockProps( blockAttributes );
|
||||
const { generateProductVariations } = useProductVariationsHelper();
|
||||
|
@ -57,19 +58,26 @@ export function Edit( {
|
|||
'default_attributes'
|
||||
);
|
||||
|
||||
const { postType } = context;
|
||||
const productId = useEntityId( 'postType', postType );
|
||||
|
||||
const { attributes, handleChange } = useProductAttributes( {
|
||||
const { attributes, fetchAttributes, handleChange } = useProductAttributes(
|
||||
{
|
||||
allAttributes: entityAttributes,
|
||||
isVariationAttributes: true,
|
||||
productId: useEntityId( 'postType', 'product' ),
|
||||
productId,
|
||||
onChange( values, defaultAttributes ) {
|
||||
setEntityAttributes( values );
|
||||
setEntityDefaultAttributes( defaultAttributes );
|
||||
generateProductVariations( values, defaultAttributes );
|
||||
},
|
||||
} );
|
||||
}
|
||||
);
|
||||
|
||||
useEffect( () => {
|
||||
if ( isInSelectedTab ) {
|
||||
fetchAttributes();
|
||||
}
|
||||
}, [ isInSelectedTab, entityAttributes ] );
|
||||
|
||||
const localAttributeNames = attributes
|
||||
.filter( ( attr ) => attr.id === 0 )
|
||||
|
|
|
@ -10,28 +10,26 @@ import { recordEvent } from '@woocommerce/tracks';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { AttributeControl } from '../attribute-control';
|
||||
import { useProductAttributes } from '../../hooks/use-product-attributes';
|
||||
|
||||
type AttributesProps = {
|
||||
attributeList?: ProductProductAttribute[];
|
||||
value: ProductProductAttribute[];
|
||||
onChange: ( value: ProductProductAttribute[] ) => void;
|
||||
productId?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* This component is no longer in active use.
|
||||
* It is kept here for backward compatibility because is being used in the `AttributesField` component, under
|
||||
* `plugins/woocommerce-admin/client/products/fills/attributes-section/attributes-field.tsx`.
|
||||
*/
|
||||
export const Attributes: React.FC< AttributesProps > = ( {
|
||||
value,
|
||||
onChange,
|
||||
productId,
|
||||
attributeList = [],
|
||||
} ) => {
|
||||
const { attributes, handleChange } = useProductAttributes( {
|
||||
allAttributes: value,
|
||||
onChange,
|
||||
productId,
|
||||
} );
|
||||
|
||||
return (
|
||||
<AttributeControl
|
||||
value={ attributes }
|
||||
value={ attributeList }
|
||||
disabledAttributeIds={ value
|
||||
.filter( ( attr ) => !! attr.variation )
|
||||
.map( ( attr ) => attr.id ) }
|
||||
|
@ -44,14 +42,14 @@ export const Attributes: React.FC< AttributesProps > = ( {
|
|||
onAdd={ () => {
|
||||
recordEvent( 'product_add_attributes_modal_add_button_click' );
|
||||
} }
|
||||
onChange={ handleChange }
|
||||
onChange={ onChange }
|
||||
onNewModalCancel={ () => {
|
||||
recordEvent(
|
||||
'product_add_attributes_modal_cancel_button_click'
|
||||
);
|
||||
} }
|
||||
onNewModalOpen={ () => {
|
||||
if ( ! attributes.length ) {
|
||||
if ( ! attributeList.length ) {
|
||||
recordEvent( 'product_add_first_attribute_button_click' );
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ describe( 'useProductAttributes', () => {
|
|||
},
|
||||
}
|
||||
);
|
||||
result.current.fetchAttributes();
|
||||
await waitForNextUpdate();
|
||||
expect( resolveSelect ).not.toHaveBeenCalled();
|
||||
expect( result.current.attributes ).toEqual( [] );
|
||||
|
@ -175,6 +176,7 @@ describe( 'useProductAttributes', () => {
|
|||
},
|
||||
}
|
||||
);
|
||||
result.current.fetchAttributes();
|
||||
jest.runOnlyPendingTimers();
|
||||
await waitForNextUpdate();
|
||||
result.current.handleChange( [
|
||||
|
@ -210,6 +212,7 @@ describe( 'useProductAttributes', () => {
|
|||
}
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
result.current.fetchAttributes();
|
||||
await waitForNextUpdate();
|
||||
result.current.handleChange( [
|
||||
{ ...testAttributes[ 0 ], isDefault: false },
|
||||
|
@ -242,6 +245,7 @@ describe( 'useProductAttributes', () => {
|
|||
}
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
result.current.fetchAttributes();
|
||||
await waitForNextUpdate();
|
||||
result.current.handleChange( [
|
||||
{ ...testAttributes[ 0 ], isDefault: false },
|
||||
|
@ -274,6 +278,7 @@ describe( 'useProductAttributes', () => {
|
|||
}
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
result.current.fetchAttributes();
|
||||
await waitForNextUpdate();
|
||||
result.current.handleChange( [
|
||||
{ ...testAttributes[ 1 ], isDefault: false },
|
||||
|
@ -305,6 +310,7 @@ describe( 'useProductAttributes', () => {
|
|||
}
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
result.current.fetchAttributes();
|
||||
await waitForNextUpdate();
|
||||
result.current.handleChange( [
|
||||
{ ...testAttributes[ 0 ], isDefault: false },
|
||||
|
@ -336,6 +342,7 @@ describe( 'useProductAttributes', () => {
|
|||
}
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
result.current.fetchAttributes();
|
||||
await waitForNextUpdate();
|
||||
result.current.handleChange( [ { ...testAttributes[ 0 ] } ] );
|
||||
expect( onChange ).toHaveBeenCalledWith(
|
||||
|
@ -371,6 +378,7 @@ describe( 'useProductAttributes', () => {
|
|||
}
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
result.current.fetchAttributes();
|
||||
await waitForNextUpdate();
|
||||
result.current.handleChange( [
|
||||
{ ...testAttributes[ 0 ], isDefault: true },
|
||||
|
@ -415,6 +423,7 @@ describe( 'useProductAttributes', () => {
|
|||
},
|
||||
}
|
||||
);
|
||||
result.current.fetchAttributes();
|
||||
jest.runOnlyPendingTimers();
|
||||
await waitForNextUpdate();
|
||||
expect( result.current.attributes.length ).toBe( 2 );
|
||||
|
@ -445,6 +454,7 @@ describe( 'useProductAttributes', () => {
|
|||
},
|
||||
}
|
||||
);
|
||||
result.current.fetchAttributes();
|
||||
jest.runOnlyPendingTimers();
|
||||
await waitForNextUpdate();
|
||||
expect( result.current.attributes.length ).toBe( 2 );
|
||||
|
@ -460,6 +470,7 @@ describe( 'useProductAttributes', () => {
|
|||
isVariationAttributes: false,
|
||||
productId: 123,
|
||||
} );
|
||||
result.current.fetchAttributes();
|
||||
jest.runOnlyPendingTimers();
|
||||
await waitForNextUpdate();
|
||||
expect( result.current.attributes.length ).toBe( 1 );
|
||||
|
@ -486,6 +497,7 @@ describe( 'useProductAttributes', () => {
|
|||
},
|
||||
}
|
||||
);
|
||||
result.current.fetchAttributes();
|
||||
jest.runOnlyPendingTimers();
|
||||
await waitForNextUpdate();
|
||||
expect( result.current.attributes.length ).toBe( 3 );
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
ProductDefaultAttribute,
|
||||
} from '@woocommerce/data';
|
||||
import { resolveSelect } from '@wordpress/data';
|
||||
import { useCallback, useEffect, useState } from '@wordpress/element';
|
||||
import { useCallback, useState } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -167,7 +167,7 @@ export function useProductAttributes( {
|
|||
}
|
||||
};
|
||||
|
||||
useEffect( () => {
|
||||
const fetchAttributes = useCallback( () => {
|
||||
const [
|
||||
localAttributes,
|
||||
globalAttributes,
|
||||
|
@ -190,6 +190,7 @@ export function useProductAttributes( {
|
|||
|
||||
return {
|
||||
attributes,
|
||||
fetchAttributes,
|
||||
handleChange,
|
||||
setAttributes,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue