Refactor modal to pass insert callback and isOpened value
[MAILPOET-6354]
This commit is contained in:
@ -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 ) {
|
||||
<ToolbarButton
|
||||
icon="shortcode"
|
||||
title={ __( 'Personalization Tags', 'mailpoet' ) }
|
||||
onClick={ () => {
|
||||
togglePersonalizationTagsModal( true, {
|
||||
onInsert: handleInsert,
|
||||
} );
|
||||
onClick={ () => setIsModalOpened( true ) }
|
||||
/>
|
||||
<PersonalizationTagsModal
|
||||
isOpened={ isModalOpened }
|
||||
onInsert={ ( value ) => {
|
||||
handleInsert( value );
|
||||
setIsModalOpened( false );
|
||||
} }
|
||||
closeCallback={ () => setIsModalOpened( false ) }
|
||||
/>
|
||||
</ToolbarGroup>
|
||||
</BlockControls>
|
||||
|
@ -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() {
|
||||
<SentEmailNotice />
|
||||
<Sidebar />
|
||||
<StylesSidebar />
|
||||
<PersonalizationTagsModal />
|
||||
<TemplateSelection />
|
||||
<InterfaceSkeleton
|
||||
className={ className }
|
||||
|
@ -1,22 +1,16 @@
|
||||
import { Button } from '@wordpress/components';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { PersonalizationTag, storeName } from '../../store';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import { PersonalizationTag } from '../../store';
|
||||
|
||||
const CategorySection = ( {
|
||||
groupedTags,
|
||||
activeCategory,
|
||||
onInsert,
|
||||
}: {
|
||||
groupedTags: Record< string, PersonalizationTag[] >;
|
||||
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' ) }
|
||||
|
@ -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 = () => {
|
||||
<Modal
|
||||
size="medium"
|
||||
title={ __( 'Personalization Tags', 'mailpoet' ) }
|
||||
onRequestClose={ () => togglePersonalizationTagsModal( false ) }
|
||||
onRequestClose={ closeCallback }
|
||||
className="mailpoet-personalization-tags-modal"
|
||||
>
|
||||
<p>
|
||||
@ -68,6 +60,7 @@ const PersonalizationTagsModal = () => {
|
||||
<CategorySection
|
||||
groupedTags={ groupedTags }
|
||||
activeCategory={ activeCategory }
|
||||
onInsert={ onInsert }
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
|
@ -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() {
|
||||
<span>{ __( 'Subject', 'mailpoet' ) }</span>
|
||||
<PersonalizationTagsButton
|
||||
onClick={ () => {
|
||||
setActiveRichText( 'subject' );
|
||||
togglePersonalizationTagsModal( true, {
|
||||
onInsert: handleInsertPersonalizationTag,
|
||||
} );
|
||||
setSubjectModalIsOpened( true );
|
||||
} }
|
||||
/>
|
||||
<ExternalLink href="https://kb.mailpoet.com/article/215-personalize-newsletter-with-shortcodes#list">
|
||||
@ -163,10 +158,7 @@ export function DetailsPanel() {
|
||||
<span>{ __( 'Preview text', 'mailpoet' ) }</span>
|
||||
<PersonalizationTagsButton
|
||||
onClick={ () => {
|
||||
setActiveRichText( 'preheader' );
|
||||
togglePersonalizationTagsModal( true, {
|
||||
onInsert: handleInsertPersonalizationTag,
|
||||
} );
|
||||
setPreheaderModalIsOpened( true );
|
||||
} }
|
||||
/>
|
||||
<span
|
||||
@ -196,6 +188,14 @@ export function DetailsPanel() {
|
||||
className="mailpoet-settings-panel__subject"
|
||||
help={ subjectHelp }
|
||||
>
|
||||
<PersonalizationTagsModal
|
||||
isOpened={ subjectModalIsOpened }
|
||||
onInsert={ ( value ) => {
|
||||
handleInsertPersonalizationTag( value, 'subject' );
|
||||
setSubjectModalIsOpened( false );
|
||||
} }
|
||||
closeCallback={ () => setSubjectModalIsOpened( false ) }
|
||||
/>
|
||||
<RichText
|
||||
ref={ subjectRef }
|
||||
className="mailpoet-settings-panel__richtext"
|
||||
@ -204,7 +204,6 @@ export function DetailsPanel() {
|
||||
'mailpoet'
|
||||
) }
|
||||
onFocus={ () => {
|
||||
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 }
|
||||
>
|
||||
<PersonalizationTagsModal
|
||||
isOpened={ preheaderModalIsOpened }
|
||||
onInsert={ ( value ) => {
|
||||
handleInsertPersonalizationTag( value, 'preheader' );
|
||||
setPreheaderModalIsOpened( false );
|
||||
} }
|
||||
closeCallback={ () => setPreheaderModalIsOpened( false ) }
|
||||
/>
|
||||
<RichText
|
||||
ref={ preheaderRef }
|
||||
className="mailpoet-settings-panel__richtext"
|
||||
@ -252,7 +257,6 @@ export function DetailsPanel() {
|
||||
'mailpoet'
|
||||
) }
|
||||
onFocus={ () => {
|
||||
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,
|
||||
|
@ -39,9 +39,7 @@ export function getInitialState(): State {
|
||||
sendingPreviewStatus: null,
|
||||
},
|
||||
personalizationTags: {
|
||||
isModalOpened: false,
|
||||
list: [],
|
||||
onInsert: null,
|
||||
isFetching: false,
|
||||
},
|
||||
};
|
||||
|
@ -201,9 +201,7 @@ export type State = {
|
||||
sendingPreviewStatus: SendingPreviewStatus | null;
|
||||
};
|
||||
personalizationTags: {
|
||||
isModalOpened: boolean;
|
||||
list: PersonalizationTag[];
|
||||
onInsert: ( ( value: string ) => void ) | null;
|
||||
isFetching: boolean;
|
||||
};
|
||||
};
|
||||
|
Reference in New Issue
Block a user