diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx
index 90ed32ee337e8..1c2e1563d1eee 100644
--- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx
+++ b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/index.tsx
@@ -6,7 +6,6 @@ import {
__experimentalNavigatorProvider as NavigatorProvider,
__experimentalNavigatorScreen as NavigatorScreen,
__experimentalUseNavigator as useNavigator,
- withNotices,
} from '@wordpress/components';
import { compose } from '@wordpress/compose';
import { useDispatch, useSelect } from '@wordpress/data';
@@ -33,7 +32,7 @@ import usePatternCategories from './hooks/use-pattern-categories';
import usePatternsMapByCategory from './hooks/use-patterns-map-by-category';
import { usePrefetchImages } from './hooks/use-prefetch-images';
import useRecipe from './hooks/use-recipe';
-import Notices, { getNoticeContent } from './notices/notices';
+import withNotices, { NoticesProps } from './notices/notices';
import PatternAssemblerContainer from './pattern-assembler-container';
import PatternLargePreview from './pattern-large-preview';
import ScreenActivation from './screen-activation';
@@ -61,9 +60,9 @@ const PatternAssembler = ( {
navigation,
flow,
stepName,
- noticeList,
noticeOperations,
-}: StepProps & withNotices.Props ) => {
+ noticeUI,
+}: StepProps & NoticesProps ) => {
const translate = useTranslate();
const navigator = useNavigator();
const [ sectionPosition, setSectionPosition ] = useState< number | null >( null );
@@ -212,10 +211,6 @@ const PatternAssembler = ( {
} );
};
- const showNotice = ( action: string, pattern: Pattern ) => {
- noticeOperations.createNotice( { content: getNoticeContent( action, pattern ) } );
- };
-
const getDesign = () =>
( {
...selectedDesign,
@@ -237,12 +232,12 @@ const PatternAssembler = ( {
updateActivePatternPosition( -1 );
if ( pattern ) {
if ( header ) {
- showNotice( 'replace', pattern );
+ noticeOperations.showPatternReplacedNotice( pattern );
} else {
- showNotice( 'add', pattern );
+ noticeOperations.showPatternInsertedNotice( pattern );
}
} else if ( header ) {
- showNotice( 'remove', header );
+ noticeOperations.showPatternRemovedNotice( header );
}
};
@@ -256,12 +251,12 @@ const PatternAssembler = ( {
activateFooterPosition( !! pattern );
if ( pattern ) {
if ( footer ) {
- showNotice( 'replace', pattern );
+ noticeOperations.showPatternReplacedNotice( pattern );
} else {
- showNotice( 'add', pattern );
+ noticeOperations.showPatternInsertedNotice( pattern );
}
} else if ( footer ) {
- showNotice( 'remove', footer );
+ noticeOperations.showPatternRemovedNotice( footer );
}
};
@@ -276,7 +271,7 @@ const PatternAssembler = ( {
...sections.slice( sectionPosition + 1 ),
] );
updateActivePatternPosition( sectionPosition );
- showNotice( 'replace', pattern );
+ noticeOperations.showPatternReplacedNotice( pattern );
}
};
@@ -289,11 +284,11 @@ const PatternAssembler = ( {
},
] );
updateActivePatternPosition( sections.length );
- showNotice( 'add', pattern );
+ noticeOperations.showPatternInsertedNotice( pattern );
};
const deleteSection = ( position: number ) => {
- showNotice( 'remove', sections[ position ] );
+ noticeOperations.showPatternRemovedNotice( sections[ position ] );
setSections( [ ...sections.slice( 0, position ), ...sections.slice( position + 1 ) ] );
updateActivePatternPosition( position );
};
@@ -564,7 +559,7 @@ const PatternAssembler = ( {
ref={ wrapperRef }
tabIndex={ -1 }
>
-
+ { noticeUI }
(
+const PatternAssemblerStep = ( props: StepProps & NoticesProps ) => (
diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.tsx
index f6d3445e08fac..a319799394250 100644
--- a/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.tsx
+++ b/client/landing/stepper/declarative-flow/internals/steps-repository/pattern-assembler/notices/notices.tsx
@@ -1,6 +1,7 @@
-import { SnackbarList, withNotices, NoticeList } from '@wordpress/components';
+import { NoticeList, SnackbarList } from '@wordpress/components';
+import { createHigherOrderComponent } from '@wordpress/compose';
import i18n from 'i18n-calypso';
-import { useEffect } from 'react';
+import { ComponentType, ReactNode, ReactChild, useState } from 'react';
import type { Pattern } from '../types';
import './notices.scss';
@@ -10,47 +11,86 @@ type Notice = NoticeList.Notice & {
timer?: ReturnType< typeof setTimeout >;
};
-const Notices = ( {
- noticeList,
- noticeOperations,
-}: Pick< withNotices.Props, 'noticeList' | 'noticeOperations' > ) => {
- const onRemoveNotice = ( id: string ) => {
- const notice = noticeList.find( ( notice ) => id === notice.id ) as Notice;
- if ( notice?.timer ) {
- clearTimeout( notice.timer );
- delete notice.timer;
- }
- noticeOperations.removeNotice( id );
- };
-
- useEffect( () => {
- const lastNotice = noticeList[ noticeList.length - 1 ] as Notice;
-
- if ( lastNotice?.id && ! lastNotice?.timer ) {
- lastNotice.timer = setTimeout(
- () => noticeOperations.removeNotice( lastNotice.id ),
- NOTICE_TIMEOUT
- );
- }
- }, [ noticeList, noticeOperations ] );
-
- return ;
-};
+interface NoticeOperationsProps {
+ showPatternInsertedNotice: ( pattern: Pattern ) => void;
+ showPatternReplacedNotice: ( pattern: Pattern ) => void;
+ showPatternRemovedNotice: ( pattern: Pattern ) => void;
+}
-export const getNoticeContent = ( action: string, pattern: Pattern ) => {
- const actions: { [ key: string ]: any } = {
- add: i18n.translate( 'Block pattern "%(patternName)s" inserted.', {
- args: { patternName: pattern.title },
- } ),
- replace: i18n.translate( 'Block pattern "%(patternName)s" replaced.', {
- args: { patternName: pattern.title },
- } ),
- remove: i18n.translate( 'Block pattern "%(patternName)s" removed.', {
- args: { patternName: pattern.title },
- } ),
- };
-
- return actions[ action ];
-};
+export interface NoticesProps {
+ noticeOperations: NoticeOperationsProps;
+ noticeUI: ReactNode;
+}
+
+const withNotices = createHigherOrderComponent(
+ < OuterProps, >( InnerComponent: ComponentType< OuterProps > ) => {
+ return ( props: OuterProps & NoticesProps ) => {
+ const [ noticeList, setNoticeList ] = useState< Notice[] >( [] );
+
+ const removeNotice = ( id: string ) => {
+ setNoticeList( ( current ) => current.filter( ( notice ) => notice.id !== id ) );
+ };
+
+ const createNotice = ( id: string, content: ReactChild ) => {
+ const existingNoticeWithSameId = noticeList.find( ( notice ) => notice.id === id );
+ if ( existingNoticeWithSameId?.timer ) {
+ clearTimeout( existingNoticeWithSameId.timer );
+ delete existingNoticeWithSameId.timer;
+ }
+
+ const newNotice = {
+ id,
+ content,
+ timer: setTimeout( () => {
+ removeNotice( id );
+ }, NOTICE_TIMEOUT ),
+ };
+
+ setNoticeList( ( current ) => [
+ ...current.filter( ( notice ) => notice.id !== id ),
+ newNotice,
+ ] );
+ };
+
+ const noticeOperations: NoticeOperationsProps = {
+ showPatternInsertedNotice: ( pattern: Pattern ) => {
+ createNotice(
+ 'pattern-inserted',
+ i18n.translate( 'Block pattern "%(patternName)s" inserted.', {
+ args: { patternName: pattern.title },
+ } )
+ );
+ },
+ showPatternReplacedNotice: ( pattern: Pattern ) => {
+ createNotice(
+ 'pattern-replaced',
+ i18n.translate( 'Block pattern "%(patternName)s" replaced.', {
+ args: { patternName: pattern.title },
+ } )
+ );
+ },
+ showPatternRemovedNotice: ( pattern: Pattern ) => {
+ createNotice(
+ 'pattern-removed',
+ i18n.translate( 'Block pattern "%(patternName)s" removed.', {
+ args: { patternName: pattern.title },
+ } )
+ );
+ },
+ };
+
+ const noticeUI = ;
+
+ const propsWithNotices = {
+ ...props,
+ noticeOperations,
+ noticeUI,
+ };
+
+ return ;
+ };
+ },
+ 'withNotices'
+);
-export default Notices;
+export default withNotices;