Merge branch 'trunk' into feature/34906-marketing-channels-card

This commit is contained in:
Gan Eng Chin 2023-02-04 02:33:01 +08:00
commit b717ce9645
No known key found for this signature in database
GPG Key ID: 94D5D972860ADB01
22 changed files with 3012 additions and 2683 deletions

View File

@ -9,7 +9,6 @@ import {
__experimentalSelectControlMenuSlot as SelectControlMenuSlot,
Link,
} from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
import interpolateComponents from '@automattic/interpolate-components';
import { getAdminLink } from '@woocommerce/settings';
@ -17,48 +16,69 @@ import { getAdminLink } from '@woocommerce/settings';
* Internal dependencies
*/
import './attribute-field.scss';
import { AddAttributeModal } from './add-attribute-modal';
import { EditAttributeModal } from './edit-attribute-modal';
import { EnhancedProductAttribute } from '~/products/hooks/use-product-attributes';
import {
getAttributeId,
getAttributeKey,
reorderSortableProductAttributePositions,
} from './utils';
import { AttributeEmptyState } from '../attribute-empty-state';
import {
AddAttributeListItem,
AttributeListItem,
NewAttributeListItem,
} from '../attribute-list-item';
import { NewAttributeModal } from './new-attribute-modal';
type AttributeControlProps = {
value: ProductAttribute[];
onAdd?: ( attribute: EnhancedProductAttribute[] ) => void;
onChange: ( value: ProductAttribute[] ) => void;
// TODO: should we support an 'any' option to show all attributes?
attributeType?: 'regular' | 'for-variations';
onEdit?: ( attribute: ProductAttribute ) => void;
onRemove?: ( attribute: ProductAttribute ) => void;
onRemoveCancel?: ( attribute: ProductAttribute ) => void;
onNewModalCancel?: () => void;
onNewModalClose?: () => void;
onNewModalOpen?: () => void;
onEditModalCancel?: ( attribute?: ProductAttribute ) => void;
onEditModalClose?: ( attribute?: ProductAttribute ) => void;
onEditModalOpen?: ( attribute?: ProductAttribute ) => void;
uiStrings?: {
emptyStateSubtitle?: string;
newAttributeListItemLabel?: string;
newAttributeModalTitle?: string;
globalAttributeHelperMessage: string;
};
};
export const AttributeControl: React.FC< AttributeControlProps > = ( {
value,
attributeType = 'regular',
onAdd = () => {},
onChange,
onEdit = () => {},
onNewModalCancel = () => {},
onNewModalClose = () => {},
onNewModalOpen = () => {},
onEditModalCancel = () => {},
onEditModalClose = () => {},
onEditModalOpen = () => {},
onRemove = () => {},
onRemoveCancel = () => {},
uiStrings = {
newAttributeModalTitle: undefined,
emptyStateSubtitle: undefined,
newAttributeListItemLabel: undefined,
globalAttributeHelperMessage: __(
`You can change the attribute's name in {{link}}Attributes{{/link}}.`,
'woocommerce'
),
},
} ) => {
const [ showAddAttributeModal, setShowAddAttributeModal ] =
useState( false );
const [ editingAttributeId, setEditingAttributeId ] = useState<
const [ isNewModalVisible, setIsNewModalVisible ] = useState( false );
const [ currentAttributeId, setCurrentAttributeId ] = useState<
null | string
>( null );
const isOnlyForVariations = attributeType === 'for-variations';
const newAttributeProps = { variation: isOnlyForVariations };
const CANCEL_BUTTON_EVENT_NAME = isOnlyForVariations
? 'product_add_options_modal_cancel_button_click'
: 'product_add_attributes_modal_cancel_button_click';
const fetchAttributeId = ( attribute: { id: number; name: string } ) =>
`${ attribute.id }-${ attribute.name }`;
const handleChange = ( newAttributes: EnhancedProductAttribute[] ) => {
onChange(
newAttributes.map( ( attr ) => {
@ -74,79 +94,89 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
);
};
const onRemove = ( attribute: ProductAttribute ) => {
const handleRemove = ( attribute: ProductAttribute ) => {
// eslint-disable-next-line no-alert
if ( window.confirm( __( 'Remove this attribute?', 'woocommerce' ) ) ) {
recordEvent(
'product_remove_attribute_confirmation_confirm_click'
);
handleChange(
value.filter(
( attr ) =>
fetchAttributeId( attr ) !==
fetchAttributeId( attribute )
getAttributeId( attr ) !== getAttributeId( attribute )
)
);
} else {
recordEvent( 'product_remove_attribute_confirmation_cancel_click' );
onRemove( attribute );
return;
}
onRemoveCancel( attribute );
};
const onAddNewAttributes = (
newAttributes: EnhancedProductAttribute[]
) => {
const openNewModal = () => {
setIsNewModalVisible( true );
onNewModalOpen();
};
const closeNewModal = () => {
setIsNewModalVisible( false );
onNewModalClose();
};
const openEditModal = ( attribute: ProductAttribute ) => {
setCurrentAttributeId( getAttributeId( attribute ) );
onEditModalOpen( attribute );
};
const closeEditModal = ( attribute: ProductAttribute ) => {
setCurrentAttributeId( null );
onEditModalClose( attribute );
};
const handleAdd = ( newAttributes: EnhancedProductAttribute[] ) => {
handleChange( [
...( value || [] ),
...newAttributes
.filter(
( newAttr ) =>
! ( value || [] ).find( ( attr ) =>
newAttr.id === 0
? newAttr.name === attr.name // check name if custom attribute = id === 0.
: attr.id === newAttr.id
)
)
.map( ( newAttr, index ) => {
return {
...newAttributeProps,
...newAttr,
position: ( value || [] ).length + index,
};
} ),
...value,
...newAttributes.filter(
( newAttr ) =>
! value.find(
( attr ) =>
getAttributeId( newAttr ) === getAttributeId( attr )
)
),
] );
recordEvent( 'product_add_attributes_modal_add_button_click' );
setShowAddAttributeModal( false );
onAdd( newAttributes );
closeNewModal();
};
const handleEdit = ( updatedAttribute: ProductAttribute ) => {
const updatedAttributes = value.map( ( attr ) => {
if (
getAttributeId( attr ) === getAttributeId( updatedAttribute )
) {
return updatedAttribute;
}
return attr;
} );
onEdit( updatedAttribute );
handleChange( updatedAttributes );
closeEditModal( updatedAttribute );
};
if ( ! value.length ) {
return (
<>
<AttributeEmptyState
addNewLabel={
isOnlyForVariations
? __( 'Add options', 'woocommerce' )
: undefined
}
onNewClick={ () => {
recordEvent(
'product_add_first_attribute_button_click'
);
setShowAddAttributeModal( true );
} }
subtitle={
isOnlyForVariations
? __( 'No options yet', 'woocommerce' )
: undefined
}
addNewLabel={ uiStrings.newAttributeModalTitle }
onNewClick={ () => openNewModal() }
subtitle={ uiStrings.emptyStateSubtitle }
/>
{ showAddAttributeModal && (
<AddAttributeModal
{ isNewModalVisible && (
<NewAttributeModal
onCancel={ () => {
recordEvent( CANCEL_BUTTON_EVENT_NAME );
setShowAddAttributeModal( false );
closeNewModal();
onNewModalCancel();
} }
onAdd={ onAddNewAttributes }
onAdd={ handleAdd }
selectedAttributeIds={ [] }
title={ uiStrings.newAttributeModalTitle }
/>
) }
<SelectControlMenuSlot />
@ -167,20 +197,10 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
{} as Record< number | string, ProductAttribute >
);
const editingAttribute = value.find(
( attr ) => fetchAttributeId( attr ) === editingAttributeId
const currentAttribute = value.find(
( attr ) => getAttributeId( attr ) === currentAttributeId
) as EnhancedProductAttribute;
const editAttributeCopy = isOnlyForVariations
? __(
`You can change the option's name in {{link}}Attributes{{/link}}.`,
'woocommerce'
)
: __(
`You can change the attribute's name in {{link}}Attributes{{/link}}.`,
'woocommerce'
);
return (
<div className="woocommerce-attribute-field">
<Sortable
@ -204,54 +224,37 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
{ sortedAttributes.map( ( attr ) => (
<AttributeListItem
attribute={ attr }
key={ fetchAttributeId( attr ) }
onEditClick={ () =>
setEditingAttributeId( fetchAttributeId( attr ) )
}
onRemoveClick={ () => onRemove( attr ) }
key={ getAttributeId( attr ) }
onEditClick={ () => openEditModal( attr ) }
onRemoveClick={ () => handleRemove( attr ) }
/>
) ) }
</Sortable>
<AddAttributeListItem
label={
isOnlyForVariations
? __( 'Add option', 'woocommerce' )
: undefined
}
onAddClick={ () => {
recordEvent(
isOnlyForVariations
? 'product_add_option_button'
: 'product_add_attribute_button'
);
setShowAddAttributeModal( true );
} }
<NewAttributeListItem
label={ uiStrings.newAttributeListItemLabel }
onClick={ () => openNewModal() }
/>
{ showAddAttributeModal && (
<AddAttributeModal
title={
isOnlyForVariations
? __( 'Add options', 'woocommerce' )
: undefined
}
{ isNewModalVisible && (
<NewAttributeModal
title={ uiStrings.newAttributeModalTitle }
onCancel={ () => {
recordEvent( CANCEL_BUTTON_EVENT_NAME );
setShowAddAttributeModal( false );
closeNewModal();
onNewModalCancel();
} }
onAdd={ onAddNewAttributes }
onAdd={ handleAdd }
selectedAttributeIds={ value.map( ( attr ) => attr.id ) }
/>
) }
<SelectControlMenuSlot />
{ editingAttribute && (
{ currentAttribute && (
<EditAttributeModal
title={ sprintf(
/* translators: %s is the attribute name */
__( 'Edit %s', 'woocommerce' ),
editingAttribute.name
currentAttribute.name
) }
globalAttributeHelperMessage={ interpolateComponents( {
mixedString: editAttributeCopy,
mixedString: uiStrings.globalAttributeHelperMessage,
components: {
link: (
<Link
@ -266,26 +269,14 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
),
},
} ) }
onCancel={ () => setEditingAttributeId( null ) }
onEdit={ ( changedAttribute ) => {
const newAttributesSet = [ ...value ];
const changedAttributeIndex: number =
newAttributesSet.findIndex( ( attr ) =>
attr.id !== 0
? attr.id === changedAttribute.id
: attr.name === changedAttribute.name
);
newAttributesSet.splice(
changedAttributeIndex,
1,
changedAttribute
);
handleChange( newAttributesSet );
setEditingAttributeId( null );
onCancel={ () => {
closeEditModal( currentAttribute );
onEditModalCancel( currentAttribute );
} }
attribute={ editingAttribute }
onEdit={ ( updatedAttribute ) => {
handleEdit( updatedAttribute );
} }
attribute={ currentAttribute }
/>
) }
</div>

View File

@ -1,5 +1,13 @@
.woocommerce-edit-attribute-modal {
overflow: visible;
&__buttons {
margin-top: $gap-larger;
display: flex;
flex-direction: row;
gap: $gap-smaller;
justify-content: flex-end;
}
}
.woocommerce-edit-attribute-modal__body {

View File

@ -136,7 +136,7 @@ export const EditAttributeModal: React.FC< EditAttributeModalProps > = ( {
<Tooltip text={ visibleTooltip } />
</div>
</div>
<div className="woocommerce-add-attribute-modal__buttons">
<div className="woocommerce-edit-attribute-modal__buttons">
<Button
isSecondary
label={ cancelAccessibleLabel }

View File

@ -1,4 +1,4 @@
.woocommerce-add-attribute-modal {
.woocommerce-new-attribute-modal {
.components-notice.is-info {
margin-left: 0;
margin-right: 0;

View File

@ -20,7 +20,7 @@ import {
/**
* Internal dependencies
*/
import './add-attribute-modal.scss';
import './new-attribute-modal.scss';
import { AttributeInputField } from '../attribute-input-field';
import {
AttributeTermInputField,
@ -29,7 +29,7 @@ import {
import { EnhancedProductAttribute } from '~/products/hooks/use-product-attributes';
import { getProductAttributeObject } from './utils';
type AddAttributeModalProps = {
type NewAttributeModalProps = {
title?: string;
notice?: string;
attributeLabel?: string;
@ -54,7 +54,7 @@ type AttributeForm = {
attributes: Array< EnhancedProductAttribute | null >;
};
export const AddAttributeModal: React.FC< AddAttributeModalProps > = ( {
export const NewAttributeModal: React.FC< NewAttributeModalProps > = ( {
title = __( 'Add attributes', 'woocommerce' ),
notice = __(
'By default, attributes are filterable and visible on the product page. You can change these settings for each attribute separately later.',
@ -83,12 +83,11 @@ export const AddAttributeModal: React.FC< AddAttributeModalProps > = ( {
const scrollAttributeIntoView = ( index: number ) => {
setTimeout( () => {
const attributeRow = document.querySelector(
`.woocommerce-add-attribute-modal__table-row-${ index }`
`.woocommerce-new-attribute-modal__table-row-${ index }`
);
attributeRow?.scrollIntoView( { behavior: 'smooth' } );
}, 0 );
};
const [ showConfirmClose, setShowConfirmClose ] = useState( false );
const addAnother = (
values: AttributeForm,
@ -148,9 +147,9 @@ export const AddAttributeModal: React.FC< AddAttributeModalProps > = ( {
setTimeout( () => {
const valueInputField: HTMLInputElement | null =
document.querySelector(
'.woocommerce-add-attribute-modal__table-row-' +
'.woocommerce-new-attribute-modal__table-row-' +
index +
' .woocommerce-add-attribute-modal__table-attribute-value-column .woocommerce-experimental-select-control__input'
' .woocommerce-new-attribute-modal__table-attribute-value-column .woocommerce-experimental-select-control__input'
);
if ( valueInputField ) {
valueInputField.focus();
@ -198,16 +197,16 @@ export const AddAttributeModal: React.FC< AddAttributeModalProps > = ( {
onClose( values );
}
} }
className="woocommerce-add-attribute-modal"
className="woocommerce-new-attribute-modal"
>
<Notice isDismissible={ false }>
<p>{ notice }</p>
</Notice>
<div className="woocommerce-add-attribute-modal__body">
<table className="woocommerce-add-attribute-modal__table">
<div className="woocommerce-new-attribute-modal__body">
<table className="woocommerce-new-attribute-modal__table">
<thead>
<tr className="woocommerce-add-attribute-modal__table-header">
<tr className="woocommerce-new-attribute-modal__table-header">
<th>{ attributeLabel }</th>
<th>{ valueLabel }</th>
</tr>
@ -217,9 +216,9 @@ export const AddAttributeModal: React.FC< AddAttributeModalProps > = ( {
( attribute, index ) => (
<tr
key={ index }
className={ `woocommerce-add-attribute-modal__table-row woocommerce-add-attribute-modal__table-row-${ index }` }
className={ `woocommerce-new-attribute-modal__table-row woocommerce-new-attribute-modal__table-row-${ index }` }
>
<td className="woocommerce-add-attribute-modal__table-attribute-column">
<td className="woocommerce-new-attribute-modal__table-attribute-column">
<AttributeInputField
placeholder={
attributePlaceholder
@ -265,7 +264,7 @@ export const AddAttributeModal: React.FC< AddAttributeModalProps > = ( {
] }
/>
</td>
<td className="woocommerce-add-attribute-modal__table-attribute-value-column">
<td className="woocommerce-new-attribute-modal__table-attribute-value-column">
{ attribute === null ||
attribute.id !== 0 ? (
<AttributeTermInputField
@ -329,7 +328,7 @@ export const AddAttributeModal: React.FC< AddAttributeModalProps > = ( {
/>
) }
</td>
<td className="woocommerce-add-attribute-modal__table-attribute-trash-column">
<td className="woocommerce-new-attribute-modal__table-attribute-trash-column">
<Button
icon={ trash }
disabled={
@ -361,7 +360,7 @@ export const AddAttributeModal: React.FC< AddAttributeModalProps > = ( {
</div>
<div>
<Button
className="woocommerce-add-attribute-modal__add-attribute"
className="woocommerce-new-attribute-modal__add-attribute"
variant="tertiary"
label={ addAnotherAccessibleLabel }
onClick={ () => {
@ -374,7 +373,7 @@ export const AddAttributeModal: React.FC< AddAttributeModalProps > = ( {
{ addAnotherLabel }
</Button>
</div>
<div className="woocommerce-add-attribute-modal__buttons">
<div className="woocommerce-new-attribute-modal__buttons">
<Button
isSecondary
label={ cancelLabel }

View File

@ -144,7 +144,6 @@ describe( 'AttributeControl', () => {
<AttributeControl
value={ [ ...attributeList ] }
onChange={ () => {} }
attributeType="for-variations"
/>
);
} );

View File

@ -7,7 +7,7 @@ import { ProductAttribute, ProductAttributeTerm } from '@woocommerce/data';
/**
* Internal dependencies
*/
import { AddAttributeModal } from '../add-attribute-modal';
import { NewAttributeModal } from '../new-attribute-modal';
let attributeOnChange: ( val: ProductAttribute ) => void;
jest.mock( '../../attribute-input-field', () => ( {
@ -118,14 +118,14 @@ const attributeTermList: ProductAttributeTerm[] = [
},
];
describe( 'AddAttributeModal', () => {
describe( 'NewAttributeModal', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
it( 'should render at-least one row with the attribute dropdown fields', () => {
const { queryAllByText } = render(
<AddAttributeModal
<NewAttributeModal
onCancel={ () => {} }
onAdd={ () => {} }
selectedAttributeIds={ [] }
@ -139,7 +139,7 @@ describe( 'AddAttributeModal', () => {
it( 'should enable attribute term field once attribute is selected', () => {
const { queryAllByText } = render(
<AddAttributeModal
<NewAttributeModal
onCancel={ () => {} }
onAdd={ () => {} }
selectedAttributeIds={ [] }
@ -155,7 +155,7 @@ describe( 'AddAttributeModal', () => {
it( 'should allow us to add multiple new rows with the attribute fields', () => {
const { queryAllByText, queryByRole } = render(
<AddAttributeModal
<NewAttributeModal
onCancel={ () => {} }
onAdd={ () => {} }
selectedAttributeIds={ [] }
@ -175,7 +175,7 @@ describe( 'AddAttributeModal', () => {
it( 'should allow us to remove the added fields', () => {
const { queryAllByText, queryByRole, queryAllByLabelText } = render(
<AddAttributeModal
<NewAttributeModal
onCancel={ () => {} }
onAdd={ () => {} }
selectedAttributeIds={ [] }
@ -201,7 +201,7 @@ describe( 'AddAttributeModal', () => {
it( 'should not allow us to remove all the rows', () => {
const { queryAllByText, queryAllByLabelText } = render(
<AddAttributeModal
<NewAttributeModal
onCancel={ () => {} }
onAdd={ () => {} }
selectedAttributeIds={ [] }
@ -221,7 +221,7 @@ describe( 'AddAttributeModal', () => {
it( 'should not return empty attribute rows', () => {
const onAddMock = jest.fn();
const { queryAllByText, queryByLabelText, queryByRole } = render(
<AddAttributeModal
<NewAttributeModal
onCancel={ () => {} }
onAdd={ onAddMock }
selectedAttributeIds={ [] }
@ -247,7 +247,7 @@ describe( 'AddAttributeModal', () => {
it( 'should not add attribute if no terms were selected', () => {
const onAddMock = jest.fn();
const { queryByRole } = render(
<AddAttributeModal
<NewAttributeModal
onCancel={ () => {} }
onAdd={ onAddMock }
selectedAttributeIds={ [] }
@ -265,7 +265,7 @@ describe( 'AddAttributeModal', () => {
it( 'should add attribute with array of terms', () => {
const onAddMock = jest.fn();
const { queryByRole } = render(
<AddAttributeModal
<NewAttributeModal
onCancel={ () => {} }
onAdd={ onAddMock }
selectedAttributeIds={ [] }

View File

@ -15,6 +15,15 @@ export function getAttributeKey(
return attribute.id !== 0 ? attribute.id : attribute.name;
}
/**
* Get an attribute ID that works universally across global and local attributes.
*
* @param attribute Product attribute.
* @return string
*/
export const getAttributeId = ( attribute: ProductAttribute ) =>
`${ attribute.id }-${ attribute.name }`;
/**
* Updates the position of a product attribute from the new items list.
*

View File

@ -2,25 +2,24 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { DragEventHandler } from 'react';
import { Button } from '@wordpress/components';
import { ListItem } from '@woocommerce/components';
type AddAttributeListItemProps = {
type NewAttributeListItemProps = {
label?: string;
onAddClick?: () => void;
onClick?: () => void;
};
export const AddAttributeListItem: React.FC< AddAttributeListItemProps > = ( {
export const NewAttributeListItem: React.FC< NewAttributeListItemProps > = ( {
label = __( 'Add attribute', 'woocommerce' ),
onAddClick,
onClick,
} ) => {
return (
<ListItem className="woocommerce-add-attribute-list-item">
<Button
variant="secondary"
className="woocommerce-add-attribute-list-item__add-button"
onClick={ onAddClick }
onClick={ onClick }
>
{ label }
</Button>

View File

@ -2,6 +2,7 @@
* External dependencies
*/
import { ProductAttribute } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
/**
* Internal dependencies
@ -28,9 +29,33 @@ export const Attributes: React.FC< AttributesProps > = ( {
return (
<AttributeControl
attributeType="regular"
value={ attributes }
onAdd={ () => {
recordEvent( 'product_add_attributes_modal_add_button_click' );
} }
onChange={ handleChange }
onNewModalCancel={ () => {
recordEvent(
'product_add_attributes_modal_cancel_button_click'
);
} }
onNewModalOpen={ () => {
if ( ! attributes.length ) {
recordEvent( 'product_add_first_attribute_button_click' );
return;
}
recordEvent( 'product_add_attribute_button' );
} }
onRemove={ () =>
recordEvent(
'product_remove_attribute_confirmation_confirm_click'
)
}
onRemoveCancel={ () =>
recordEvent(
'product_remove_attribute_confirmation_cancel_click'
)
}
/>
);
};

View File

@ -1,7 +1,9 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Product, ProductAttribute } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useFormContext } from '@woocommerce/components';
/**
@ -40,9 +42,38 @@ export const Options: React.FC< OptionsProps > = ( {
return (
<AttributeControl
attributeType="for-variations"
value={ attributes }
onAdd={ () => {
recordEvent( 'product_add_options_modal_add_button_click' );
} }
onChange={ handleChange }
onNewModalCancel={ () => {
recordEvent( 'product_add_options_modal_cancel_button_click' );
} }
onNewModalOpen={ () => {
if ( ! attributes.length ) {
recordEvent( 'product_add_first_option_button_click' );
return;
}
recordEvent( 'product_add_option_button' );
} }
uiStrings={ {
emptyStateSubtitle: __( 'No options yet', 'woocommerce' ),
newAttributeListItemLabel: __( 'Add option', 'woocommerce' ),
newAttributeModalTitle: __( 'Add options', 'woocommerce' ),
globalAttributeHelperMessage: __(
`You can change the option's name in {{link}}Attributes{{/link}}.`,
'woocommerce'
),
} }
onRemove={ () =>
recordEvent(
'product_remove_option_confirmation_confirm_click'
)
}
onRemoveCancel={ () =>
recordEvent( 'product_remove_option_confirmation_cancel_click' )
}
/>
);
};

View File

@ -78,12 +78,21 @@ export function useProductAttributes( {
};
};
const getAugmentedAttributes = ( atts: ProductAttribute[] ) => {
return atts.map( ( attribute, index ) => ( {
...attribute,
variation: isVariationAttributes,
position: attributes.length + index,
} ) );
};
const handleChange = ( newAttributes: ProductAttribute[] ) => {
const augmentedAttributes = getAugmentedAttributes( newAttributes );
const otherAttributes = isVariationAttributes
? allAttributes.filter( ( attribute ) => ! attribute.variation )
: allAttributes.filter( ( attribute ) => !! attribute.variation );
setAttributes( newAttributes );
onChange( [ ...otherAttributes, ...newAttributes ] );
setAttributes( augmentedAttributes );
onChange( [ ...otherAttributes, ...augmentedAttributes ] );
};
useEffect( () => {

View File

@ -0,0 +1,4 @@
Significance: minor
Type: tweak
Add IR and fields priorities to list of get_country_locale() method to follow conventional way of addressing in Iran.

View File

@ -0,0 +1,4 @@
Significance: patch
Type: enhancement
Change the sass variable names to more predictable ones.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Remove attribute type logic from attribute component

View File

@ -0,0 +1,5 @@
Significance: patch
Type: update
Comment: Mark purchase tests skipped temporarily due to a change in the endpoint behavior

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
Update woocommerce-blocks to 9.4.3.

View File

@ -293,7 +293,7 @@
}
mark.yes {
color: $green;
color: var(--wc-green);
}
mark.no {

View File

@ -21,7 +21,7 @@
"maxmind-db/reader": "^1.11",
"pelago/emogrifier": "^6.0",
"woocommerce/action-scheduler": "3.5.4",
"woocommerce/woocommerce-blocks": "9.4.2"
"woocommerce/woocommerce-blocks": "9.4.3"
},
"require-dev": {
"automattic/jetpack-changelogger": "^3.3.0",

File diff suppressed because it is too large Load Diff

View File

@ -1164,6 +1164,20 @@ class WC_Countries {
'label' => __( 'State', 'woocommerce' ),
),
),
'IR' => array(
'state' => array(
'priority' => 50,
),
'city' => array(
'priority' => 60,
),
'address_1' => array(
'priority' => 70,
),
'address_2' => array(
'priority' => 80,
),
),
'IT' => array(
'postcode' => array(
'priority' => 65,

View File

@ -82,6 +82,7 @@ class WC_Admin_Tests_OnboardingTasks_Task_Purchase extends WC_Unit_Test_Case {
* Test is_complete function of Purchase task.
*/
public function test_is_not_complete_if_remaining_paid_products() {
$this->markTestSkipped( 'Skipped temporarily due to change in endpoint behavior.' );
update_option( OnboardingProfile::DATA_OPTION, array( 'product_types' => array( 'memberships' ) ) );
$this->assertEquals( false, $this->task->is_complete() );
}
@ -160,6 +161,7 @@ class WC_Admin_Tests_OnboardingTasks_Task_Purchase extends WC_Unit_Test_Case {
* Test the task title if 2 paid items exist.
*/
public function test_get_title_if_multiple_paid_themes() {
$this->markTestSkipped( 'Skipped temporarily due to change in endpoint behavior.' );
update_option(
OnboardingProfile::DATA_OPTION,
array(
@ -174,6 +176,7 @@ class WC_Admin_Tests_OnboardingTasks_Task_Purchase extends WC_Unit_Test_Case {
* Test the task title if multiple additional paid items exist.
*/
public function test_get_title_if_multiple_paid_products() {
$this->markTestSkipped( 'Skipped temporarily due to change in endpoint behavior.' );
update_option(
OnboardingProfile::DATA_OPTION,
array(