Use the validatorId to get access to the field instead of the context (#50035)
* Remove context * Add method to get closest block * Make methods async * Add changelog * Add await to getProductErrorMessageAndProps * Fix getClientIdByField * Fix tests * Undo send id to DateTimePickerControl * Add check before calling getClientIdByField
This commit is contained in:
parent
66daa66aa3
commit
14751afeac
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: dev
|
||||
|
||||
Use the validatorId to get access to the field instead of the context #50035
|
|
@ -17,7 +17,6 @@ import { useProductEdits } from '../../../hooks/use-product-edits';
|
|||
|
||||
export function Edit( {
|
||||
attributes,
|
||||
clientId,
|
||||
context: { postType },
|
||||
}: ProductEditorBlockEditProps< NumberBlockAttributes > ) {
|
||||
const blockProps = useWooBlockProps( attributes );
|
||||
|
@ -57,7 +56,6 @@ export function Edit( {
|
|||
),
|
||||
min
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
if (
|
||||
|
@ -74,13 +72,11 @@ export function Edit( {
|
|||
),
|
||||
min
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
if ( required && ! value ) {
|
||||
return {
|
||||
message: __( 'This field is required.', 'woocommerce' ),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
@ -21,7 +21,6 @@ import { TextBlockAttributes } from './types';
|
|||
|
||||
export function Edit( {
|
||||
attributes,
|
||||
clientId,
|
||||
context: { postType },
|
||||
}: ProductEditorBlockEditProps< TextBlockAttributes > ) {
|
||||
const blockProps = useWooBlockProps( attributes );
|
||||
|
@ -135,7 +134,6 @@ export function Edit( {
|
|||
if ( ! input.validity.valid ) {
|
||||
return {
|
||||
message: customErrorMessage,
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
@ -57,7 +57,6 @@ export function Edit( {
|
|||
'This field must be a positive number.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
@ -57,7 +57,6 @@ export function Edit( {
|
|||
'Stock quantity must be a positive number.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
@ -85,7 +85,6 @@ export function NameBlockEdit( {
|
|||
if ( ! name || name === AUTO_DRAFT_NAME ) {
|
||||
return {
|
||||
message: __( 'Product name is required.', 'woocommerce' ),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -95,7 +94,6 @@ export function NameBlockEdit( {
|
|||
'Please enter a product name shorter than 120 characters.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
@ -187,10 +187,14 @@ export function ProductDetailsSectionDescriptionBlockEdit( {
|
|||
template: productTemplate.id,
|
||||
} );
|
||||
} catch ( error ) {
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
errorHandler( error as WPError, productStatus ) as WPError,
|
||||
selectedTab
|
||||
);
|
||||
const { message, errorProps } =
|
||||
await getProductErrorMessageAndProps(
|
||||
errorHandler(
|
||||
error as WPError,
|
||||
productStatus
|
||||
) as WPError,
|
||||
selectedTab
|
||||
);
|
||||
createErrorNotice( message, errorProps );
|
||||
}
|
||||
|
||||
|
@ -305,10 +309,11 @@ export function ProductDetailsSectionDescriptionBlockEdit( {
|
|||
// by the product editor.
|
||||
window.location.href = getNewPath( {}, `/product/${ productId }` );
|
||||
} catch ( error ) {
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
errorHandler( error as WPError, productStatus ) as WPError,
|
||||
selectedTab
|
||||
);
|
||||
const { message, errorProps } =
|
||||
await getProductErrorMessageAndProps(
|
||||
errorHandler( error as WPError, productStatus ) as WPError,
|
||||
selectedTab
|
||||
);
|
||||
createErrorNotice( message, errorProps );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,6 @@ export function Edit( {
|
|||
'Regular price must be greater than or equals to zero.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
if (
|
||||
|
@ -84,7 +83,6 @@ export function Edit( {
|
|||
'Regular price must be greater than the sale price.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
} else if ( isRequired ) {
|
||||
|
@ -94,7 +92,6 @@ export function Edit( {
|
|||
__( '%s is required.', 'woocommerce' ),
|
||||
label
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
@ -64,7 +64,6 @@ export function Edit( {
|
|||
'Sale price must be greater than or equals to zero.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
const listPrice = Number.parseFloat( regularPrice );
|
||||
|
@ -77,7 +76,6 @@ export function Edit( {
|
|||
'Sale price must be lower than the regular price.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,6 @@ export function Edit( {
|
|||
'Please enter a valid date.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -115,7 +114,6 @@ export function Edit( {
|
|||
'The start date of the sale must be before the end date.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +135,6 @@ export function Edit( {
|
|||
'Please enter a valid date.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -147,7 +144,6 @@ export function Edit( {
|
|||
'The end date of the sale must be after the start date.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,7 +103,6 @@ export function Edit( {
|
|||
'Width must be greater than zero.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
@ -125,7 +124,6 @@ export function Edit( {
|
|||
'Length must be greater than zero.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
@ -147,7 +145,6 @@ export function Edit( {
|
|||
'Height must be greater than zero.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
@ -169,7 +166,6 @@ export function Edit( {
|
|||
'Weight must be greater than zero.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
@ -32,7 +32,6 @@ import { EmptyState } from '../../../components/empty-state';
|
|||
|
||||
export function Edit( {
|
||||
attributes,
|
||||
clientId,
|
||||
context: { isInSelectedTab },
|
||||
}: ProductEditorBlockEditProps< VariationOptionsBlockAttributes > ) {
|
||||
const noticeDimissed = useRef( false );
|
||||
|
@ -126,7 +125,6 @@ export function Edit( {
|
|||
'Set variation prices before adding this product.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
@ -36,11 +36,9 @@ export function PreviewButton( {
|
|||
navigateTo( { url } );
|
||||
}
|
||||
},
|
||||
onSaveError( error ) {
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
async onSaveError( error ) {
|
||||
const { message, errorProps } =
|
||||
await getProductErrorMessageAndProps( error, visibleTab );
|
||||
createErrorNotice( message, errorProps );
|
||||
},
|
||||
} );
|
||||
|
|
|
@ -51,11 +51,9 @@ export function PublishButtonMenu( {
|
|||
|
||||
showSuccessNotice( scheduledProduct );
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
.catch( async ( error ) => {
|
||||
const { message, errorProps } =
|
||||
await getProductErrorMessageAndProps( error, visibleTab );
|
||||
createErrorNotice( message, errorProps );
|
||||
} )
|
||||
.finally( () => {
|
||||
|
@ -138,9 +136,9 @@ export function PublishButtonMenu( {
|
|||
);
|
||||
navigateTo( { url } );
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
.catch( async ( error ) => {
|
||||
const { message, errorProps } =
|
||||
getProductErrorMessageAndProps(
|
||||
await getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
|
@ -176,9 +174,9 @@ export function PublishButtonMenu( {
|
|||
url: productListUrl,
|
||||
} );
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
.catch( async ( error ) => {
|
||||
const { message, errorProps } =
|
||||
getProductErrorMessageAndProps(
|
||||
await getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
|
|
|
@ -62,11 +62,9 @@ export function PublishButton( {
|
|||
navigateTo( { url } );
|
||||
}
|
||||
},
|
||||
onPublishError( error ) {
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
async onPublishError( error ) {
|
||||
const { message, errorProps } =
|
||||
await getProductErrorMessageAndProps( error, visibleTab );
|
||||
createErrorNotice( message, errorProps );
|
||||
},
|
||||
} );
|
||||
|
|
|
@ -48,11 +48,9 @@ export function SaveDraftButton( {
|
|||
navigateTo( { url } );
|
||||
}
|
||||
},
|
||||
onSaveError( error ) {
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
async onSaveError( error ) {
|
||||
const { message, errorProps } =
|
||||
await getProductErrorMessageAndProps( error, visibleTab );
|
||||
createErrorNotice( message, errorProps );
|
||||
},
|
||||
} );
|
||||
|
|
|
@ -26,7 +26,7 @@ export type ValidationProviderProps = {
|
|||
};
|
||||
|
||||
export type ValidationError =
|
||||
| { message?: string; context?: string; validatorId?: string }
|
||||
| { message?: string; validatorId?: string }
|
||||
| undefined;
|
||||
export type ValidationErrors = Record< string, ValidationError >;
|
||||
|
||||
|
|
|
@ -62,5 +62,6 @@ export function useValidations< T = unknown >() {
|
|||
} );
|
||||
},
|
||||
focusByValidatorId,
|
||||
getFieldByValidatorId: context.getFieldByValidatorId,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import { useBlocksHelper } from '../use-blocks-helper';
|
|||
|
||||
const mockNavigateTo = jest.fn();
|
||||
const mockFocusByValidatorId = jest.fn();
|
||||
const mockGetFieldByValidatorId = jest.fn();
|
||||
|
||||
jest.mock( '@woocommerce/navigation', () => ( {
|
||||
getNewPath: jest.fn().mockReturnValue( '/new-path' ),
|
||||
|
@ -26,6 +27,9 @@ jest.mock( '../../contexts/validation-context', () => ( {
|
|||
focusByValidatorId: jest.fn( ( args ) =>
|
||||
mockFocusByValidatorId( args )
|
||||
),
|
||||
getFieldByValidatorId: jest.fn( ( args ) =>
|
||||
mockGetFieldByValidatorId( args )
|
||||
),
|
||||
} ),
|
||||
} ) );
|
||||
|
||||
|
@ -39,6 +43,7 @@ jest.mock( '../use-blocks-helper', () => ( {
|
|||
useBlocksHelper: jest.fn().mockReturnValue( {
|
||||
getParentTabId: jest.fn( () => 'inventory' ),
|
||||
getParentTabIdByBlockName: jest.fn( () => 'inventory' ),
|
||||
getClientIdByField: jest.fn( ( arg ) => arg ),
|
||||
} ),
|
||||
} ) );
|
||||
|
||||
|
@ -47,7 +52,7 @@ describe( 'useErrorHandler', () => {
|
|||
jest.clearAllMocks();
|
||||
} );
|
||||
|
||||
it( 'should return the correct error message and props when exists and the field is visible', () => {
|
||||
it( 'should return the correct error message and props when exists and the field is visible', async () => {
|
||||
const error = {
|
||||
code: 'product_invalid_sku',
|
||||
message: 'Invalid or duplicated SKU.',
|
||||
|
@ -57,7 +62,7 @@ describe( 'useErrorHandler', () => {
|
|||
const { result } = renderHook( () => useErrorHandler() );
|
||||
const { getProductErrorMessageAndProps } = result.current;
|
||||
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
const { message, errorProps } = await getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
|
@ -66,7 +71,7 @@ describe( 'useErrorHandler', () => {
|
|||
expect( errorProps ).toEqual( {} );
|
||||
} );
|
||||
|
||||
it( 'should return the correct error message and props when exists and the field is not visible', () => {
|
||||
it( 'should return the correct error message and props when exists and the field is not visible', async () => {
|
||||
const error = {
|
||||
code: 'product_invalid_sku',
|
||||
} as WPError;
|
||||
|
@ -75,7 +80,7 @@ describe( 'useErrorHandler', () => {
|
|||
const { result } = renderHook( () => useErrorHandler() );
|
||||
const { getProductErrorMessageAndProps } = result.current;
|
||||
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
const { message, errorProps } = await getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
|
@ -84,7 +89,7 @@ describe( 'useErrorHandler', () => {
|
|||
expect( errorProps.explicitDismiss ).toBeTruthy();
|
||||
} );
|
||||
|
||||
it( 'should call focusByValidatorId for form field errors when errorProps action is triggered', () => {
|
||||
it( 'should call focusByValidatorId for form field errors when errorProps action is triggered', async () => {
|
||||
const error = {
|
||||
code: 'product_form_field_error',
|
||||
validatorId: 'test-validator',
|
||||
|
@ -94,7 +99,7 @@ describe( 'useErrorHandler', () => {
|
|||
const { result } = renderHook( () => useErrorHandler() );
|
||||
const { getProductErrorMessageAndProps } = result.current;
|
||||
|
||||
const { errorProps } = getProductErrorMessageAndProps(
|
||||
const { errorProps } = await getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
|
@ -111,8 +116,11 @@ describe( 'useErrorHandler', () => {
|
|||
expect( mockFocusByValidatorId ).toHaveBeenCalledWith(
|
||||
'test-validator'
|
||||
);
|
||||
expect( mockGetFieldByValidatorId ).toHaveBeenCalledWith(
|
||||
'test-validator'
|
||||
);
|
||||
} );
|
||||
it( 'should call getParentTabIdByBlockName and focusByValidatorId for invalid sku errors when errorProps action is triggered', () => {
|
||||
it( 'should call getParentTabIdByBlockName and focusByValidatorId for invalid sku errors when errorProps action is triggered', async () => {
|
||||
const error = {
|
||||
code: 'product_invalid_sku',
|
||||
} as WPError;
|
||||
|
@ -121,10 +129,8 @@ describe( 'useErrorHandler', () => {
|
|||
const { result } = renderHook( () => useErrorHandler() );
|
||||
const { getProductErrorMessageAndProps } = result.current;
|
||||
|
||||
const { errorProps: fieldsErrorProps } = getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
const { errorProps: fieldsErrorProps } =
|
||||
await getProductErrorMessageAndProps( error, visibleTab );
|
||||
|
||||
expect( fieldsErrorProps ).toBeDefined();
|
||||
expect( fieldsErrorProps.actions ).toBeDefined();
|
||||
|
@ -137,7 +143,7 @@ describe( 'useErrorHandler', () => {
|
|||
|
||||
expect( mockFocusByValidatorId ).toHaveBeenCalledWith( 'sku' );
|
||||
} );
|
||||
it( 'should not call getErrorPropsWithActions for invalid sku errors when getParentTabIdByBlockName returns null', () => {
|
||||
it( 'should not call getErrorPropsWithActions for invalid sku errors when getParentTabIdByBlockName returns null', async () => {
|
||||
const error = {
|
||||
code: 'product_invalid_sku',
|
||||
} as WPError;
|
||||
|
@ -146,12 +152,13 @@ describe( 'useErrorHandler', () => {
|
|||
( useBlocksHelper as jest.Mock ).mockReturnValue( {
|
||||
getParentTabId: jest.fn( () => null ), // Mock returns null
|
||||
getParentTabIdByBlockName: jest.fn( () => null ), // Mock returns null
|
||||
getClientIdByField: jest.fn( () => null ), // Mock returns null
|
||||
} );
|
||||
|
||||
const { result } = renderHook( () => useErrorHandler() );
|
||||
const { getProductErrorMessageAndProps } = result.current;
|
||||
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
const { message, errorProps } = await getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
|
@ -161,7 +168,7 @@ describe( 'useErrorHandler', () => {
|
|||
expect( mockFocusByValidatorId ).not.toHaveBeenCalled();
|
||||
expect( message ).toBe( 'Invalid or duplicated SKU.' );
|
||||
} );
|
||||
it( 'should not call getErrorPropsWithActions for form field errors when getParentTabId returns null', () => {
|
||||
it( 'should not call getErrorPropsWithActions for form field errors when getParentTabId returns null', async () => {
|
||||
const error = {
|
||||
code: 'product_form_field_error',
|
||||
validatorId: 'test-validator',
|
||||
|
@ -172,12 +179,13 @@ describe( 'useErrorHandler', () => {
|
|||
( useBlocksHelper as jest.Mock ).mockReturnValue( {
|
||||
getParentTabId: jest.fn( () => null ), // Mock returns null
|
||||
getParentTabIdByBlockName: jest.fn( () => null ), // Mock returns null
|
||||
getClientIdByField: jest.fn( () => null ), // Mock returns null
|
||||
} );
|
||||
|
||||
const { result } = renderHook( () => useErrorHandler() );
|
||||
const { getProductErrorMessageAndProps } = result.current;
|
||||
|
||||
const { message, errorProps } = getProductErrorMessageAndProps(
|
||||
const { message, errorProps } = await getProductErrorMessageAndProps(
|
||||
error,
|
||||
visibleTab
|
||||
);
|
||||
|
@ -185,6 +193,9 @@ describe( 'useErrorHandler', () => {
|
|||
expect( errorProps ).toBeDefined();
|
||||
expect( errorProps.actions ).not.toBeDefined();
|
||||
expect( mockFocusByValidatorId ).not.toHaveBeenCalled();
|
||||
expect( mockGetFieldByValidatorId ).toHaveBeenCalledWith(
|
||||
'test-validator'
|
||||
);
|
||||
expect( message ).toBe( 'Test error message' );
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -22,7 +22,14 @@ export function useBlocksHelper() {
|
|||
return attributes?.id;
|
||||
}
|
||||
|
||||
function getParentTabId( clientId?: string ) {
|
||||
function getClientIdByField( field: HTMLElement ) {
|
||||
const parentBlockElement = field.closest(
|
||||
'[data-block]'
|
||||
) as HTMLElement;
|
||||
return parentBlockElement?.dataset.block;
|
||||
}
|
||||
|
||||
function getParentTabId( clientId?: string | null ) {
|
||||
if ( clientId ) {
|
||||
return getClosestParentTabId( clientId );
|
||||
}
|
||||
|
@ -41,6 +48,7 @@ export function useBlocksHelper() {
|
|||
}
|
||||
|
||||
return {
|
||||
getClientIdByField,
|
||||
getParentTabId,
|
||||
getParentTabIdByBlockName,
|
||||
};
|
||||
|
|
|
@ -24,7 +24,6 @@ export type WPError = {
|
|||
code: WPErrorCode;
|
||||
message: string;
|
||||
validatorId?: string;
|
||||
context?: string;
|
||||
};
|
||||
|
||||
type ErrorProps = {
|
||||
|
@ -41,10 +40,10 @@ type UseErrorHandlerTypes = {
|
|||
getProductErrorMessageAndProps: (
|
||||
error: WPError,
|
||||
visibleTab: string | null
|
||||
) => {
|
||||
) => Promise< {
|
||||
message: string;
|
||||
errorProps: ErrorProps;
|
||||
};
|
||||
} >;
|
||||
};
|
||||
|
||||
function getUrl( tab: string ): string {
|
||||
|
@ -74,22 +73,32 @@ function getErrorPropsWithActions(
|
|||
}
|
||||
|
||||
export const useErrorHandler = (): UseErrorHandlerTypes => {
|
||||
const { focusByValidatorId } = useValidations();
|
||||
const { getParentTabId, getParentTabIdByBlockName } = useBlocksHelper();
|
||||
const { focusByValidatorId, getFieldByValidatorId } = useValidations();
|
||||
const { getClientIdByField, getParentTabId, getParentTabIdByBlockName } =
|
||||
useBlocksHelper();
|
||||
|
||||
async function getClientIdByValidatorId( validatorId: string ) {
|
||||
if ( ! validatorId ) {
|
||||
return null;
|
||||
}
|
||||
const field = await getFieldByValidatorId( validatorId );
|
||||
if ( ! field ) {
|
||||
return null;
|
||||
}
|
||||
return getClientIdByField( field );
|
||||
}
|
||||
|
||||
const getProductErrorMessageAndProps = useCallback(
|
||||
( error: WPError, visibleTab: string | null ) => {
|
||||
async ( error: WPError, visibleTab: string | null ) => {
|
||||
const response = {
|
||||
message: '',
|
||||
errorProps: {} as ErrorProps,
|
||||
};
|
||||
const {
|
||||
code,
|
||||
context = '',
|
||||
message: errorMessage,
|
||||
validatorId = '',
|
||||
} = error;
|
||||
const errorContext = getParentTabId( context );
|
||||
const { code, message: errorMessage, validatorId = '' } = error;
|
||||
|
||||
const clientId = await getClientIdByValidatorId( validatorId );
|
||||
const errorContext = getParentTabId( clientId );
|
||||
|
||||
switch ( code ) {
|
||||
case 'variable_product_no_variation_prices':
|
||||
response.message = errorMessage;
|
||||
|
|
Loading…
Reference in New Issue