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,8 @@
export const ACTION_TYPES = {
SET_VALIDATION_ERRORS: 'SET_VALIDATION_ERRORS',
CLEAR_VALIDATION_ERROR: 'CLEAR_VALIDATION_ERROR',
CLEAR_VALIDATION_ERRORS: 'CLEAR_VALIDATION_ERRORS',
HIDE_VALIDATION_ERROR: 'HIDE_VALIDATION_ERROR',
SHOW_VALIDATION_ERROR: 'SHOW_VALIDATION_ERROR',
SHOW_ALL_VALIDATION_ERRORS: 'SHOW_ALL_VALIDATION_ERRORS',
} as const;

View File

@@ -0,0 +1,70 @@
/**
* External dependencies
*/
import deprecated from '@wordpress/deprecated';
import { FieldValidationStatus } from '@woocommerce/types';
/**
* Internal dependencies
*/
import { ACTION_TYPES as types } from './action-types';
import { ReturnOrGeneratorYieldUnion } from '../mapped-types';
export const setValidationErrors = (
errors: Record< string, FieldValidationStatus >
) => ( {
type: types.SET_VALIDATION_ERRORS,
errors,
} );
/**
* Clears validation errors for the given ids.
*
* @param errors Array of error ids to clear.
*/
export const clearValidationErrors = ( errors?: string[] | undefined ) => ( {
type: types.CLEAR_VALIDATION_ERRORS,
errors,
} );
export const clearAllValidationErrors = () => {
deprecated( 'clearAllValidationErrors', {
version: '9.0.0',
alternative: 'clearValidationErrors',
plugin: 'WooCommerce Blocks',
link: 'https://github.com/woocommerce/woocommerce-blocks/pull/7601',
hint: 'Calling `clearValidationErrors` with no arguments will clear all validation errors.',
} );
// Return clearValidationErrors which will clear all errors by defaults if no error ids are passed.
return clearValidationErrors();
};
export const clearValidationError = ( error: string ) => ( {
type: types.CLEAR_VALIDATION_ERROR,
error,
} );
export const hideValidationError = ( error: string ) => ( {
type: types.HIDE_VALIDATION_ERROR,
error,
} );
export const showValidationError = ( error: string ) => ( {
type: types.SHOW_VALIDATION_ERROR,
error,
} );
export const showAllValidationErrors = () => ( {
type: types.SHOW_ALL_VALIDATION_ERRORS,
} );
export type ValidationAction = ReturnOrGeneratorYieldUnion<
| typeof setValidationErrors
| typeof clearAllValidationErrors
| typeof clearValidationError
| typeof clearValidationErrors
| typeof hideValidationError
| typeof showValidationError
| typeof showAllValidationErrors
>;

View File

@@ -0,0 +1 @@
export const STORE_KEY = 'wc/store/validation';

View File

@@ -0,0 +1,35 @@
/**
* External dependencies
*/
import { createReduxStore, register } from '@wordpress/data';
/**
* Internal dependencies
*/
import reducer from './reducers';
import { STORE_KEY } from './constants';
import * as actions from './actions';
import * as selectors from './selectors';
import { DispatchFromMap, SelectFromMap } from '../mapped-types';
export const config = {
reducer,
selectors,
actions,
};
const store = createReduxStore( STORE_KEY, config );
register( store );
export const VALIDATION_STORE_KEY = STORE_KEY;
declare module '@wordpress/data' {
function dispatch(
key: typeof VALIDATION_STORE_KEY
): DispatchFromMap< typeof actions >;
function select( key: typeof VALIDATION_STORE_KEY ): SelectFromMap<
typeof selectors
> & {
hasFinishedResolution: ( selector: string ) => boolean;
};
}

View File

