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 { __ } from '@wordpress/i18n';
|
||||||
import { BlockControls } from '@wordpress/block-editor';
|
import { BlockControls } from '@wordpress/block-editor';
|
||||||
import { ToolbarButton, ToolbarGroup } from '@wordpress/components';
|
import { ToolbarButton, ToolbarGroup } from '@wordpress/components';
|
||||||
import { storeName } from '../../store';
|
|
||||||
import { useSelect, useDispatch } from '@wordpress/data';
|
import { useSelect, useDispatch } from '@wordpress/data';
|
||||||
import {
|
import {
|
||||||
createTextToHtmlMap,
|
createTextToHtmlMap,
|
||||||
getCursorPosition,
|
getCursorPosition,
|
||||||
isMatchingComment,
|
isMatchingComment,
|
||||||
} from '../../components/personalization-tags/rich-text-utils';
|
} 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
|
* Disable Rich text formats we currently cannot support
|
||||||
@ -36,8 +37,7 @@ type Props = {
|
|||||||
* @param root0.contentRef
|
* @param root0.contentRef
|
||||||
*/
|
*/
|
||||||
function PersonalizationTagsButton( { contentRef }: Props ) {
|
function PersonalizationTagsButton( { contentRef }: Props ) {
|
||||||
const { togglePersonalizationTagsModal } = useDispatch( storeName );
|
const [ isModalOpened, setIsModalOpened ] = useState( false );
|
||||||
|
|
||||||
const selectedBlockId = useSelect( ( select ) =>
|
const selectedBlockId = useSelect( ( select ) =>
|
||||||
select( 'core/block-editor' ).getSelectedBlockClientId()
|
select( 'core/block-editor' ).getSelectedBlockClientId()
|
||||||
);
|
);
|
||||||
@ -87,11 +87,15 @@ function PersonalizationTagsButton( { contentRef }: Props ) {
|
|||||||
<ToolbarButton
|
<ToolbarButton
|
||||||
icon="shortcode"
|
icon="shortcode"
|
||||||
title={ __( 'Personalization Tags', 'mailpoet' ) }
|
title={ __( 'Personalization Tags', 'mailpoet' ) }
|
||||||
onClick={ () => {
|
onClick={ () => setIsModalOpened( true ) }
|
||||||
togglePersonalizationTagsModal( true, {
|
/>
|
||||||
onInsert: handleInsert,
|
<PersonalizationTagsModal
|
||||||
} );
|
isOpened={ isModalOpened }
|
||||||
|
onInsert={ ( value ) => {
|
||||||
|
handleInsert( value );
|
||||||
|
setIsModalOpened( false );
|
||||||
} }
|
} }
|
||||||
|
closeCallback={ () => setIsModalOpened( false ) }
|
||||||
/>
|
/>
|
||||||
</ToolbarGroup>
|
</ToolbarGroup>
|
||||||
</BlockControls>
|
</BlockControls>
|
||||||
|
@ -24,7 +24,6 @@ import { StylesSidebar } from '../styles-sidebar';
|
|||||||
import { VisualEditor } from './visual-editor/visual-editor';
|
import { VisualEditor } from './visual-editor/visual-editor';
|
||||||
|
|
||||||
import { TemplateSelection } from '../template-select';
|
import { TemplateSelection } from '../template-select';
|
||||||
import { PersonalizationTagsModal } from '../personalization-tags/personalization-tags-modal';
|
|
||||||
|
|
||||||
export function Layout() {
|
export function Layout() {
|
||||||
const {
|
const {
|
||||||
@ -93,7 +92,6 @@ export function Layout() {
|
|||||||
<SentEmailNotice />
|
<SentEmailNotice />
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<StylesSidebar />
|
<StylesSidebar />
|
||||||
<PersonalizationTagsModal />
|
|
||||||
<TemplateSelection />
|
<TemplateSelection />
|
||||||
<InterfaceSkeleton
|
<InterfaceSkeleton
|
||||||
className={ className }
|
className={ className }
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
import { Button } from '@wordpress/components';
|
import { Button } from '@wordpress/components';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { PersonalizationTag, storeName } from '../../store';
|
import { PersonalizationTag } from '../../store';
|
||||||
import { useDispatch, useSelect } from '@wordpress/data';
|
|
||||||
|
|
||||||
const CategorySection = ( {
|
const CategorySection = ( {
|
||||||
groupedTags,
|
groupedTags,
|
||||||
activeCategory,
|
activeCategory,
|
||||||
|
onInsert,
|
||||||
}: {
|
}: {
|
||||||
groupedTags: Record< string, PersonalizationTag[] >;
|
groupedTags: Record< string, PersonalizationTag[] >;
|
||||||
activeCategory: string | null;
|
activeCategory: string | null;
|
||||||
|
onInsert: ( tag: string ) => void;
|
||||||
} ) => {
|
} ) => {
|
||||||
const { togglePersonalizationTagsModal } = useDispatch( storeName );
|
|
||||||
|
|
||||||
const { onInsert } = useSelect(
|
|
||||||
( select ) => select( storeName ).getPersonalizationTagsState(),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const categoriesToRender: [ string, PersonalizationTag[] ][] =
|
const categoriesToRender: [ string, PersonalizationTag[] ][] =
|
||||||
activeCategory === null
|
activeCategory === null
|
||||||
? Object.entries( groupedTags ) // Render all categories
|
? Object.entries( groupedTags ) // Render all categories
|
||||||
@ -46,9 +40,6 @@ const CategorySection = ( {
|
|||||||
if ( onInsert ) {
|
if ( onInsert ) {
|
||||||
onInsert( item.token );
|
onInsert( item.token );
|
||||||
}
|
}
|
||||||
togglePersonalizationTagsModal(
|
|
||||||
false
|
|
||||||
);
|
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
{ __( 'Insert' ) }
|
{ __( 'Insert' ) }
|
||||||
|
@ -1,31 +1,23 @@
|
|||||||
import { Modal, SearchControl } from '@wordpress/components';
|
import { Modal, SearchControl } from '@wordpress/components';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { PersonalizationTag, storeName } from '../../store';
|
import { PersonalizationTag, storeName } from '../../store';
|
||||||
import { useDispatch, useSelect } from '@wordpress/data';
|
import { select } from '@wordpress/data';
|
||||||
import { external, Icon } from '@wordpress/icons';
|
import { external, Icon } from '@wordpress/icons';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
import { useState } from '@wordpress/element';
|
import { useState } from '@wordpress/element';
|
||||||
import { CategoryMenu } from './category-menu';
|
import { CategoryMenu } from './category-menu';
|
||||||
import { CategorySection } from './category-section';
|
import { CategorySection } from './category-section';
|
||||||
|
|
||||||
const PersonalizationTagsModal = () => {
|
const PersonalizationTagsModal = ( { onInsert, isOpened, closeCallback } ) => {
|
||||||
const [ activeCategory, setActiveCategory ] = useState( null );
|
const [ activeCategory, setActiveCategory ] = useState( null );
|
||||||
const [ searchQuery, setSearchQuery ] = useState( '' );
|
const [ searchQuery, setSearchQuery ] = useState( '' );
|
||||||
|
|
||||||
const { togglePersonalizationTagsModal } = useDispatch( storeName );
|
if ( ! isOpened ) {
|
||||||
|
|
||||||
const { isModalOpened, list } = useSelect( ( select ) => {
|
|
||||||
const store = select( storeName );
|
|
||||||
return {
|
|
||||||
isModalOpened: store.getPersonalizationTagsState().isModalOpened,
|
|
||||||
list: store.getPersonalizationTagsList(),
|
|
||||||
};
|
|
||||||
}, [] );
|
|
||||||
|
|
||||||
if ( ! isModalOpened ) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const list = select( storeName ).getPersonalizationTagsList();
|
||||||
|
|
||||||
const groupedTags: Record< string, PersonalizationTag[] > = list.reduce(
|
const groupedTags: Record< string, PersonalizationTag[] > = list.reduce(
|
||||||
( groups, item ) => {
|
( groups, item ) => {
|
||||||
const { category, name, token } = item;
|
const { category, name, token } = item;
|
||||||
@ -49,7 +41,7 @@ const PersonalizationTagsModal = () => {
|
|||||||
<Modal
|
<Modal
|
||||||
size="medium"
|
size="medium"
|
||||||
title={ __( 'Personalization Tags', 'mailpoet' ) }
|
title={ __( 'Personalization Tags', 'mailpoet' ) }
|
||||||
onRequestClose={ () => togglePersonalizationTagsModal( false ) }
|
onRequestClose={ closeCallback }
|
||||||
className="mailpoet-personalization-tags-modal"
|
className="mailpoet-personalization-tags-modal"
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
@ -68,6 +60,7 @@ const PersonalizationTagsModal = () => {
|
|||||||
<CategorySection
|
<CategorySection
|
||||||
groupedTags={ groupedTags }
|
groupedTags={ groupedTags }
|
||||||
activeCategory={ activeCategory }
|
activeCategory={ activeCategory }
|
||||||
|
onInsert={ onInsert }
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
getCursorPosition,
|
getCursorPosition,
|
||||||
isMatchingComment,
|
isMatchingComment,
|
||||||
} from '../personalization-tags/rich-text-utils';
|
} from '../personalization-tags/rich-text-utils';
|
||||||
|
import { PersonalizationTagsModal } from '../personalization-tags/personalization-tags-modal';
|
||||||
|
|
||||||
const previewTextMaxLength = 150;
|
const previewTextMaxLength = 150;
|
||||||
const previewTextRecommendedLength = 80;
|
const previewTextRecommendedLength = 80;
|
||||||
@ -38,36 +39,33 @@ export function DetailsPanel() {
|
|||||||
'mailpoet_data'
|
'mailpoet_data'
|
||||||
);
|
);
|
||||||
|
|
||||||
const { togglePersonalizationTagsModal, updateEmailMailPoetProperty } =
|
const { updateEmailMailPoetProperty } = useDispatch( storeName );
|
||||||
useDispatch( storeName );
|
|
||||||
const [ activeRichText, setActiveRichText ] = useState( null );
|
|
||||||
const [ selectionRange, setSelectionRange ] = useState( null );
|
const [ selectionRange, setSelectionRange ] = useState( null );
|
||||||
|
const [ subjectModalIsOpened, setSubjectModalIsOpened ] = useState( false );
|
||||||
|
const [ preheaderModalIsOpened, setPreheaderModalIsOpened ] =
|
||||||
|
useState( false );
|
||||||
|
|
||||||
const subjectRef = useRef( null );
|
const subjectRef = useRef( null );
|
||||||
const preheaderRef = useRef( null );
|
const preheaderRef = useRef( null );
|
||||||
|
|
||||||
const handleInsertPersonalizationTag = async ( value ) => {
|
const handleInsertPersonalizationTag = async ( value, activeRichText ) => {
|
||||||
if ( ! activeRichText || ! selectionRange ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ref = activeRichText === 'subject' ? subjectRef : preheaderRef;
|
|
||||||
if ( ! ref ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the current value of the active RichText
|
// Retrieve the current value of the active RichText
|
||||||
const currentValue =
|
const currentValue =
|
||||||
activeRichText === 'subject'
|
activeRichText === 'subject'
|
||||||
? mailpoetEmailData?.subject ?? ''
|
? mailpoetEmailData?.subject ?? ''
|
||||||
: mailpoetEmailData?.preheader ?? '';
|
: mailpoetEmailData?.preheader ?? '';
|
||||||
|
|
||||||
|
const ref = activeRichText === 'subject' ? subjectRef : preheaderRef;
|
||||||
|
if ( ! ref ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate text-to-HTML mapping
|
// Generate text-to-HTML mapping
|
||||||
const { mapping } = createTextToHtmlMap( currentValue );
|
const { mapping } = createTextToHtmlMap( currentValue );
|
||||||
|
|
||||||
// Ensure selection range is within bounds
|
// Ensure selection range is within bounds
|
||||||
const start = selectionRange.start;
|
const start = selectionRange?.start ?? currentValue.length;
|
||||||
const end = selectionRange.end;
|
const end = selectionRange?.end ?? currentValue.length;
|
||||||
|
|
||||||
// Default values for starting and ending indexes.
|
// Default values for starting and ending indexes.
|
||||||
let htmlStart = start;
|
let htmlStart = start;
|
||||||
@ -124,10 +122,7 @@ export function DetailsPanel() {
|
|||||||
<span>{ __( 'Subject', 'mailpoet' ) }</span>
|
<span>{ __( 'Subject', 'mailpoet' ) }</span>
|
||||||
<PersonalizationTagsButton
|
<PersonalizationTagsButton
|
||||||
onClick={ () => {
|
onClick={ () => {
|
||||||
setActiveRichText( 'subject' );
|
setSubjectModalIsOpened( true );
|
||||||
togglePersonalizationTagsModal( true, {
|
|
||||||
onInsert: handleInsertPersonalizationTag,
|
|
||||||
} );
|
|
||||||
} }
|
} }
|
||||||
/>
|
/>
|
||||||
<ExternalLink href="https://kb.mailpoet.com/article/215-personalize-newsletter-with-shortcodes#list">
|
<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>
|
<span>{ __( 'Preview text', 'mailpoet' ) }</span>
|
||||||
<PersonalizationTagsButton
|
<PersonalizationTagsButton
|
||||||
onClick={ () => {
|
onClick={ () => {
|
||||||
setActiveRichText( 'preheader' );
|
setPreheaderModalIsOpened( true );
|
||||||
togglePersonalizationTagsModal( true, {
|
|
||||||
onInsert: handleInsertPersonalizationTag,
|
|
||||||
} );
|
|
||||||
} }
|
} }
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
@ -196,6 +188,14 @@ export function DetailsPanel() {
|
|||||||
className="mailpoet-settings-panel__subject"
|
className="mailpoet-settings-panel__subject"
|
||||||
help={ subjectHelp }
|
help={ subjectHelp }
|
||||||
>
|
>
|
||||||
|
<PersonalizationTagsModal
|
||||||
|
isOpened={ subjectModalIsOpened }
|
||||||
|
onInsert={ ( value ) => {
|
||||||
|
handleInsertPersonalizationTag( value, 'subject' );
|
||||||
|
setSubjectModalIsOpened( false );
|
||||||
|
} }
|
||||||
|
closeCallback={ () => setSubjectModalIsOpened( false ) }
|
||||||
|
/>
|
||||||
<RichText
|
<RichText
|
||||||
ref={ subjectRef }
|
ref={ subjectRef }
|
||||||
className="mailpoet-settings-panel__richtext"
|
className="mailpoet-settings-panel__richtext"
|
||||||
@ -204,7 +204,6 @@ export function DetailsPanel() {
|
|||||||
'mailpoet'
|
'mailpoet'
|
||||||
) }
|
) }
|
||||||
onFocus={ () => {
|
onFocus={ () => {
|
||||||
setActiveRichText( 'subject' );
|
|
||||||
setSelectionRange(
|
setSelectionRange(
|
||||||
getCursorPosition(
|
getCursorPosition(
|
||||||
subjectRef,
|
subjectRef,
|
||||||
@ -213,7 +212,6 @@ export function DetailsPanel() {
|
|||||||
);
|
);
|
||||||
} }
|
} }
|
||||||
onKeyUp={ () => {
|
onKeyUp={ () => {
|
||||||
setActiveRichText( 'subject' );
|
|
||||||
setSelectionRange(
|
setSelectionRange(
|
||||||
getCursorPosition(
|
getCursorPosition(
|
||||||
subjectRef,
|
subjectRef,
|
||||||
@ -222,7 +220,6 @@ export function DetailsPanel() {
|
|||||||
);
|
);
|
||||||
} }
|
} }
|
||||||
onClick={ () => {
|
onClick={ () => {
|
||||||
setActiveRichText( 'subject' );
|
|
||||||
setSelectionRange(
|
setSelectionRange(
|
||||||
getCursorPosition(
|
getCursorPosition(
|
||||||
subjectRef,
|
subjectRef,
|
||||||
@ -244,6 +241,14 @@ export function DetailsPanel() {
|
|||||||
className="mailpoet-settings-panel__preview-text"
|
className="mailpoet-settings-panel__preview-text"
|
||||||
help={ preheaderHelp }
|
help={ preheaderHelp }
|
||||||
>
|
>
|
||||||
|
<PersonalizationTagsModal
|
||||||
|
isOpened={ preheaderModalIsOpened }
|
||||||
|
onInsert={ ( value ) => {
|
||||||
|
handleInsertPersonalizationTag( value, 'preheader' );
|
||||||
|
setPreheaderModalIsOpened( false );
|
||||||
|
} }
|
||||||
|
closeCallback={ () => setPreheaderModalIsOpened( false ) }
|
||||||
|
/>
|
||||||
<RichText
|
<RichText
|
||||||
ref={ preheaderRef }
|
ref={ preheaderRef }
|
||||||
className="mailpoet-settings-panel__richtext"
|
className="mailpoet-settings-panel__richtext"
|
||||||
@ -252,7 +257,6 @@ export function DetailsPanel() {
|
|||||||
'mailpoet'
|
'mailpoet'
|
||||||
) }
|
) }
|
||||||
onFocus={ () => {
|
onFocus={ () => {
|
||||||
setActiveRichText( 'preheader' );
|
|
||||||
setSelectionRange(
|
setSelectionRange(
|
||||||
getCursorPosition(
|
getCursorPosition(
|
||||||
preheaderRef,
|
preheaderRef,
|
||||||
@ -261,7 +265,6 @@ export function DetailsPanel() {
|
|||||||
);
|
);
|
||||||
} }
|
} }
|
||||||
onKeyUp={ () => {
|
onKeyUp={ () => {
|
||||||
setActiveRichText( 'preheader' );
|
|
||||||
setSelectionRange(
|
setSelectionRange(
|
||||||
getCursorPosition(
|
getCursorPosition(
|
||||||
preheaderRef,
|
preheaderRef,
|
||||||
@ -270,7 +273,6 @@ export function DetailsPanel() {
|
|||||||
);
|
);
|
||||||
} }
|
} }
|
||||||
onClick={ () => {
|
onClick={ () => {
|
||||||
setActiveRichText( 'preheader' );
|
|
||||||
setSelectionRange(
|
setSelectionRange(
|
||||||
getCursorPosition(
|
getCursorPosition(
|
||||||
preheaderRef,
|
preheaderRef,
|
||||||
|
@ -39,9 +39,7 @@ export function getInitialState(): State {
|
|||||||
sendingPreviewStatus: null,
|
sendingPreviewStatus: null,
|
||||||
},
|
},
|
||||||
personalizationTags: {
|
personalizationTags: {
|
||||||
isModalOpened: false,
|
|
||||||
list: [],
|
list: [],
|
||||||
onInsert: null,
|
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -201,9 +201,7 @@ export type State = {
|
|||||||
sendingPreviewStatus: SendingPreviewStatus | null;
|
sendingPreviewStatus: SendingPreviewStatus | null;
|
||||||
};
|
};
|
||||||
personalizationTags: {
|
personalizationTags: {
|
||||||
isModalOpened: boolean;
|
|
||||||
list: PersonalizationTag[];
|
list: PersonalizationTag[];
|
||||||
onInsert: ( ( value: string ) => void ) | null;
|
|
||||||
isFetching: boolean;
|
isFetching: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user