rebase from live enviornment

This commit is contained in:
Rachit Bhargava
2024-01-09 22:14:20 -05:00
parent ff0b49a046
commit 3a22fcaa4a
15968 changed files with 2344674 additions and 45234 deletions

View File

@@ -0,0 +1,27 @@
const has = ( obj: Record< string, unknown >, path: string[] ): boolean => {
return (
!! path &&
!! path.reduce< unknown >(
( prevObj, key ) =>
typeof prevObj === 'object' && prevObj !== null
? ( prevObj as Record< string, unknown > )[ key ]
: undefined,
obj
)
);
};
/**
* Utility for returning whether the given path exists in the state.
*
* @param {Object} state The state being checked
* @param {Array} path The path to check
*
* @return {boolean} True means this exists in the state.
*/
export default function hasInState(
state: Record< string, unknown >,
path: string[]
): boolean {
return has( state, path );
}

View File

@@ -0,0 +1,3 @@
export { default as hasInState } from './has-in-state';
export { default as updateState } from './update-state';
export * from './process-error-response';

View File

@@ -0,0 +1,159 @@
/**
* External dependencies
*/
import { createNotice, DEFAULT_ERROR_MESSAGE } from '@woocommerce/base-utils';
import { decodeEntities } from '@wordpress/html-entities';
import {
objectHasProp,
ApiErrorResponse,
isApiErrorResponse,
} from '@woocommerce/types';
import { noticeContexts } from '@woocommerce/base-context/event-emit/utils';
type ApiParamError = {
param: string;
id: string;
code: string;
message: string;
};
/**
* Flattens error details which are returned from the API when multiple params are not valid.
*
* - Codes will be prefixed with the param. For example, `invalid_email` becomes `billing_address_invalid_email`.
* - Additional error messages will be flattened alongside the main error message.
* - Supports 1 level of nesting.
* - Decodes HTML entities in error messages.
*/
export const getErrorDetails = (
response: ApiErrorResponse
): ApiParamError[] => {
const errorDetails = objectHasProp( response.data, 'details' )
? Object.entries( response.data.details )
: null;
if ( ! errorDetails ) {
return [];
}
return errorDetails.reduce(
(
acc,
[
param,
{ code, message, additional_errors: additionalErrors = [] },
]
) => {
return [
...acc,
{
param,
id: `${ param }_${ code }`,
code,
message: decodeEntities( message ),
},
...( Array.isArray( additionalErrors )
? additionalErrors.flatMap( ( additionalError ) => {
if (
! objectHasProp( additionalError, 'code' ) ||
! objectHasProp( additionalError, 'message' )
) {
return [];
}
return [
{
param,
id: `${ param }_${ additionalError.code }`,
code: additionalError.code,
message: decodeEntities(
additionalError.message
),
},
];
} )
: [] ),
];
},
[] as ApiParamError[]
);
};
/**
* Gets appropriate error context from error code.
*/
const getErrorContextFromCode = ( code: string ): string => {
switch ( code ) {
case 'woocommerce_rest_missing_email_address':
case 'woocommerce_rest_invalid_email_address':
return noticeContexts.CONTACT_INFORMATION;
default:
return noticeContexts.CART;
}
};
/**
* Gets appropriate error context from error param name.
*/
const getErrorContextFromParam = ( param: string ): string | undefined => {
switch ( param ) {
case 'invalid_email':
return noticeContexts.CONTACT_INFORMATION;
case 'billing_address':
return noticeContexts.BILLING_ADDRESS;
case 'shipping_address':
return noticeContexts.SHIPPING_ADDRESS;
default:
return undefined;
}
};
/**
* Processes the response for an invalid param error, with response code rest_invalid_param.
*/
const processInvalidParamResponse = (
response: ApiErrorResponse,
context: string | undefined
) => {
const errorDetails = getErrorDetails( response );
errorDetails.forEach( ( { code, message, id, param } ) => {
createNotice( 'error', message, {
id,
context:
context ||
getErrorContextFromParam( param ) ||
getErrorContextFromCode( code ),
} );
} );
};
/**
* Takes an API response object and creates error notices to display to the customer.
*
* This is where we can handle specific error codes and display notices in specific contexts.
*/
export const processErrorResponse = (
response: ApiErrorResponse | null,
context?: string | undefined
) => {
if ( ! isApiErrorResponse( response ) ) {
return;
}
if ( response.code === 'rest_invalid_param' ) {
return processInvalidParamResponse( response, context );
}
let errorMessage =
decodeEntities( response.message ) || DEFAULT_ERROR_MESSAGE;
// Replace the generic invalid JSON message with something more user friendly.
if ( response.code === 'invalid_json' ) {
errorMessage = DEFAULT_ERROR_MESSAGE;
}
createNotice( 'error', errorMessage, {
id: response.code,
context: context || getErrorContextFromCode( response.code ),
} );
};

View File

@@ -0,0 +1,37 @@
/**
* Utility for updating nested state in the path that changed.
*/
function updateNested< T >( // The state being updated
state: T,
// The path being updated
path: string[],
// The value to update for the path
value: unknown,
// The current index in the path
index = 0
): T {
const key = path[ index ] as keyof T;
if ( index === path.length - 1 ) {
return { ...state, [ key ]: value };
}
const nextState = state[ key ] || {};
return {
...state,
[ key ]: updateNested( nextState, path, value, index + 1 ),
} as T;
}
/**
* Utility for updating state and only cloning objects in the path that changed.
*/
export default function updateState< T >(
// The state being updated
state: T,
// The path being updated
path: string[],
// The value to update for the path
value: unknown
): T {
return updateNested( state, path, value );
}