@@ -0,0 +1,98 @@
/**
* External dependencies
*/
import type { Reducer } from 'redux';
import isShallowEqual from '@wordpress/is-shallow-equal';
import { isString, FieldValidationStatus } from '@woocommerce/types';
/**
* Internal dependencies
*/
import { ValidationAction } from './actions';
import { ACTION_TYPES as types } from './action-types';
const reducer: Reducer< Record< string, FieldValidationStatus > > = (
state: Record< string, FieldValidationStatus > = {},
action: Partial< ValidationAction >
) => {
const newState = { ...state };
switch ( action.type ) {
case types.SET_VALIDATION_ERRORS:
if ( ! action.errors ) {
return state;
}
const hasNewError = Object.entries( action.errors ).some(
( [ property, error ] ) => {
if ( typeof error?.message !== 'string' ) {
return false;
}
if (
state.hasOwnProperty( property ) &&
isShallowEqual( state[ property ], error )
) {
return false;
}
return true;
}
);
if ( ! hasNewError ) {
return state;
}
return { ...state, ...action.errors };
case types.CLEAR_VALIDATION_ERROR:
if (
! isString( action.error ) ||
! newState.hasOwnProperty( action.error )
) {
return newState;
}
delete newState[ action.error ];
return newState;
case types.CLEAR_VALIDATION_ERRORS:
const { errors } = action;
if ( typeof errors === 'undefined' ) {
return {};
}
if ( ! Array.isArray( errors ) ) {
return newState;
}
errors.forEach( ( error ) => {
if ( newState.hasOwnProperty( error ) ) {
delete newState[ error ];
}
} );
return newState;
case types.HIDE_VALIDATION_ERROR:
if (
! isString( action.error ) ||
! newState.hasOwnProperty( action.error )
) {
return newState;
}
newState[ action.error ].hidden = true;
return newState;
case types.SHOW_VALIDATION_ERROR:
if (
! isString( action.error ) ||
! newState.hasOwnProperty( action.error )
) {
return newState;
}
newState[ action.error ].hidden = false;
return newState;
case types.SHOW_ALL_VALIDATION_ERRORS:
Object.keys( newState ).forEach( ( property ) => {
if ( newState[ property ].hidden ) {
newState[ property ].hidden = false;
}
} );
return { ...newState };
default:
return state;
}
};
export type State = ReturnType< typeof reducer >;
export default reducer;

View File

@@ -0,0 +1,38 @@
/**
* Internal dependencies
*/
import type { State } from './reducers';
/**
* Gets a validation error by ID.
*
* @param { State } state The current state.
* @param { string } errorId The error ID.
* @return { string } The validation error.
*/
export const getValidationError = ( state: State, errorId: string ) =>
state[ errorId ];
/**
* Gets a validation error ID for use in HTML which can be used as a CSS selector, or to reference an error message.
*
* @param { State } state The current state.
* @param { string } errorId The error ID.
* @return { string } The validation error ID.
*/
export const getValidationErrorId = ( state: State, errorId: string ) => {
if ( ! state.hasOwnProperty( errorId ) || state[ errorId ].hidden ) {
return;
}
return `validate-error-${ errorId }`;
};
/**
* Whether the store has validation errors.
*
* @param { State } state The current state.
* @return { boolean } Whether the store has validation errors or not.
*/
export const hasValidationErrors = ( state: State ) => {
return Object.keys( state ).length > 0;
};

View File

