diff --git a/plugins/woocommerce-admin/client/products/fields/attribute-field/attribute-field.tsx b/plugins/woocommerce-admin/client/products/fields/attribute-field/attribute-field.tsx index f3fe69a63fb..88a97d01cd3 100644 --- a/plugins/woocommerce-admin/client/products/fields/attribute-field/attribute-field.tsx +++ b/plugins/woocommerce-admin/client/products/fields/attribute-field/attribute-field.tsx @@ -24,7 +24,10 @@ import { getAdminLink } from '@woocommerce/settings'; import './attribute-field.scss'; import { AddAttributeModal } from './add-attribute-modal'; import { EditAttributeModal } from './edit-attribute-modal'; -import { reorderSortableProductAttributePositions } from './utils'; +import { + getAttributeKey, + reorderSortableProductAttributePositions, +} from './utils'; import { sift } from '../../../utils'; import { AttributeEmptyState } from '../attribute-empty-state'; import { @@ -244,10 +247,10 @@ export const AttributeField: React.FC< AttributeFieldProps > = ( { ); const attributeKeyValues = filteredAttributes.reduce( ( - keyValue: Record< number, ProductAttribute >, + keyValue: Record< number | string, ProductAttribute >, attribute: ProductAttribute ) => { - keyValue[ attribute.id ] = attribute; + keyValue[ getAttributeKey( attribute ) ] = attribute; return keyValue; }, {} as Record< number, ProductAttribute > diff --git a/plugins/woocommerce-admin/client/products/fields/attribute-field/test/utils.spec.ts b/plugins/woocommerce-admin/client/products/fields/attribute-field/test/utils.spec.ts index 71964dd5fac..0c3812eafda 100644 --- a/plugins/woocommerce-admin/client/products/fields/attribute-field/test/utils.spec.ts +++ b/plugins/woocommerce-admin/client/products/fields/attribute-field/test/utils.spec.ts @@ -6,7 +6,10 @@ import { ProductAttribute } from '@woocommerce/data'; /** * Internal dependencies */ -import { reorderSortableProductAttributePositions } from '../utils'; +import { + getAttributeKey, + reorderSortableProductAttributePositions, +} from '../utils'; const attributeList: Record< number, ProductAttribute > = { 15: { @@ -38,9 +41,9 @@ const attributeList: Record< number, ProductAttribute > = { describe( 'reorderSortableProductAttributePositions', () => { it( 'should update product attribute positions depending on JSX.Element order', () => { const elements = [ - { key: '3' }, - { key: '15' }, - { key: '1' }, + { props: { attribute: attributeList[ '3' ] } }, + { props: { attribute: attributeList[ '15' ] } }, + { props: { attribute: attributeList[ '1' ] } }, ] as JSX.Element[]; const newList = reorderSortableProductAttributePositions( elements, @@ -53,19 +56,19 @@ describe( 'reorderSortableProductAttributePositions', () => { expect( newList[ 2 ].position ).toEqual( 2 ); expect( newList[ 2 ].id ).toEqual( 1 ); } ); +} ); - it( 'should filter out elements that do not contain a key', () => { - const elements = [ - { key: '3' }, - {}, - { key: '15' }, - {}, - { key: '1' }, - ] as JSX.Element[]; - const newList = reorderSortableProductAttributePositions( - elements, - attributeList - ); - expect( newList.length ).toEqual( 3 ); +describe( 'getAttributeKey', () => { + attributeList[ '20' ] = { + id: 0, + name: 'Quality', + position: 3, + visible: true, + variation: true, + options: [ 'low', 'high' ], + }; + it( 'should return the attribute key', () => { + expect( getAttributeKey( attributeList[ '15' ] ) ).toEqual( 15 ); + expect( getAttributeKey( attributeList[ '20' ] ) ).toEqual( 'Quality' ); } ); } ); diff --git a/plugins/woocommerce-admin/client/products/fields/attribute-field/utils.ts b/plugins/woocommerce-admin/client/products/fields/attribute-field/utils.ts index 2fc31820553..8548e335bf6 100644 --- a/plugins/woocommerce-admin/client/products/fields/attribute-field/utils.ts +++ b/plugins/woocommerce-admin/client/products/fields/attribute-field/utils.ts @@ -3,6 +3,18 @@ */ import { ProductAttribute } from '@woocommerce/data'; +/** + * Returns the attribute key. The key will be the `id` or the `name` when the id is 0. + * + * @param { ProductAttribute } attribute product attribute. + * @return string|number + */ +export function getAttributeKey( + attribute: ProductAttribute +): number | string { + return attribute.id !== 0 ? attribute.id : attribute.name; +} + /** * Updates the position of a product attribute from the new items JSX.Element list. * @@ -11,12 +23,12 @@ import { ProductAttribute } from '@woocommerce/data'; */ export function reorderSortableProductAttributePositions( items: JSX.Element[], - attributeKeyValues: Record< number, ProductAttribute > + attributeKeyValues: Record< number | string, ProductAttribute > ): ProductAttribute[] { return items - .map( ( item, index ): ProductAttribute | undefined => { - const key = item.key ? parseInt( item.key as string, 10 ) : NaN; - if ( key !== NaN && attributeKeyValues[ key ] ) { + .map( ( { props }, index ): ProductAttribute | undefined => { + const key = getAttributeKey( props?.attribute ); + if ( attributeKeyValues[ key ] ) { return { ...attributeKeyValues[ key ], position: index, diff --git a/plugins/woocommerce/changelog/fix-36190_attribute_lists_corrupt_renders b/plugins/woocommerce/changelog/fix-36190_attribute_lists_corrupt_renders new file mode 100644 index 00000000000..99d4514d606 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-36190_attribute_lists_corrupt_renders @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Fix attributes/options lists corrupt render #36236