Refactor modal to pass insert callback and isOpened value

[MAILPOET-6354]
This commit is contained in:
Jan Lysý
2024-12-12 13:37:55 +01:00
committed by Aschepikov
parent 64264460e8
commit b264c74ce9
7 changed files with 53 additions and 69 deletions

View File

@ -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>

View File

@ -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 }

View File

@ -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' ) }

View File

@ -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>
);

View File

@ -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,

View File

@ -39,9 +39,7 @@ export function getInitialState(): State {
sendingPreviewStatus: null,
},
personalizationTags: {
isModalOpened: false,
list: [],
onInsert: null,
isFetching: false,
},
};

View File

@ -201,9 +201,7 @@ export type State = {
sendingPreviewStatus: SendingPreviewStatus | null;
};
personalizationTags: {
isModalOpened: boolean;
list: PersonalizationTag[];
onInsert: ( ( value: string ) => void ) | null;
isFetching: boolean;
};
};