@@ -0,0 +1,273 @@
/**
* External dependencies
*/
import { FieldValidationStatus } from '@woocommerce/types';
/**
* Internal dependencies
*/
import reducer from '../reducers';
import { ACTION_TYPES as types } from '.././action-types';
import { ValidationAction } from '../actions';
describe( 'Validation reducer', () => {
it( 'Sets a single validation error', () => {
const singleValidationAction: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
singleValidationError: {
message: 'This is a single validation error message',
hidden: false,
},
},
};
const nextState = reducer( {}, singleValidationAction );
expect( nextState ).toEqual( {
singleValidationError: {
message: 'This is a single validation error message',
hidden: false,
},
} );
} );
it( 'Does not add new errors if the same error already exists in state', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
};
const existingErrorValidation: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
},
};
const nextState = reducer( state, existingErrorValidation );
expect( nextState ).toEqual( {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
} );
} );
it( 'Does not add new errors if error message is not string, but keeps existing errors', () => {
const integerErrorAction: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
integerError: {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore ignoring because we're testing runtime errors with integers.
message: 1234,
hidden: false,
},
},
};
const nextState = reducer( {}, integerErrorAction );
expect( nextState ).not.toHaveProperty( 'integerError' );
} );
it( 'Updates existing error if message or hidden property changes', () => {
const state: Record< string, FieldValidationStatus > = {
existingValidationError: {
message: 'This is an existing error message',
hidden: false,
},
};
const updateExistingErrorAction: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
existingValidationError: {
message: 'This is an existing error message',
hidden: true,
},
},
};
const nextState = reducer( state, updateExistingErrorAction );
expect( nextState ).toEqual( {
existingValidationError: {
message: 'This is an existing error message',
hidden: true,
},
} );
} );
it( 'Appends new errors to list of existing errors', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
};
const addNewError: ValidationAction = {
type: types.SET_VALIDATION_ERRORS,
errors: {
newError: {
message: 'This is a new error',
hidden: false,
},
},
};
const nextState = reducer( state, addNewError );
expect( nextState ).toEqual( {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
newError: {
message: 'This is a new error',
hidden: false,
},
} );
} );
it( 'Clears all validation errors', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
};
const clearAllErrors: ValidationAction = {
type: types.CLEAR_VALIDATION_ERRORS,
errors: undefined,
};
const nextState = reducer( state, clearAllErrors );
expect( nextState ).toEqual( {} );
} );
it( 'Clears a single validation error', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
testError: {
message: 'This is error should not be removed',
hidden: false,
},
};
const clearError: ValidationAction = {
type: types.CLEAR_VALIDATION_ERROR,
error: 'existingError',
};
const nextState = reducer( state, clearError );
expect( nextState ).not.toHaveProperty( 'existingError' );
expect( nextState ).toHaveProperty( 'testError' );
} );
it( 'Clears multiple validation errors', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
testError: {
message: 'This is error should also be removed',
hidden: false,
},
};
const clearError: ValidationAction = {
type: types.CLEAR_VALIDATION_ERRORS,
errors: [ 'existingError', 'testError' ],
};
const nextState = reducer( state, clearError );
expect( nextState ).not.toHaveProperty( 'existingError' );
expect( nextState ).not.toHaveProperty( 'testError' );
} );
it( 'Hides a single validation error', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
testError: {
message: 'This is error should not be removed',
hidden: false,
},
};
const testAction: ValidationAction = {
type: types.HIDE_VALIDATION_ERROR,
error: 'existingError',
};
const nextState = reducer( state, testAction );
expect( nextState ).toEqual( {
existingError: {
message: 'This is an existing error message',
hidden: true,
},
testError: {
message: 'This is error should not be removed',
hidden: false,
},
} );
} );
it( 'Shows a single validation error', () => {
const state: Record< string, FieldValidationStatus > = {
existingError: {
message: 'This is an existing error message',
hidden: true,
},
testError: {
message: 'This is error should not be removed',
hidden: true,
},
visibleError: {
message: 'This is error should remain visible',
hidden: false,
},
};
const testAction: ValidationAction = {
type: types.SHOW_VALIDATION_ERROR,
error: 'existingError',
};
const nextState = reducer( state, testAction );
expect( nextState ).toEqual( {
existingError: {
message: 'This is an existing error message',
hidden: false,
},
testError: {
message: 'This is error should not be removed',
hidden: true,
},
visibleError: {
message: 'This is error should remain visible',
hidden: false,
},
} );
} );
it( 'Shows all validation errors', () => {
const state: Record< string, FieldValidationStatus > = {
firstExistingError: {
message: 'This is first existing error message',
hidden: true,
},
secondExistingError: {
message: 'This is the second existing error message',
hidden: true,
},
};
const showAllErrors: ValidationAction = {
type: types.SHOW_ALL_VALIDATION_ERRORS,
};
const nextState = reducer( state, showAllErrors );
expect( nextState ).toEqual( {
firstExistingError: {
message: 'This is first existing error message',
hidden: false,
},
secondExistingError: {
message: 'This is the second existing error message',
hidden: false,
},
} );
} );
} );

View File

@@ -0,0 +1,58 @@
/**
* External dependencies
*/
import { FieldValidationStatus } from '@woocommerce/types';
/**
* Internal dependencies
*/
import {
getValidationErrorId,
getValidationError,
hasValidationErrors,
} from '../selectors';
describe( 'Validation selectors', () => {
it( 'Gets the validation error', () => {
const state: Record< string, FieldValidationStatus > = {
validationError: {
message: 'This is a test message',
hidden: false,
},
};
const validationError = getValidationError( state, 'validationError' );
expect( validationError ).toEqual( {
message: 'This is a test message',
hidden: false,
} );
} );
it( 'Gets the generated validation error ID', () => {
const state: Record< string, FieldValidationStatus > = {
validationError: {
message: 'This is a test message',
hidden: false,
},
};
const validationErrorID = getValidationErrorId(
state,
'validationError'
);
expect( validationErrorID ).toEqual( `validate-error-validationError` );
} );
it( 'Checks if state has any validation errors', () => {
const state: Record< string, FieldValidationStatus > = {
validationError: {
message: 'This is a test message',
hidden: false,
},
};
const validationErrors = hasValidationErrors( state );
expect( validationErrors ).toEqual( true );
const stateWithNoErrors: Record< string, FieldValidationStatus > = {};
const stateWithNoErrorsCheckResult =
hasValidationErrors( stateWithNoErrors );
expect( stateWithNoErrorsCheckResult ).toEqual( false );
} );
} );