diff --git a/packages/js/email-editor/src/blocks/core/rich-text.tsx b/packages/js/email-editor/src/blocks/core/rich-text.tsx index 9a26789f74..15aa2469b2 100644 --- a/packages/js/email-editor/src/blocks/core/rich-text.tsx +++ b/packages/js/email-editor/src/blocks/core/rich-text.tsx @@ -2,13 +2,14 @@ import { registerFormatType, unregisterFormatType } from '@wordpress/rich-text'; import { __ } from '@wordpress/i18n'; import { BlockControls } from '@wordpress/block-editor'; import { ToolbarButton, ToolbarGroup } from '@wordpress/components'; -import { storeName } from '../../store'; import { useSelect, useDispatch } from '@wordpress/data'; import { createTextToHtmlMap, getCursorPosition, isMatchingComment, } from '../../components/personalization-tags/rich-text-utils'; +import { PersonalizationTagsModal } from '../../components/personalization-tags/personalization-tags-modal'; +import { useState } from '@wordpress/element'; /** * Disable Rich text formats we currently cannot support @@ -36,8 +37,7 @@ type Props = { * @param root0.contentRef */ function PersonalizationTagsButton( { contentRef }: Props ) { - const { togglePersonalizationTagsModal } = useDispatch( storeName ); - + const [ isModalOpened, setIsModalOpened ] = useState( false ); const selectedBlockId = useSelect( ( select ) => select( 'core/block-editor' ).getSelectedBlockClientId() ); @@ -87,11 +87,15 @@ function PersonalizationTagsButton( { contentRef }: Props ) { { - togglePersonalizationTagsModal( true, { - onInsert: handleInsert, - } ); + onClick={ () => setIsModalOpened( true ) } + /> + { + handleInsert( value ); + setIsModalOpened( false ); } } + closeCallback={ () => setIsModalOpened( false ) } /> diff --git a/packages/js/email-editor/src/components/block-editor/layout.tsx b/packages/js/email-editor/src/components/block-editor/layout.tsx index b942e5d5f5..f8354151a8 100644 --- a/packages/js/email-editor/src/components/block-editor/layout.tsx +++ b/packages/js/email-editor/src/components/block-editor/layout.tsx @@ -24,7 +24,6 @@ import { StylesSidebar } from '../styles-sidebar'; import { VisualEditor } from './visual-editor/visual-editor'; import { TemplateSelection } from '../template-select'; -import { PersonalizationTagsModal } from '../personalization-tags/personalization-tags-modal'; export function Layout() { const { @@ -93,7 +92,6 @@ export function Layout() { - ; activeCategory: string | null; + onInsert: ( tag: string ) => void; } ) => { - const { togglePersonalizationTagsModal } = useDispatch( storeName ); - - const { onInsert } = useSelect( - ( select ) => select( storeName ).getPersonalizationTagsState(), - [] - ); - const categoriesToRender: [ string, PersonalizationTag[] ][] = activeCategory === null ? Object.entries( groupedTags ) // Render all categories @@ -46,9 +40,6 @@ const CategorySection = ( { if ( onInsert ) { onInsert( item.token ); } - togglePersonalizationTagsModal( - false - ); } } > { __( 'Insert' ) } diff --git a/packages/js/email-editor/src/components/personalization-tags/personalization-tags-modal.tsx b/packages/js/email-editor/src/components/personalization-tags/personalization-tags-modal.tsx index 6880ab5903..fdb226ce8b 100644 --- a/packages/js/email-editor/src/components/personalization-tags/personalization-tags-modal.tsx +++ b/packages/js/email-editor/src/components/personalization-tags/personalization-tags-modal.tsx @@ -1,31 +1,23 @@ import { Modal, SearchControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { PersonalizationTag, storeName } from '../../store'; -import { useDispatch, useSelect } from '@wordpress/data'; +import { select } from '@wordpress/data'; import { external, Icon } from '@wordpress/icons'; import './index.scss'; import { useState } from '@wordpress/element'; import { CategoryMenu } from './category-menu'; import { CategorySection } from './category-section'; -const PersonalizationTagsModal = () => { +const PersonalizationTagsModal = ( { onInsert, isOpened, closeCallback } ) => { const [ activeCategory, setActiveCategory ] = useState( null ); const [ searchQuery, setSearchQuery ] = useState( '' ); - const { togglePersonalizationTagsModal } = useDispatch( storeName ); - - const { isModalOpened, list } = useSelect( ( select ) => { - const store = select( storeName ); - return { - isModalOpened: store.getPersonalizationTagsState().isModalOpened, - list: store.getPersonalizationTagsList(), - }; - }, [] ); - - if ( ! isModalOpened ) { + if ( ! isOpened ) { return null; } + const list = select( storeName ).getPersonalizationTagsList(); + const groupedTags: Record< string, PersonalizationTag[] > = list.reduce( ( groups, item ) => { const { category, name, token } = item; @@ -49,7 +41,7 @@ const PersonalizationTagsModal = () => { togglePersonalizationTagsModal( false ) } + onRequestClose={ closeCallback } className="mailpoet-personalization-tags-modal" >

@@ -68,6 +60,7 @@ const PersonalizationTagsModal = () => { ); diff --git a/packages/js/email-editor/src/components/sidebar/details-panel.tsx b/packages/js/email-editor/src/components/sidebar/details-panel.tsx index 7f498f60ca..deceac2faa 100644 --- a/packages/js/email-editor/src/components/sidebar/details-panel.tsx +++ b/packages/js/email-editor/src/components/sidebar/details-panel.tsx @@ -16,6 +16,7 @@ import { getCursorPosition, isMatchingComment, } from '../personalization-tags/rich-text-utils'; +import { PersonalizationTagsModal } from '../personalization-tags/personalization-tags-modal'; const previewTextMaxLength = 150; const previewTextRecommendedLength = 80; @@ -38,36 +39,33 @@ export function DetailsPanel() { 'mailpoet_data' ); - const { togglePersonalizationTagsModal, updateEmailMailPoetProperty } = - useDispatch( storeName ); - const [ activeRichText, setActiveRichText ] = useState( null ); + const { updateEmailMailPoetProperty } = useDispatch( storeName ); + const [ selectionRange, setSelectionRange ] = useState( null ); + const [ subjectModalIsOpened, setSubjectModalIsOpened ] = useState( false ); + const [ preheaderModalIsOpened, setPreheaderModalIsOpened ] = + useState( false ); const subjectRef = useRef( null ); const preheaderRef = useRef( null ); - const handleInsertPersonalizationTag = async ( value ) => { - if ( ! activeRichText || ! selectionRange ) { - return; - } - - const ref = activeRichText === 'subject' ? subjectRef : preheaderRef; - if ( ! ref ) { - return; - } - + const handleInsertPersonalizationTag = async ( value, activeRichText ) => { // Retrieve the current value of the active RichText const currentValue = activeRichText === 'subject' ? mailpoetEmailData?.subject ?? '' : mailpoetEmailData?.preheader ?? ''; + const ref = activeRichText === 'subject' ? subjectRef : preheaderRef; + if ( ! ref ) { + return; + } + // Generate text-to-HTML mapping const { mapping } = createTextToHtmlMap( currentValue ); - // Ensure selection range is within bounds - const start = selectionRange.start; - const end = selectionRange.end; + const start = selectionRange?.start ?? currentValue.length; + const end = selectionRange?.end ?? currentValue.length; // Default values for starting and ending indexes. let htmlStart = start; @@ -124,10 +122,7 @@ export function DetailsPanel() { { __( 'Subject', 'mailpoet' ) } { - setActiveRichText( 'subject' ); - togglePersonalizationTagsModal( true, { - onInsert: handleInsertPersonalizationTag, - } ); + setSubjectModalIsOpened( true ); } } /> @@ -163,10 +158,7 @@ export function DetailsPanel() { { __( 'Preview text', 'mailpoet' ) } { - setActiveRichText( 'preheader' ); - togglePersonalizationTagsModal( true, { - onInsert: handleInsertPersonalizationTag, - } ); + setPreheaderModalIsOpened( true ); } } /> + { + handleInsertPersonalizationTag( value, 'subject' ); + setSubjectModalIsOpened( false ); + } } + closeCallback={ () => setSubjectModalIsOpened( false ) } + /> { - setActiveRichText( 'subject' ); setSelectionRange( getCursorPosition( subjectRef, @@ -213,7 +212,6 @@ export function DetailsPanel() { ); } } onKeyUp={ () => { - setActiveRichText( 'subject' ); setSelectionRange( getCursorPosition( subjectRef, @@ -222,7 +220,6 @@ export function DetailsPanel() { ); } } onClick={ () => { - setActiveRichText( 'subject' ); setSelectionRange( getCursorPosition( subjectRef, @@ -244,6 +241,14 @@ export function DetailsPanel() { className="mailpoet-settings-panel__preview-text" help={ preheaderHelp } > + { + handleInsertPersonalizationTag( value, 'preheader' ); + setPreheaderModalIsOpened( false ); + } } + closeCallback={ () => setPreheaderModalIsOpened( false ) } + /> { - setActiveRichText( 'preheader' ); setSelectionRange( getCursorPosition( preheaderRef, @@ -261,7 +265,6 @@ export function DetailsPanel() { ); } } onKeyUp={ () => { - setActiveRichText( 'preheader' ); setSelectionRange( getCursorPosition( preheaderRef, @@ -270,7 +273,6 @@ export function DetailsPanel() { ); } } onClick={ () => { - setActiveRichText( 'preheader' ); setSelectionRange( getCursorPosition( preheaderRef, diff --git a/packages/js/email-editor/src/store/initial-state.ts b/packages/js/email-editor/src/store/initial-state.ts index 7797ea62de..b11523f797 100644 --- a/packages/js/email-editor/src/store/initial-state.ts +++ b/packages/js/email-editor/src/store/initial-state.ts @@ -39,9 +39,7 @@ export function getInitialState(): State { sendingPreviewStatus: null, }, personalizationTags: { - isModalOpened: false, list: [], - onInsert: null, isFetching: false, }, }; diff --git a/packages/js/email-editor/src/store/types.ts b/packages/js/email-editor/src/store/types.ts index c458837556..b5763f1a81 100644 --- a/packages/js/email-editor/src/store/types.ts +++ b/packages/js/email-editor/src/store/types.ts @@ -201,9 +201,7 @@ export type State = { sendingPreviewStatus: SendingPreviewStatus | null; }; personalizationTags: { - isModalOpened: boolean; list: PersonalizationTag[]; - onInsert: ( ( value: string ) => void ) | null; isFetching: boolean; }; };