Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Update the sidebar notice we show for incompatible extensions #10877

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions assets/js/blocks/cart-checkout-shared/sidebar-notices/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { CartCheckoutSidebarCompatibilityNotice } from '@woocommerce/editor-comp
import { NoPaymentMethodsNotice } from '@woocommerce/editor-components/no-payment-methods-notice';
import { PAYMENT_STORE_KEY } from '@woocommerce/block-data';
import { DefaultNotice } from '@woocommerce/editor-components/default-notice';
import { IncompatiblePaymentGatewaysNotice } from '@woocommerce/editor-components/incompatible-payment-gateways-notice';
import { IncompatibleExtensionsNotice } from '@woocommerce/editor-components/incompatible-extension-notice';
import { useSelect } from '@wordpress/data';
import { CartCheckoutFeedbackPrompt } from '@woocommerce/editor-components/feedback-prompt';
import { useState } from '@wordpress/element';
Expand All @@ -38,14 +38,14 @@ const withSidebarNotices = createHigherOrderComponent(
} = props;

const [
isIncompatiblePaymentGatewaysNoticeDismissed,
setIsIncompatiblePaymentGatewaysNoticeDismissed,
isIncompatibleExtensionsNoticeDismissed,
setIsIncompatibleExtensionsNoticeDismissed,
] = useState( true );

