2021-02-17 13:01:20 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { useMemo } from '@wordpress/element';
|
2021-04-23 09:15:17 +00:00
|
|
|
import { __, sprintf } from '@wordpress/i18n';
|
2021-04-22 11:37:27 +00:00
|
|
|
import { CURRENT_USER_IS_ADMIN } from '@woocommerce/settings';
|
2021-07-01 13:12:46 +00:00
|
|
|
import deprecated from '@wordpress/deprecated';
|
2021-02-17 13:01:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
2021-04-08 12:31:12 +00:00
|
|
|
import { returnTrue } from '../utils';
|
2021-02-17 13:01:20 +00:00
|
|
|
|
2021-03-05 14:03:48 +00:00
|
|
|
type CheckoutFilterFunction = < T >(
|
2021-05-05 09:41:48 +00:00
|
|
|
value: T,
|
2021-03-05 14:03:48 +00:00
|
|
|
extensions: Record< string, unknown >,
|
|
|
|
args?: CheckoutFilterArguments
|
|
|
|
) => T;
|
|
|
|
|
|
|
|
type CheckoutFilterArguments =
|
|
|
|
| ( Record< string, unknown > & {
|
|
|
|
context?: string;
|
|
|
|
} )
|
|
|
|
| null;
|
|
|
|
|
|
|
|
let checkoutFilters: Record<
|
|
|
|
string,
|
|
|
|
Record< string, CheckoutFilterFunction >
|
|
|
|
> = {};
|
2021-02-09 16:54:38 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Register filters for a specific extension.
|
|
|
|
*/
|
2021-03-05 14:03:48 +00:00
|
|
|
export const __experimentalRegisterCheckoutFilters = (
|
|
|
|
namespace: string,
|
|
|
|
filters: Record< string, CheckoutFilterFunction >
|
|
|
|
): void => {
|
2021-07-26 08:13:54 +00:00
|
|
|
/**
|
|
|
|
* Let developers know snackbarNotices is no longer available as a filter.
|
|
|
|
*
|
|
|
|
* See: https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/4417
|
|
|
|
*/
|
|
|
|
if ( Object.keys( filters ).includes( 'couponName' ) ) {
|
|
|
|
deprecated( 'snackbarNotices', {
|
|
|
|
alternative: 'snackbarNoticeVisibility',
|
|
|
|
plugin: 'WooCommerce Blocks',
|
|
|
|
link:
|
|
|
|
'https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/4417',
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2021-07-01 13:12:46 +00:00
|
|
|
/**
|
|
|
|
* Let the user know couponName is no longer available as a filter.
|
|
|
|
*
|
|
|
|
* See https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/4312
|
|
|
|
*/
|
|
|
|
if ( Object.keys( filters ).includes( 'couponName' ) ) {
|
|
|
|
deprecated( 'couponName', {
|
|
|
|
alternative: 'coupons',
|
|
|
|
plugin: 'WooCommerce Blocks',
|
|
|
|
link:
|
|
|
|
'https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/bb921d21f42e21f38df2b1c87b48e07aa4cb0538/docs/extensibility/available-filters.md#coupons',
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2021-02-09 16:54:38 +00:00
|
|
|
checkoutFilters = {
|
|
|
|
...checkoutFilters,
|
|
|
|
[ namespace ]: filters,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get all filters with a specific name.
|
|
|
|
*
|
|
|
|
* @param {string} filterName Name of the filter to search for.
|
|
|
|
* @return {Function[]} Array of functions that are registered for that filter
|
|
|
|
* name.
|
|
|
|
*/
|
2021-03-05 14:03:48 +00:00
|
|
|
const getCheckoutFilters = ( filterName: string ): CheckoutFilterFunction[] => {
|
2021-02-09 16:54:38 +00:00
|
|
|
const namespaces = Object.keys( checkoutFilters );
|
|
|
|
const filters = namespaces
|
|
|
|
.map( ( namespace ) => checkoutFilters[ namespace ][ filterName ] )
|
|
|
|
.filter( Boolean );
|
|
|
|
return filters;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Apply a filter.
|
|
|
|
*/
|
2021-04-23 09:15:17 +00:00
|
|
|
export const __experimentalApplyCheckoutFilter = < T >( {
|
2021-02-09 16:54:38 +00:00
|
|
|
filterName,
|
|
|
|
defaultValue,
|
2021-08-13 13:42:09 +00:00
|
|
|
extensions = null,
|
2021-02-09 16:54:38 +00:00
|
|
|
arg = null,
|
2021-02-17 13:01:20 +00:00
|
|
|
validation = returnTrue,
|
2021-03-05 14:03:48 +00:00
|
|
|
}: {
|
|
|
|
/** Name of the filter to apply. */
|
|
|
|
filterName: string;
|
|
|
|
/** Default value to filter. */
|
2021-04-23 09:15:17 +00:00
|
|
|
defaultValue: T;
|
2021-03-05 14:03:48 +00:00
|
|
|
/** Values extend to REST API response. */
|
2021-08-13 13:42:09 +00:00
|
|
|
extensions?: Record< string, unknown > | null;
|
2021-03-05 14:03:48 +00:00
|
|
|
/** Object containing arguments for the filter function. */
|
2021-06-07 08:41:33 +00:00
|
|
|
arg?: CheckoutFilterArguments;
|
2021-03-05 14:03:48 +00:00
|
|
|
/** Function that needs to return true when the filtered value is passed in order for the filter to be applied. */
|
2021-06-01 08:46:02 +00:00
|
|
|
validation?: ( value: T ) => true | Error;
|
2021-04-23 09:15:17 +00:00
|
|
|
} ): T => {
|
2021-02-17 13:01:20 +00:00
|
|
|
return useMemo( () => {
|
|
|
|
const filters = getCheckoutFilters( filterName );
|
|
|
|
|
|
|
|
let value = defaultValue;
|
|
|
|
filters.forEach( ( filter ) => {
|
|
|
|
try {
|
2021-08-13 13:42:09 +00:00
|
|
|
const newValue = filter( value, extensions || {}, arg );
|
2021-04-23 09:15:17 +00:00
|
|
|
if ( typeof newValue !== typeof value ) {
|
|
|
|
throw new Error(
|
|
|
|
sprintf(
|
|
|
|
/* translators: %1$s is the type of the variable passed to the filter function, %2$s is the type of the value returned by the filter function. */
|
|
|
|
__(
|
|
|
|
'The type returned by checkout filters must be the same as the type they receive. The function received %1$s but returned %2$s.',
|
|
|
|
'woo-gutenberg-products-block'
|
|
|
|
),
|
|
|
|
typeof value,
|
|
|
|
typeof newValue
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2021-02-17 13:01:20 +00:00
|
|
|
value = validation( newValue ) ? newValue : value;
|
|
|
|
} catch ( e ) {
|
|
|
|
if ( CURRENT_USER_IS_ADMIN ) {
|
|
|
|
throw e;
|
|
|
|
} else {
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.error( e );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
return value;
|
|
|
|
}, [ filterName, defaultValue, extensions, arg, validation ] );
|
2021-02-09 16:54:38 +00:00
|
|
|
};
|