woocommerce/plugins/woocommerce-blocks/assets/js/editor-components/incompatible-payment-gatewa.../use-incompatible-payment-ga...

104 lines
2.8 KiB
TypeScript

/**
* External dependencies
*/
import { useSelect } from '@wordpress/data';
import { useEffect, useState } from '@wordpress/element';
import { useLocalStorageState } from '@woocommerce/base-hooks';
/**
* Internal dependencies
*/
import { STORE_KEY as PAYMENT_STORE_KEY } from '../../data/payment/constants';
type StoredIncompatibleGateway = { [ k: string ]: string[] };
const initialDismissedNotices: React.SetStateAction<
StoredIncompatibleGateway[]
> = [];
const areEqual = ( array1: string[], array2: string[] ) => {
if ( array1.length !== array2.length ) {
return false;
}
const uniqueCollectionValues = new Set( [ ...array1, ...array2 ] );
return uniqueCollectionValues.size === array1.length;
};
export const useIncompatiblePaymentGatewaysNotice = (
blockName: string
): [ boolean, () => void, { [ k: string ]: string }, number ] => {
const [ dismissedNotices, setDismissedNotices ] = useLocalStorageState<
StoredIncompatibleGateway[]
>(
`wc-blocks_dismissed_incompatible_payment_gateways_notices`,
initialDismissedNotices
);
const [ isVisible, setIsVisible ] = useState( false );
const { incompatiblePaymentMethods } = useSelect( ( select ) => {
const { getIncompatiblePaymentMethods } = select( PAYMENT_STORE_KEY );
return {
incompatiblePaymentMethods: getIncompatiblePaymentMethods(),
};
}, [] );
const incompatiblePaymentMethodsIDs = Object.keys(
incompatiblePaymentMethods
);
const numberOfIncompatiblePaymentMethods =
incompatiblePaymentMethodsIDs.length;
const isDismissedNoticeUpToDate = dismissedNotices.some(
( notice ) =>
Object.keys( notice ).includes( blockName ) &&
areEqual(
notice[ blockName as keyof object ],
incompatiblePaymentMethodsIDs
)
);
const shouldBeDismissed =
numberOfIncompatiblePaymentMethods === 0 || isDismissedNoticeUpToDate;
const dismissNotice = () => {
const dismissedNoticesSet = new Set( dismissedNotices );
dismissedNoticesSet.add( {
[ blockName ]: incompatiblePaymentMethodsIDs,
} );
setDismissedNotices( [ ...dismissedNoticesSet ] );
};
// This ensures the modal is not loaded on first render. This is required so
// Gutenberg doesn't steal the focus from the Guide and focuses the block.
useEffect( () => {
setIsVisible( ! shouldBeDismissed );
if ( ! shouldBeDismissed && ! isDismissedNoticeUpToDate ) {
setDismissedNotices( ( previousDismissedNotices ) =>
previousDismissedNotices.reduce(
( acc: StoredIncompatibleGateway[], curr ) => {
if ( Object.keys( curr ).includes( blockName ) ) {
return acc;
}
acc.push( curr );
return acc;
},
[]
)
);
}
}, [
shouldBeDismissed,
isDismissedNoticeUpToDate,
setDismissedNotices,
blockName,
] );
return [
isVisible,
dismissNotice,
incompatiblePaymentMethods,
numberOfIncompatiblePaymentMethods,
];
};