const toggleIncompatiblePaymentGatewaysNoticeDismissedStatus = (
const toggleIncompatibleExtensionsNoticeDismissedStatus = (
isDismissed: boolean
) => {
setIsIncompatiblePaymentGatewaysNoticeDismissed( isDismissed );
setIsIncompatibleExtensionsNoticeDismissed( isDismissed );
};

const { isCart, isCheckout, isPaymentMethodsBlock, hasPaymentMethods } =
Expand Down Expand Up @@ -91,9 +91,9 @@ const withSidebarNotices = createHigherOrderComponent(
return (
<>
<InspectorControls>
<IncompatiblePaymentGatewaysNotice
<IncompatibleExtensionsNotice
toggleDismissedStatus={
toggleIncompatiblePaymentGatewaysNoticeDismissedStatus
toggleIncompatibleExtensionsNoticeDismissedStatus
}
block={
isCheckout
Expand All @@ -104,7 +104,7 @@ const withSidebarNotices = createHigherOrderComponent(

<DefaultNotice block={ isCheckout ? 'checkout' : 'cart' } />

{ isIncompatiblePaymentGatewaysNoticeDismissed ? (
{ isIncompatibleExtensionsNoticeDismissed ? (
<CartCheckoutSidebarCompatibilityNotice
block={ isCheckout ? 'checkout' : 'cart' }
/>
Expand Down
6 changes: 3 additions & 3 deletions assets/js/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import '@wordpress/notices';
/**
* Internal dependencies
*/
export { SCHEMA_STORE_KEY } from './schema';
export { COLLECTIONS_STORE_KEY } from './collections';
export { CART_STORE_KEY } from './cart';
export { CHECKOUT_STORE_KEY } from './checkout';
export { COLLECTIONS_STORE_KEY } from './collections';
export { PAYMENT_STORE_KEY } from './payment';
export { VALIDATION_STORE_KEY } from './validation';
export { QUERY_STATE_STORE_KEY } from './query-state';
export { SCHEMA_STORE_KEY } from './schema';
export { STORE_NOTICES_STORE_KEY } from './store-notices';
export { VALIDATION_STORE_KEY } from './validation';
export * from './constants';
export * from './utils';
106 changes: 106 additions & 0 deletions assets/js/editor-components/incompatible-extension-notice/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { Notice, ExternalLink } from '@wordpress/components';
import { createInterpolateElement, useEffect } from '@wordpress/element';
import { Alert } from '@woocommerce/icons';
import { Icon } from '@wordpress/icons';
/**
* Internal dependencies
*/
import { useCombinedIncompatibilityNotice } from './use-combined-incompatibility-notice';
import './editor.scss';

interface ExtensionNoticeProps {
toggleDismissedStatus: ( status: boolean ) => void;
block: 'woocommerce/cart' | 'woocommerce/checkout';
}

export function IncompatibleExtensionsNotice( {
toggleDismissedStatus,
block,
}: ExtensionNoticeProps ) {
const [
isVisible,
dismissNotice,
incompatiblePaymentMethods,
numberOfIncompatiblePaymentMethods,
] = useCombinedIncompatibilityNotice( block );

useEffect( () => {
toggleDismissedStatus( ! isVisible );
}, [ isVisible, toggleDismissedStatus ] );

if ( ! isVisible ) {
return null;
}

// console.log( incompatiblePaymentMethods );

const noticeContent = (
<>
{ numberOfIncompatiblePaymentMethods > 1
? createInterpolateElement(
__(
'The following extensions may be incompatible with the block-based checkout. <a>Learn more</a>',
'woo-gutenberg-products-block'
),
{
a: (
<ExternalLink href="https://woocommerce.com/document/cart-checkout-blocks-support-status/" />
),
}
)
: createInterpolateElement(
sprintf(
// translators: %s is the name of the extension that is incompatible with the block-based checkout.
__(
'<strong>%s</strong> may be incompatible with the block-based checkout. <a>Learn more</a>',
'woo-gutenberg-products-block'
),
Object.values( incompatiblePaymentMethods )[ 0 ]
),
{
strong: <strong />,
a: (
<ExternalLink href="https://woocommerce.com/document/cart-checkout-blocks-support-status/" />
),
}
) }
</>
);

return (
<Notice
className="wc-blocks-incompatible-extensions-notice"
status={ 'warning' }
onRemove={ dismissNotice }
spokenMessage={ noticeContent }
>
<div className="wc-blocks-incompatible-extensions-notice__content">
<Icon
className="wc-blocks-incompatible-extensions-notice__warning-icon"
icon={ <Alert /> }
/>
<div>
<p>{ noticeContent }</p>
{ numberOfIncompatiblePaymentMethods > 1 && (
<ul>
{ Object.entries( incompatiblePaymentMethods ).map(
( [ id, title ] ) => (
<li
key={ id }
className="wc-blocks-incompatible-extensions-notice__element"
>
{ title }
</li>
)
) }
</ul>
) }
</div>
</div>
</Notice>
);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/**
* External dependencies
*/
import { useSelect } from '@wordpress/data';
import { useEffect, useState } from '@wordpress/element';
import { useState, useEffect } from '@wordpress/element';
import { useLocalStorageState } from '@woocommerce/base-hooks';

/**
* Internal dependencies
*/
import { STORE_KEY as PAYMENT_STORE_KEY } from '../../data/payment/constants';
import { useIncompatiblePaymentGatewaysNotice } from './use-incompatible-payment-gateways-notice';
import { useIncompatibleExtensionNotice } from './use-incompatible-extensions-notice';

type StoredIncompatibleGateway = { [ k: string ]: string[] };
type StoredIncompatibleExtension = { [ k: string ]: string[] };
const initialDismissedNotices: React.SetStateAction<
StoredIncompatibleGateway[]
StoredIncompatibleExtension[]
> = [];

const areEqual = ( array1: string[], array2: string[] ) => {
Expand All @@ -25,44 +25,68 @@ const areEqual = ( array1: string[], array2: string[] ) => {
return uniqueCollectionValues.size === array1.length;
};

export const useIncompatiblePaymentGatewaysNotice = (
const sortAlphabetically = ( obj: {
[ key: string ]: string;
} ): { [ key: string ]: string } =>
Object.fromEntries(
Object.entries( obj ).sort( ( [ , a ], [ , b ] ) =>
a.localeCompare( b )
)
);

export const useCombinedIncompatibilityNotice = (
blockName: string
): [ boolean, () => void, { [ k: string ]: string }, number ] => {
const [
incompatibleExtensions,
incompatibleExtensionSlugs,
incompatibleExtensionCount,
] = useIncompatibleExtensionNotice();

const [
incompatiblePaymentMethods,
incompatiblePaymentMethodSlugs,
incompatiblePaymentMethodCount,
] = useIncompatiblePaymentGatewaysNotice();

const allIncompatibleItems = {
...incompatibleExtensions,
...incompatiblePaymentMethods,
};

const allIncompatibleItemSlugs = [
...incompatibleExtensionSlugs,
...incompatiblePaymentMethodSlugs,
];

const allIncompatibleItemCount =
incompatibleExtensionCount + incompatiblePaymentMethodCount;

const [ dismissedNotices, setDismissedNotices ] = useLocalStorageState<
StoredIncompatibleGateway[]
StoredIncompatibleExtension[]
>(
`wc-blocks_dismissed_incompatible_payment_gateways_notices`,
`wc-blocks_dismissed_incompatible_extensions_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 [ isVisible, setIsVisible ] = useState( false );

const isDismissedNoticeUpToDate = dismissedNotices.some(
( notice ) =>
Object.keys( notice ).includes( blockName ) &&
areEqual(
notice[ blockName as keyof object ],
incompatiblePaymentMethodsIDs
allIncompatibleItemSlugs
)
);

const shouldBeDismissed =
numberOfIncompatiblePaymentMethods === 0 || isDismissedNoticeUpToDate;
allIncompatibleItemCount === 0 || isDismissedNoticeUpToDate;

const dismissNotice = () => {
const dismissedNoticesSet = new Set( dismissedNotices );
dismissedNoticesSet.add( {
[ blockName ]: incompatiblePaymentMethodsIDs,
[ blockName ]: allIncompatibleItemSlugs,
} );
setDismissedNotices( [ ...dismissedNoticesSet ] );
};
Expand All @@ -75,7 +99,7 @@ export const useIncompatiblePaymentGatewaysNotice = (
if ( ! shouldBeDismissed && ! isDismissedNoticeUpToDate ) {
setDismissedNotices( ( previousDismissedNotices ) =>
previousDismissedNotices.reduce(
( acc: StoredIncompatibleGateway[], curr ) => {
( acc: StoredIncompatibleExtension[], curr ) => {
if ( Object.keys( curr ).includes( blockName ) ) {
return acc;
}
Expand All @@ -97,7 +121,7 @@ export const useIncompatiblePaymentGatewaysNotice = (
return [
isVisible,
dismissNotice,
incompatiblePaymentMethods,
numberOfIncompatiblePaymentMethods,
sortAlphabetically( allIncompatibleItems ),
allIncompatibleItemCount,
];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* External dependencies
*/
import { getSetting } from '@woocommerce/settings';

export const useIncompatibleExtensionNotice = (): [
{ [ k: string ]: string } | null,
string[],
number
] => {
interface GlobalIncompatibleExtensions {
id: string;
title: string;
}

const incompatibleExtensions: Record< string, string > = {};

if ( getSetting( 'incompatibleExtensions' ) ) {
getSetting< GlobalIncompatibleExtensions[] >(
'incompatibleExtensions'
).forEach( ( extension ) => {
incompatibleExtensions[ extension.id ] = extension.title;
} );
}

const incompatibleExtensionSlugs = Object.keys( incompatibleExtensions );
const incompatibleExtensionCount = incompatibleExtensionSlugs.length;

return [
incompatibleExtensions,
incompatibleExtensionSlugs,
incompatibleExtensionCount,
];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* External dependencies
*/
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { STORE_KEY as PAYMENT_STORE_KEY } from '../../data/payment/constants';

export const useIncompatiblePaymentGatewaysNotice = (): [
{ [ k: string ]: string },
string[],
number
] => {
const { incompatiblePaymentMethods } = useSelect( ( select ) => {
const { getIncompatiblePaymentMethods } = select( PAYMENT_STORE_KEY );
return {
incompatiblePaymentMethods: getIncompatiblePaymentMethods(),
};
}, [] );

const incompatiblePaymentMethodSlugs = Object.keys(
incompatiblePaymentMethods
);

const incompatiblePaymentMethodCount =
incompatiblePaymentMethodSlugs.length;

return [
incompatiblePaymentMethods,
incompatiblePaymentMethodSlugs,
incompatiblePaymentMethodCount,
];
};
Loading