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( {
|
||||
attributes,
|
||||
clientId,
|
||||
context: { postType },
|
||||
}: ProductEditorBlockEditProps< NumberBlockAttributes > ) {
|
||||
const blockProps = useWooBlockProps( attributes );
|
||||
|
@ -47,31 +48,40 @@ export function Edit( {
|
|||
value &&
|
||||
parseFloat( value ) < min
|
||||
) {
|
||||
return sprintf(
|
||||
return {
|
||||
message: sprintf(
|
||||
// translators: %d is the minimum value of the number input.
|
||||
__(
|
||||
'Value must be greater than or equal to %d',
|
||||
'woocommerce'
|
||||
),
|
||||
min
|
||||
);
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
if (
|
||||
typeof max === 'number' &&
|
||||
value &&
|
||||
parseFloat( value ) > max
|
||||
) {
|
||||
return sprintf(
|
||||
// translators: %d is the maximum value of the number input.
|
||||
return {
|
||||
message: sprintf(
|
||||
// translators: %d is the minimum value of the number input.
|
||||
__(
|
||||
'Value must be less than or equal to %d',
|
||||
'woocommerce'
|
||||
),
|
||||
max
|
||||
);
|
||||
min
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
if ( required && ! value ) {
|
||||
return __( 'This field is required.', 'woocommerce' );
|
||||
return {
|
||||
message: __( 'This field is required.', 'woocommerce' ),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
[ value ]
|
||||
|
|
|
@ -20,6 +20,7 @@ import { TextBlockAttributes } from './types';
|
|||
|
||||
export function Edit( {
|
||||
attributes,
|
||||
clientId,
|
||||
context: { postType },
|
||||
}: ProductEditorBlockEditProps< TextBlockAttributes > ) {
|
||||
const blockProps = useWooBlockProps( attributes );
|
||||
|
@ -127,7 +128,10 @@ export function Edit( {
|
|||
input.setCustomValidity( customErrorMessage );
|
||||
|
||||
if ( ! input.validity.valid ) {
|
||||
return input.validationMessage;
|
||||
return {
|
||||
message: customErrorMessage,
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
[ type, required, pattern, minLength, maxLength, min, max ]
|
||||
|
|
|
@ -52,10 +52,13 @@ export function Edit( {
|
|||
`low_stock_amount-${ clientId }`,
|
||||
async function stockQuantityValidator() {
|
||||
if ( lowStockAmount && lowStockAmount < 0 ) {
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'This field must be a positive number.',
|
||||
'woocommerce'
|
||||
);
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
[ lowStockAmount ]
|
||||
|
|
|
@ -52,10 +52,13 @@ export function Edit( {
|
|||
`stock_quantity-${ clientId }`,
|
||||
async function stockQuantityValidator() {
|
||||
if ( manageStock && stockQuantity && stockQuantity < 0 ) {
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'Stock quantity must be a positive number.',
|
||||
'woocommerce'
|
||||
);
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
[ manageStock, stockQuantity ]
|
||||
|
|
|
@ -83,14 +83,20 @@ export function NameBlockEdit( {
|
|||
'name',
|
||||
async function nameValidator() {
|
||||
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 ) {
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'Please enter a product name shorter than 120 characters.',
|
||||
'woocommerce'
|
||||
);
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
[ name ]
|
||||
|
|
|
@ -67,23 +67,35 @@ export function Edit( {
|
|||
const listPrice = Number.parseFloat( regularPrice );
|
||||
if ( listPrice ) {
|
||||
if ( listPrice < 0 ) {
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'Regular price must be greater than or equals to zero.',
|
||||
'woocommerce'
|
||||
);
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
if (
|
||||
salePrice &&
|
||||
listPrice <= Number.parseFloat( salePrice )
|
||||
) {
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'Regular price must be greater than the sale price.',
|
||||
'woocommerce'
|
||||
);
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
} else if ( isRequired ) {
|
||||
return {
|
||||
message: sprintf(
|
||||
/* translators: label of required field. */
|
||||
return sprintf( __( '%s is required.', 'woocommerce' ), label );
|
||||
__( '%s is required.', 'woocommerce' ),
|
||||
label
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
[ regularPrice, salePrice ]
|
||||
|
|
|
@ -59,20 +59,26 @@ export function Edit( {
|
|||
async function salePriceValidator() {
|
||||
if ( salePrice ) {
|
||||
if ( Number.parseFloat( salePrice ) < 0 ) {
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'Sale price must be greater than or equals to zero.',
|
||||
'woocommerce'
|
||||
);
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
const listPrice = Number.parseFloat( regularPrice );
|
||||
if (
|
||||
! listPrice ||
|
||||
listPrice <= Number.parseFloat( salePrice )
|
||||
) {
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'Sale price must be lower than the regular price.',
|
||||
'woocommerce'
|
||||
);
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -100,14 +100,23 @@ export function Edit( {
|
|||
async function dateOnSaleFromValidator() {
|
||||
if ( showScheduleSale && dateOnSaleFromGmt ) {
|
||||
if ( ! _dateOnSaleFrom.isValid() ) {
|
||||
return __( 'Please enter a valid date.', 'woocommerce' );
|
||||
return {
|
||||
message: __(
|
||||
'Please enter a valid date.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
|
||||
if ( _dateOnSaleFrom.isAfter( _dateOnSaleTo ) ) {
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'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() {
|
||||
if ( showScheduleSale && dateOnSaleToGmt ) {
|
||||
if ( ! _dateOnSaleTo.isValid() ) {
|
||||
return __( 'Please enter a valid date.', 'woocommerce' );
|
||||
return {
|
||||
message: __(
|
||||
'Please enter a valid date.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
|
||||
if ( _dateOnSaleTo.isBefore( _dateOnSaleFrom ) ) {
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'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 }`,
|
||||
async function dimensionsWidthValidator() {
|
||||
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 ]
|
||||
|
@ -110,7 +116,13 @@ export function Edit( {
|
|||
`dimensions_length-${ clientId }`,
|
||||
async function dimensionsLengthValidator() {
|
||||
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 ]
|
||||
|
@ -124,7 +136,13 @@ export function Edit( {
|
|||
`dimensions_height-${ clientId }`,
|
||||
async function dimensionsHeightValidator() {
|
||||
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 ]
|
||||
|
@ -138,7 +156,13 @@ export function Edit( {
|
|||
`weight-${ clientId }`,
|
||||
async function weightValidator() {
|
||||
if ( weight && +weight <= 0 ) {
|
||||
return __( 'Weight must be greater than zero.', 'woocommerce' );
|
||||
return {
|
||||
message: __(
|
||||
'Weight must be greater than zero.',
|
||||
'woocommerce'
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
[ weight ]
|
||||
|
|
|
@ -32,6 +32,7 @@ import { EmptyState } from '../../../components/empty-state';
|
|||
|
||||
export function Edit( {
|
||||
attributes,
|
||||
clientId,
|
||||
context: { isInSelectedTab },
|
||||
}: ProductEditorBlockEditProps< VariationOptionsBlockAttributes > ) {
|
||||
const noticeDimissed = useRef( false );
|
||||
|
@ -125,10 +126,13 @@ export function Edit( {
|
|||
},
|
||||
} );
|
||||
}
|
||||
return __(
|
||||
return {
|
||||
message: __(
|
||||
'Set variation prices before adding this product.',
|
||||
'woocommerce'
|
||||
);
|
||||
),
|
||||
context: clientId,
|
||||
};
|
||||
}
|
||||
},
|
||||
[ totalCountWithoutPrice ]
|
||||
|
|
|
@ -24,7 +24,9 @@ export type ValidationProviderProps = {
|
|||
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 ValidatorRegistration< T > = {
|
||||
|
|
|
@ -31,7 +31,7 @@ export function useValidation< T >(
|
|||
|
||||
return {
|
||||
ref,
|
||||
error: context.errors[ validatorId ],
|
||||
error: context.errors[ validatorId ]?.message,
|
||||
isValidating,
|
||||
async validate( newData?: Record< string, unknown > ) {
|
||||
setIsValidating( true );
|
||||
|
|
|
@ -9,6 +9,7 @@ import { createElement, useRef, useState } from '@wordpress/element';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
ValidationError,
|
||||
ValidationErrors,
|
||||
ValidationProviderProps,
|
||||
Validator,
|
||||
|
@ -64,11 +65,13 @@ export function ValidationProvider< T >( {
|
|||
const result = validator( initialValue, newData );
|
||||
|
||||
return result.then( ( error ) => {
|
||||
const errorWithValidatorId: ValidationError =
|
||||
error !== undefined ? { validatorId, ...error } : undefined;
|
||||
setErrors( ( currentErrors ) => ( {
|
||||
...currentErrors,
|
||||
[ validatorId ]: error,
|
||||
[ validatorId ]: errorWithValidatorId,
|
||||
} ) );
|
||||
return error;
|
||||
return errorWithValidatorId;
|
||||
} );
|
||||
}
|
||||
|
||||
|
|
|
@ -18,21 +18,21 @@ export function errorHandler( error: WPError, productStatus: ProductStatus ) {
|
|||
return error;
|
||||
}
|
||||
|
||||
const errorObj = Object.values( error ).find(
|
||||
( value ) => value !== undefined
|
||||
) as WPError | undefined;
|
||||
|
||||
if ( 'variations' in error && error.variations ) {
|
||||
return {
|
||||
...errorObj,
|
||||
code: 'variable_product_no_variation_prices',
|
||||
message: error.variations,
|
||||
};
|
||||
}
|
||||
|
||||
const errorMessage = Object.values( error ).find(
|
||||
( value ) => value !== undefined
|
||||
) as string | undefined;
|
||||
|
||||
if ( errorMessage !== undefined ) {
|
||||
if ( errorObj !== undefined ) {
|
||||
return {
|
||||
...errorObj,
|
||||
code: 'product_form_field_error',
|
||||
message: errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue