Add context to errors (#49242)
* Add context to errors * Add changelog * Fix product manager hook * Add useBlocksHelper # Conflicts: # packages/js/product-editor/src/blocks/product-fields/shipping-dimensions/edit.tsx * Send clientId as context * Add validatorId when validating * Small refactor errorHandler * Improve method
This commit is contained in:
parent
9fa32b4f2b
commit
64ce7bd732
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: dev
|
||||||
|
|
||||||
|
Add context to errors #49242
|
|
@ -17,6 +17,7 @@ import { useProductEdits } from '../../../hooks/use-product-edits';
|
||||||
|
|
||||||
export function Edit( {
|
export function Edit( {
|
||||||
attributes,
|
attributes,
|
||||||
|
clientId,
|
||||||
context: { postType },
|
context: { postType },
|
||||||
}: ProductEditorBlockEditProps< NumberBlockAttributes > ) {
|
}: ProductEditorBlockEditProps< NumberBlockAttributes > ) {
|
||||||
const blockProps = useWooBlockProps( attributes );
|
const blockProps = useWooBlockProps( attributes );
|
||||||
|
@ -47,31 +48,40 @@ export function Edit( {
|
||||||
value &&
|
value &&
|
||||||
parseFloat( value ) < min
|
parseFloat( value ) < min
|
||||||
) {
|
) {
|
||||||
return sprintf(
|
return {
|
||||||
// translators: %d is the minimum value of the number input.
|
message: sprintf(
|
||||||
__(
|
// translators: %d is the minimum value of the number input.
|
||||||
'Value must be greater than or equal to %d',
|
__(
|
||||||
'woocommerce'
|
'Value must be greater than or equal to %d',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
min
|
||||||
),
|
),
|
||||||
min
|
context: clientId,
|
||||||
);
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
typeof max === 'number' &&
|
typeof max === 'number' &&
|
||||||
value &&
|
value &&
|
||||||
parseFloat( value ) > max
|
parseFloat( value ) > max
|
||||||
) {
|
) {
|
||||||
return sprintf(
|
return {
|
||||||
// translators: %d is the maximum value of the number input.
|
message: sprintf(
|
||||||
__(
|
// translators: %d is the minimum value of the number input.
|
||||||
'Value must be less than or equal to %d',
|
__(
|
||||||
'woocommerce'
|
'Value must be less than or equal to %d',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
min
|
||||||
),
|
),
|
||||||
max
|
context: clientId,
|
||||||
);
|
};
|
||||||
}
|
}
|
||||||
if ( required && ! value ) {
|
if ( required && ! value ) {
|
||||||
return __( 'This field is required.', 'woocommerce' );
|
return {
|
||||||
|
message: __( 'This field is required.', 'woocommerce' ),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ value ]
|
[ value ]
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { TextBlockAttributes } from './types';
|
||||||
|
|
||||||
export function Edit( {
|
export function Edit( {
|
||||||
attributes,
|
attributes,
|
||||||
|
clientId,
|
||||||
context: { postType },
|
context: { postType },
|
||||||
}: ProductEditorBlockEditProps< TextBlockAttributes > ) {
|
}: ProductEditorBlockEditProps< TextBlockAttributes > ) {
|
||||||
const blockProps = useWooBlockProps( attributes );
|
const blockProps = useWooBlockProps( attributes );
|
||||||
|
@ -127,7 +128,10 @@ export function Edit( {
|
||||||
input.setCustomValidity( customErrorMessage );
|
input.setCustomValidity( customErrorMessage );
|
||||||
|
|
||||||
if ( ! input.validity.valid ) {
|
if ( ! input.validity.valid ) {
|
||||||
return input.validationMessage;
|
return {
|
||||||
|
message: customErrorMessage,
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ type, required, pattern, minLength, maxLength, min, max ]
|
[ type, required, pattern, minLength, maxLength, min, max ]
|
||||||
|
|
|
@ -52,10 +52,13 @@ export function Edit( {
|
||||||
`low_stock_amount-${ clientId }`,
|
`low_stock_amount-${ clientId }`,
|
||||||
async function stockQuantityValidator() {
|
async function stockQuantityValidator() {
|
||||||
if ( lowStockAmount && lowStockAmount < 0 ) {
|
if ( lowStockAmount && lowStockAmount < 0 ) {
|
||||||
return __(
|
return {
|
||||||
'This field must be a positive number.',
|
message: __(
|
||||||
'woocommerce'
|
'This field must be a positive number.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ lowStockAmount ]
|
[ lowStockAmount ]
|
||||||
|
|
|
@ -52,10 +52,13 @@ export function Edit( {
|
||||||
`stock_quantity-${ clientId }`,
|
`stock_quantity-${ clientId }`,
|
||||||
async function stockQuantityValidator() {
|
async function stockQuantityValidator() {
|
||||||
if ( manageStock && stockQuantity && stockQuantity < 0 ) {
|
if ( manageStock && stockQuantity && stockQuantity < 0 ) {
|
||||||
return __(
|
return {
|
||||||
'Stock quantity must be a positive number.',
|
message: __(
|
||||||
'woocommerce'
|
'Stock quantity must be a positive number.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ manageStock, stockQuantity ]
|
[ manageStock, stockQuantity ]
|
||||||
|
|
|
@ -83,14 +83,20 @@ export function NameBlockEdit( {
|
||||||
'name',
|
'name',
|
||||||
async function nameValidator() {
|
async function nameValidator() {
|
||||||
if ( ! name || name === AUTO_DRAFT_NAME ) {
|
if ( ! name || name === AUTO_DRAFT_NAME ) {
|
||||||
return __( 'Product name is required.', 'woocommerce' );
|
return {
|
||||||
|
message: __( 'Product name is required.', 'woocommerce' ),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( name.length > 120 ) {
|
if ( name.length > 120 ) {
|
||||||
return __(
|
return {
|
||||||
'Please enter a product name shorter than 120 characters.',
|
message: __(
|
||||||
'woocommerce'
|
'Please enter a product name shorter than 120 characters.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ name ]
|
[ name ]
|
||||||
|
|
|
@ -67,23 +67,35 @@ export function Edit( {
|
||||||
const listPrice = Number.parseFloat( regularPrice );
|
const listPrice = Number.parseFloat( regularPrice );
|
||||||
if ( listPrice ) {
|
if ( listPrice ) {
|
||||||
if ( listPrice < 0 ) {
|
if ( listPrice < 0 ) {
|
||||||
return __(
|
return {
|
||||||
'Regular price must be greater than or equals to zero.',
|
message: __(
|
||||||
'woocommerce'
|
'Regular price must be greater than or equals to zero.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
salePrice &&
|
salePrice &&
|
||||||
listPrice <= Number.parseFloat( salePrice )
|
listPrice <= Number.parseFloat( salePrice )
|
||||||
) {
|
) {
|
||||||
return __(
|
return {
|
||||||
'Regular price must be greater than the sale price.',
|
message: __(
|
||||||
'woocommerce'
|
'Regular price must be greater than the sale price.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else if ( isRequired ) {
|
} else if ( isRequired ) {
|
||||||
/* translators: label of required field. */
|
return {
|
||||||
return sprintf( __( '%s is required.', 'woocommerce' ), label );
|
message: sprintf(
|
||||||
|
/* translators: label of required field. */
|
||||||
|
__( '%s is required.', 'woocommerce' ),
|
||||||
|
label
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ regularPrice, salePrice ]
|
[ regularPrice, salePrice ]
|
||||||
|
|
|
@ -59,20 +59,26 @@ export function Edit( {
|
||||||
async function salePriceValidator() {
|
async function salePriceValidator() {
|
||||||
if ( salePrice ) {
|
if ( salePrice ) {
|
||||||
if ( Number.parseFloat( salePrice ) < 0 ) {
|
if ( Number.parseFloat( salePrice ) < 0 ) {
|
||||||
return __(
|
return {
|
||||||
'Sale price must be greater than or equals to zero.',
|
message: __(
|
||||||
'woocommerce'
|
'Sale price must be greater than or equals to zero.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const listPrice = Number.parseFloat( regularPrice );
|
const listPrice = Number.parseFloat( regularPrice );
|
||||||
if (
|
if (
|
||||||
! listPrice ||
|
! listPrice ||
|
||||||
listPrice <= Number.parseFloat( salePrice )
|
listPrice <= Number.parseFloat( salePrice )
|
||||||
) {
|
) {
|
||||||
return __(
|
return {
|
||||||
'Sale price must be lower than the regular price.',
|
message: __(
|
||||||
'woocommerce'
|
'Sale price must be lower than the regular price.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -100,14 +100,23 @@ export function Edit( {
|
||||||
async function dateOnSaleFromValidator() {
|
async function dateOnSaleFromValidator() {
|
||||||
if ( showScheduleSale && dateOnSaleFromGmt ) {
|
if ( showScheduleSale && dateOnSaleFromGmt ) {
|
||||||
if ( ! _dateOnSaleFrom.isValid() ) {
|
if ( ! _dateOnSaleFrom.isValid() ) {
|
||||||
return __( 'Please enter a valid date.', 'woocommerce' );
|
return {
|
||||||
|
message: __(
|
||||||
|
'Please enter a valid date.',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( _dateOnSaleFrom.isAfter( _dateOnSaleTo ) ) {
|
if ( _dateOnSaleFrom.isAfter( _dateOnSaleTo ) ) {
|
||||||
return __(
|
return {
|
||||||
'The start date of the sale must be before the end date.',
|
message: __(
|
||||||
'woocommerce'
|
'The start date of the sale must be before the end date.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -123,14 +132,23 @@ export function Edit( {
|
||||||
async function dateOnSaleToValidator() {
|
async function dateOnSaleToValidator() {
|
||||||
if ( showScheduleSale && dateOnSaleToGmt ) {
|
if ( showScheduleSale && dateOnSaleToGmt ) {
|
||||||
if ( ! _dateOnSaleTo.isValid() ) {
|
if ( ! _dateOnSaleTo.isValid() ) {
|
||||||
return __( 'Please enter a valid date.', 'woocommerce' );
|
return {
|
||||||
|
message: __(
|
||||||
|
'Please enter a valid date.',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( _dateOnSaleTo.isBefore( _dateOnSaleFrom ) ) {
|
if ( _dateOnSaleTo.isBefore( _dateOnSaleFrom ) ) {
|
||||||
return __(
|
return {
|
||||||
'The end date of the sale must be after the start date.',
|
message: __(
|
||||||
'woocommerce'
|
'The end date of the sale must be after the start date.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -96,7 +96,13 @@ export function Edit( {
|
||||||
`dimensions_width-${ clientId }`,
|
`dimensions_width-${ clientId }`,
|
||||||
async function dimensionsWidthValidator() {
|
async function dimensionsWidthValidator() {
|
||||||
if ( dimensions?.width && +dimensions.width <= 0 ) {
|
if ( dimensions?.width && +dimensions.width <= 0 ) {
|
||||||
return __( 'Width must be greater than zero.', 'woocommerce' );
|
return {
|
||||||
|
message: __(
|
||||||
|
'Width must be greater than zero.',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ dimensions?.width ]
|
[ dimensions?.width ]
|
||||||
|
@ -110,7 +116,13 @@ export function Edit( {
|
||||||
`dimensions_length-${ clientId }`,
|
`dimensions_length-${ clientId }`,
|
||||||
async function dimensionsLengthValidator() {
|
async function dimensionsLengthValidator() {
|
||||||
if ( dimensions?.length && +dimensions.length <= 0 ) {
|
if ( dimensions?.length && +dimensions.length <= 0 ) {
|
||||||
return __( 'Length must be greater than zero.', 'woocommerce' );
|
return {
|
||||||
|
message: __(
|
||||||
|
'Length must be greater than zero.',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ dimensions?.length ]
|
[ dimensions?.length ]
|
||||||
|
@ -124,7 +136,13 @@ export function Edit( {
|
||||||
`dimensions_height-${ clientId }`,
|
`dimensions_height-${ clientId }`,
|
||||||
async function dimensionsHeightValidator() {
|
async function dimensionsHeightValidator() {
|
||||||
if ( dimensions?.height && +dimensions.height <= 0 ) {
|
if ( dimensions?.height && +dimensions.height <= 0 ) {
|
||||||
return __( 'Height must be greater than zero.', 'woocommerce' );
|
return {
|
||||||
|
message: __(
|
||||||
|
'Height must be greater than zero.',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ dimensions?.height ]
|
[ dimensions?.height ]
|
||||||
|
@ -138,7 +156,13 @@ export function Edit( {
|
||||||
`weight-${ clientId }`,
|
`weight-${ clientId }`,
|
||||||
async function weightValidator() {
|
async function weightValidator() {
|
||||||
if ( weight && +weight <= 0 ) {
|
if ( weight && +weight <= 0 ) {
|
||||||
return __( 'Weight must be greater than zero.', 'woocommerce' );
|
return {
|
||||||
|
message: __(
|
||||||
|
'Weight must be greater than zero.',
|
||||||
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ weight ]
|
[ weight ]
|
||||||
|
|
|
@ -32,6 +32,7 @@ import { EmptyState } from '../../../components/empty-state';
|
||||||
|
|
||||||
export function Edit( {
|
export function Edit( {
|
||||||
attributes,
|
attributes,
|
||||||
|
clientId,
|
||||||
context: { isInSelectedTab },
|
context: { isInSelectedTab },
|
||||||
}: ProductEditorBlockEditProps< VariationOptionsBlockAttributes > ) {
|
}: ProductEditorBlockEditProps< VariationOptionsBlockAttributes > ) {
|
||||||
const noticeDimissed = useRef( false );
|
const noticeDimissed = useRef( false );
|
||||||
|
@ -125,10 +126,13 @@ export function Edit( {
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
return __(
|
return {
|
||||||
'Set variation prices before adding this product.',
|
message: __(
|
||||||
'woocommerce'
|
'Set variation prices before adding this product.',
|
||||||
);
|
'woocommerce'
|
||||||
|
),
|
||||||
|
context: clientId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ totalCountWithoutPrice ]
|
[ totalCountWithoutPrice ]
|
||||||
|
|
|
@ -24,7 +24,9 @@ export type ValidationProviderProps = {
|
||||||
productId: number;
|
productId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ValidationError = string | undefined;
|
export type ValidationError =
|
||||||
|
| { message?: string; context?: string; validatorId?: string }
|
||||||
|
| undefined;
|
||||||
export type ValidationErrors = Record< string, ValidationError >;
|
export type ValidationErrors = Record< string, ValidationError >;
|
||||||
|
|
||||||
export type ValidatorRegistration< T > = {
|
export type ValidatorRegistration< T > = {
|
||||||
|
|
|
@ -31,7 +31,7 @@ export function useValidation< T >(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ref,
|
ref,
|
||||||
error: context.errors[ validatorId ],
|
error: context.errors[ validatorId ]?.message,
|
||||||
isValidating,
|
isValidating,
|
||||||
async validate( newData?: Record< string, unknown > ) {
|
async validate( newData?: Record< string, unknown > ) {
|
||||||
setIsValidating( true );
|
setIsValidating( true );
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { createElement, useRef, useState } from '@wordpress/element';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
|
ValidationError,
|
||||||
ValidationErrors,
|
ValidationErrors,
|
||||||
ValidationProviderProps,
|
ValidationProviderProps,
|
||||||
Validator,
|
Validator,
|
||||||
|
@ -64,11 +65,13 @@ export function ValidationProvider< T >( {
|
||||||
const result = validator( initialValue, newData );
|
const result = validator( initialValue, newData );
|
||||||
|
|
||||||
return result.then( ( error ) => {
|
return result.then( ( error ) => {
|
||||||
|
const errorWithValidatorId: ValidationError =
|
||||||
|
error !== undefined ? { validatorId, ...error } : undefined;
|
||||||
setErrors( ( currentErrors ) => ( {
|
setErrors( ( currentErrors ) => ( {
|
||||||
...currentErrors,
|
...currentErrors,
|
||||||
[ validatorId ]: error,
|
[ validatorId ]: errorWithValidatorId,
|
||||||
} ) );
|
} ) );
|
||||||
return error;
|
return errorWithValidatorId;
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,21 +18,21 @@ export function errorHandler( error: WPError, productStatus: ProductStatus ) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const errorObj = Object.values( error ).find(
|
||||||
|
( value ) => value !== undefined
|
||||||
|
) as WPError | undefined;
|
||||||
|
|
||||||
if ( 'variations' in error && error.variations ) {
|
if ( 'variations' in error && error.variations ) {
|
||||||
return {
|
return {
|
||||||
|
...errorObj,
|
||||||
code: 'variable_product_no_variation_prices',
|
code: 'variable_product_no_variation_prices',
|
||||||
message: error.variations,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorMessage = Object.values( error ).find(
|
if ( errorObj !== undefined ) {
|
||||||
( value ) => value !== undefined
|
|
||||||
) as string | undefined;
|
|
||||||
|
|
||||||
if ( errorMessage !== undefined ) {
|
|
||||||
return {
|
return {
|
||||||
|
...errorObj,
|
||||||
code: 'product_form_field_error',
|
code: 'product_form_field_error',
|
||||||
message: errorMessage,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue