Move email editor components out of the engine folder
MAILPOET-6215
This commit is contained in:
committed by
Oluwaseun Olorunsola
parent
e6d607028c
commit
1c3ea9cd0a
@@ -0,0 +1,86 @@
|
||||
import { useRef } from '@wordpress/element';
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
VisuallyHidden,
|
||||
__experimentalText as Text, // eslint-disable-line
|
||||
TextControl,
|
||||
} from '@wordpress/components';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { chevronDown } from '@wordpress/icons';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { useEntityProp } from '@wordpress/core-data';
|
||||
import { storeName } from '../../store';
|
||||
|
||||
// @see https://github.com/WordPress/gutenberg/blob/5e0ffdbc36cb2e967dfa6a6b812a10a2e56a598f/packages/edit-post/src/components/header/document-actions/index.js
|
||||
|
||||
export function CampaignName() {
|
||||
const { showIconLabels } = useSelect(
|
||||
( select ) => ( {
|
||||
showIconLabels:
|
||||
select( storeName ).isFeatureActive( 'showIconLabels' ),
|
||||
postId: select( storeName ).getEmailPostId(),
|
||||
} ),
|
||||
[]
|
||||
);
|
||||
|
||||
const [ emailTitle = '', setTitle ] = useEntityProp(
|
||||
'postType',
|
||||
'mailpoet_email',
|
||||
'title'
|
||||
);
|
||||
|
||||
const titleRef = useRef( null );
|
||||
return (
|
||||
<div ref={ titleRef } className="mailpoet-email-editor-campaign-name">
|
||||
<Dropdown
|
||||
popoverProps={ {
|
||||
placement: 'bottom',
|
||||
anchor: titleRef.current,
|
||||
} }
|
||||
contentClassName="mailpoet-email-editor-campaign-name__dropdown"
|
||||
renderToggle={ ( { isOpen, onToggle } ) => (
|
||||
<>
|
||||
<Button
|
||||
onClick={ onToggle }
|
||||
className="mailpoet-email-campaign-name__link"
|
||||
>
|
||||
<Text size="body" as="h1">
|
||||
<VisuallyHidden as="span">
|
||||
{ __( 'Editing email:', 'mailpoet' ) }
|
||||
</VisuallyHidden>
|
||||
{ emailTitle }
|
||||
</Text>
|
||||
</Button>
|
||||
<Button
|
||||
className="mailpoet-email-campaign-name__toggle"
|
||||
icon={ chevronDown }
|
||||
aria-expanded={ isOpen }
|
||||
aria-haspopup="true"
|
||||
onClick={ onToggle }
|
||||
label={ __( 'Change campaign name', 'mailpoet' ) }
|
||||
>
|
||||
{ showIconLabels && __( 'Rename', 'mailpoet' ) }
|
||||
</Button>
|
||||
</>
|
||||
) }
|
||||
renderContent={ () => (
|
||||
<div className="mailpoet-email-editor-email-title-edit">
|
||||
<TextControl
|
||||
label={ __( 'Campaign name', 'mailpoet' ) }
|
||||
value={ emailTitle }
|
||||
onChange={ ( newTitle ) => {
|
||||
setTitle( newTitle );
|
||||
} }
|
||||
name="campaign_name"
|
||||
help={ __(
|
||||
`Name your email campaign to indicate its purpose. This would only be visible to you and not shown to your subscribers.`,
|
||||
'mailpoet'
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
205
packages/js/email-editor/src/components/header/header.tsx
Normal file
205
packages/js/email-editor/src/components/header/header.tsx
Normal file
@@ -0,0 +1,205 @@
|
||||
import { useRef, useState } from '@wordpress/element';
|
||||
import { PinnedItems } from '@wordpress/interface';
|
||||
import { Button, ToolbarItem as WpToolbarItem } from '@wordpress/components';
|
||||
import {
|
||||
NavigableToolbar,
|
||||
BlockToolbar as WPBlockToolbar,
|
||||
store as blockEditorStore,
|
||||
} from '@wordpress/block-editor';
|
||||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
import { store as coreDataStore } from '@wordpress/core-data';
|
||||
// @ts-expect-error DocumentBar types are not available
|
||||
import { DocumentBar, store as editorStore } from '@wordpress/editor';
|
||||
import { store as preferencesStore } from '@wordpress/preferences';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { plus, listView, undo, redo, next, previous } from '@wordpress/icons';
|
||||
import classnames from 'classnames';
|
||||
import { storeName } from '../../store';
|
||||
import { MoreMenu } from './more-menu';
|
||||
import { PreviewDropdown } from '../preview';
|
||||
import { SaveButton } from './save-button';
|
||||
import { CampaignName } from './campaign-name';
|
||||
import { SendButton } from './send-button';
|
||||
|
||||
import { unlock } from '../../lock-unlock';
|
||||
|
||||
// Build type for ToolbarItem contains only "as" and "children" properties but it takes all props from
|
||||
// component passed to "as" property (in this case Button). So as fix for TS errors we need to pass all props from Button to ToolbarItem.
|
||||
// We should be able to remove this fix when ToolbarItem will be fixed in Gutenberg.
|
||||
const ToolbarItem = WpToolbarItem as React.ForwardRefExoticComponent<
|
||||
React.ComponentProps< typeof WpToolbarItem > &
|
||||
React.ComponentProps< typeof Button >
|
||||
>;
|
||||
|
||||
// Definition of BlockToolbar in currently installed Gutenberg packages (wp-6.4) is missing hideDragHandle prop
|
||||
// After updating to newer version of Gutenberg we should be able to remove this fix
|
||||
const BlockToolbar = WPBlockToolbar as React.FC<
|
||||
React.ComponentProps< typeof WPBlockToolbar > & {
|
||||
hideDragHandle?: boolean;
|
||||
}
|
||||
>;
|
||||
|
||||
export function Header() {
|
||||
const inserterButton = useRef();
|
||||
const listviewButton = useRef();
|
||||
const undoButton = useRef();
|
||||
const redoButton = useRef();
|
||||
|
||||
const [ isBlockToolsCollapsed, setIsBlockToolsCollapsed ] =
|
||||
useState( false );
|
||||
|
||||
const { toggleInserterSidebar, toggleListviewSidebar } =
|
||||
useDispatch( storeName );
|
||||
const { undo: undoAction, redo: redoAction } = useDispatch( coreDataStore );
|
||||
const {
|
||||
isInserterSidebarOpened,
|
||||
isListviewSidebarOpened,
|
||||
isFixedToolbarActive,
|
||||
isBlockSelected,
|
||||
hasUndo,
|
||||
hasRedo,
|
||||
hasDocumentNavigationHistory,
|
||||
} = useSelect( ( select ) => {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { getEditorSettings: _getEditorSettings } = unlock(
|
||||
select( editorStore )
|
||||
);
|
||||
const editorSettings = _getEditorSettings();
|
||||
|
||||
return {
|
||||
isInserterSidebarOpened:
|
||||
select( storeName ).isInserterSidebarOpened(),
|
||||
isListviewSidebarOpened:
|
||||
select( storeName ).isListviewSidebarOpened(),
|
||||
isFixedToolbarActive: select( preferencesStore ).get(
|
||||
'core',
|
||||
'fixedToolbar'
|
||||
),
|
||||
isBlockSelected:
|
||||
!! select( blockEditorStore ).getBlockSelectionStart(),
|
||||
hasUndo: select( coreDataStore ).hasUndo(),
|
||||
hasRedo: select( coreDataStore ).hasRedo(),
|
||||
hasDocumentNavigationHistory:
|
||||
!! editorSettings.onNavigateToPreviousEntityRecord,
|
||||
};
|
||||
}, [] );
|
||||
|
||||
const preventDefault = ( event ) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
const shortLabelInserter = ! isInserterSidebarOpened
|
||||
? __( 'Add', 'mailpoet' )
|
||||
: __( 'Close', 'mailpoet' );
|
||||
|
||||
return (
|
||||
<div className="editor-header edit-post-header">
|
||||
<div className="editor-header__toolbar">
|
||||
<NavigableToolbar
|
||||
className="editor-document-tools edit-post-header-toolbar is-unstyled"
|
||||
aria-label={ __( 'Email document tools', 'mailpoet' ) }
|
||||
>
|
||||
<div className="editor-document-tools__left">
|
||||
<ToolbarItem
|
||||
ref={ inserterButton }
|
||||
as={ Button }
|
||||
className="editor-header-toolbar__inserter-toggle edit-post-header-toolbar__inserter-toggle"
|
||||
variant="primary"
|
||||
isPressed={ isInserterSidebarOpened }
|
||||
onMouseDown={ preventDefault }
|
||||
onClick={ toggleInserterSidebar }
|
||||
disabled={ false }
|
||||
icon={ plus }
|
||||
label={ shortLabelInserter }
|
||||
showTooltip
|
||||
aria-expanded={ isInserterSidebarOpened }
|
||||
/>
|
||||
<ToolbarItem
|
||||
ref={ undoButton }
|
||||
as={ Button }
|
||||
className="editor-history__undo"
|
||||
isPressed={ false }
|
||||
onMouseDown={ preventDefault }
|
||||
onClick={ undoAction }
|
||||
disabled={ ! hasUndo }
|
||||
icon={ undo }
|
||||
label={ __( 'Undo', 'mailpoet' ) }
|
||||
showTooltip
|
||||
/>
|
||||
<ToolbarItem
|
||||
ref={ redoButton }
|
||||
as={ Button }
|
||||
className="editor-history__redo"
|
||||
isPressed={ false }
|
||||
onMouseDown={ preventDefault }
|
||||
onClick={ redoAction }
|
||||
disabled={ ! hasRedo }
|
||||
icon={ redo }
|
||||
label={ __( 'Redo', 'mailpoet' ) }
|
||||
showTooltip
|
||||
/>
|
||||
<ToolbarItem
|
||||
ref={ listviewButton }
|
||||
as={ Button }
|
||||
className="editor-header-toolbar__document-overview-toggle edit-post-header-toolbar__document-overview-toggle"
|
||||
isPressed={ isListviewSidebarOpened }
|
||||
onMouseDown={ preventDefault }
|
||||
onClick={ toggleListviewSidebar }
|
||||
disabled={ false }
|
||||
icon={ listView }
|
||||
label={ __( 'List view', 'mailpoet' ) }
|
||||
showTooltip
|
||||
aria-expanded={ isInserterSidebarOpened }
|
||||
/>
|
||||
</div>
|
||||
</NavigableToolbar>
|
||||
{ isFixedToolbarActive && isBlockSelected && (
|
||||
<>
|
||||
<div
|
||||
className={ classnames(
|
||||
'editor-collapsible-block-toolbar',
|
||||
{
|
||||
'is-collapsed': isBlockToolsCollapsed,
|
||||
}
|
||||
) }
|
||||
>
|
||||
<BlockToolbar hideDragHandle />
|
||||
</div>
|
||||
<Button
|
||||
className="editor-header__block-tools-toggle edit-post-header__block-tools-toggle"
|
||||
icon={ isBlockToolsCollapsed ? next : previous }
|
||||
onClick={ () => {
|
||||
setIsBlockToolsCollapsed(
|
||||
( collapsed ) => ! collapsed
|
||||
);
|
||||
} }
|
||||
label={
|
||||
isBlockToolsCollapsed
|
||||
? __( 'Show block tools', 'mailpoet' )
|
||||
: __( 'Hide block tools', 'mailpoet' )
|
||||
}
|
||||
/>
|
||||
</>
|
||||
) }
|
||||
</div>
|
||||
{ ( ! isFixedToolbarActive ||
|
||||
! isBlockSelected ||
|
||||
isBlockToolsCollapsed ) && (
|
||||
<div className="editor-header__center edit-post-header__center">
|
||||
{ hasDocumentNavigationHistory ? (
|
||||
<DocumentBar />
|
||||
) : (
|
||||
<CampaignName />
|
||||
) }
|
||||
</div>
|
||||
) }
|
||||
<div className="editor-header__settings edit-post-header__settings">
|
||||
<SaveButton />
|
||||
<PreviewDropdown />
|
||||
<SendButton />
|
||||
<PinnedItems.Slot scope={ storeName } />
|
||||
<MoreMenu />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
41
packages/js/email-editor/src/components/header/index.scss
Normal file
41
packages/js/email-editor/src/components/header/index.scss
Normal file
@@ -0,0 +1,41 @@
|
||||
// Document actions - Component in header for displaying email/campaign title edit popup
|
||||
.mailpoet-email-editor-campaign-name {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
|
||||
.components-dropdown {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.components-button {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mailpoet-email-campaign-name__link {
|
||||
display: inline-flex;
|
||||
height: fit-content;
|
||||
margin-right: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
// Document actions - Popup for editing email/campaign title
|
||||
.mailpoet-email-editor-campaign-name__dropdown {
|
||||
.components-popover__content {
|
||||
min-width: 280px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mailpoet-email-editor-email-title-edit {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
.mailpoet-email-editor-save-button__dropdown {
|
||||
.components-popover__content {
|
||||
min-width: 280px;
|
||||
}
|
||||
}
|
3
packages/js/email-editor/src/components/header/index.ts
Normal file
3
packages/js/email-editor/src/components/header/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import './index.scss';
|
||||
|
||||
export * from './header';
|
137
packages/js/email-editor/src/components/header/more-menu.tsx
Normal file
137
packages/js/email-editor/src/components/header/more-menu.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { MenuGroup, MenuItem, DropdownMenu } from '@wordpress/components';
|
||||
import { useState } from '@wordpress/element';
|
||||
import { displayShortcut } from '@wordpress/keycodes';
|
||||
import { moreVertical } from '@wordpress/icons';
|
||||
import { useEntityProp } from '@wordpress/core-data';
|
||||
import { __, _x } from '@wordpress/i18n';
|
||||
import { PreferenceToggleMenuItem } from '@wordpress/preferences';
|
||||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
import { storeName } from '../../store';
|
||||
import { TrashModal } from './trash-modal';
|
||||
|
||||
// See:
|
||||
// https://github.com/WordPress/gutenberg/blob/9601a33e30ba41bac98579c8d822af63dd961488/packages/edit-post/src/components/header/more-menu/index.js
|
||||
// https://github.com/WordPress/gutenberg/blob/0ee78b1bbe9c6f3e6df99f3b967132fa12bef77d/packages/edit-site/src/components/header/more-menu/index.js
|
||||
|
||||
export function MoreMenu(): JSX.Element {
|
||||
const [ showTrashModal, setShowTrashModal ] = useState( false );
|
||||
const { urls, postId } = useSelect(
|
||||
( select ) => ( {
|
||||
urls: select( storeName ).getUrls(),
|
||||
postId: select( storeName ).getEmailPostId(),
|
||||
} ),
|
||||
[]
|
||||
);
|
||||
const [ status, setStatus ] = useEntityProp(
|
||||
'postType',
|
||||
'mailpoet_email',
|
||||
'status'
|
||||
);
|
||||
const { saveEditedEmail, updateEmailMailPoetProperty } =
|
||||
useDispatch( storeName );
|
||||
const goToListings = () => {
|
||||
window.location.href = urls.listings;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DropdownMenu
|
||||
className="edit-site-more-menu"
|
||||
popoverProps={ {
|
||||
className: 'edit-site-more-menu__content',
|
||||
} }
|
||||
icon={ moreVertical }
|
||||
label={ __( 'More', 'mailpoet' ) }
|
||||
>
|
||||
{ () => (
|
||||
<>
|
||||
<MenuGroup label={ _x( 'View', 'noun', 'mailpoet' ) }>
|
||||
<PreferenceToggleMenuItem
|
||||
scope="core"
|
||||
name="fixedToolbar"
|
||||
label={ __( 'Top toolbar', 'mailpoet' ) }
|
||||
info={ __(
|
||||
'Access all block and document tools in a single place',
|
||||
'mailpoet'
|
||||
) }
|
||||
messageActivated={ __(
|
||||
'Top toolbar activated',
|
||||
'mailpoet'
|
||||
) }
|
||||
messageDeactivated={ __(
|
||||
'Top toolbar deactivated',
|
||||
'mailpoet'
|
||||
) }
|
||||
/>
|
||||
<PreferenceToggleMenuItem
|
||||
scope="core"
|
||||
name="focusMode"
|
||||
label={ __( 'Spotlight mode', 'mailpoet' ) }
|
||||
info={ __(
|
||||
'Focus at one block at a time',
|
||||
'mailpoet'
|
||||
) }
|
||||
messageActivated={ __(
|
||||
'Spotlight mode activated',
|
||||
'mailpoet'
|
||||
) }
|
||||
messageDeactivated={ __(
|
||||
'Spotlight mode deactivated',
|
||||
'mailpoet'
|
||||
) }
|
||||
/>
|
||||
<PreferenceToggleMenuItem
|
||||
scope={ storeName }
|
||||
name="fullscreenMode"
|
||||
label={ __( 'Fullscreen mode', 'mailpoet' ) }
|
||||
info={ __(
|
||||
'Work without distraction',
|
||||
'mailpoet'
|
||||
) }
|
||||
messageActivated={ __(
|
||||
'Fullscreen mode activated',
|
||||
'mailpoet'
|
||||
) }
|
||||
messageDeactivated={ __(
|
||||
'Fullscreen mode deactivated',
|
||||
'mailpoet'
|
||||
) }
|
||||
shortcut={ displayShortcut.secondary( 'f' ) }
|
||||
/>
|
||||
</MenuGroup>
|
||||
<MenuGroup>
|
||||
{ status === 'trash' ? (
|
||||
<MenuItem
|
||||
onClick={ async () => {
|
||||
await setStatus( 'draft' );
|
||||
await updateEmailMailPoetProperty(
|
||||
'deleted_at',
|
||||
''
|
||||
);
|
||||
await saveEditedEmail();
|
||||
} }
|
||||
>
|
||||
{ __( 'Restore from trash', 'mailpoet' ) }
|
||||
</MenuItem>
|
||||
) : (
|
||||
<MenuItem
|
||||
onClick={ () => setShowTrashModal( true ) }
|
||||
isDestructive
|
||||
>
|
||||
{ __( 'Move to trash', 'mailpoet' ) }
|
||||
</MenuItem>
|
||||
) }
|
||||
</MenuGroup>
|
||||
</>
|
||||
) }
|
||||
</DropdownMenu>
|
||||
{ showTrashModal && (
|
||||
<TrashModal
|
||||
onClose={ () => setShowTrashModal( false ) }
|
||||
onRemove={ goToListings }
|
||||
postId={ postId }
|
||||
/>
|
||||
) }
|
||||
</>
|
||||
);
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
import { useRef } from '@wordpress/element';
|
||||
import { Button, Dropdown } from '@wordpress/components';
|
||||
import {
|
||||
// @ts-expect-error No types available for useEntitiesSavedStatesIsDirty
|
||||
useEntitiesSavedStatesIsDirty,
|
||||
// @ts-expect-error Our current version of packages doesn't have EntitiesSavedStates export
|
||||
EntitiesSavedStates,
|
||||
} from '@wordpress/editor';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import { check, cloud, Icon } from '@wordpress/icons';
|
||||
import { storeName } from '../../store';
|
||||
|
||||
export function SaveButton() {
|
||||
const { saveEditedEmail } = useDispatch( storeName );
|
||||
|
||||
const { dirtyEntityRecords } = useEntitiesSavedStatesIsDirty();
|
||||
|
||||
const { hasEdits, isEmpty, isSaving } = useSelect(
|
||||
( select ) => ( {
|
||||
hasEdits: select( storeName ).hasEdits(),
|
||||
isEmpty: select( storeName ).isEmpty(),
|
||||
isSaving: select( storeName ).isSaving(),
|
||||
} ),
|
||||
[]
|
||||
);
|
||||
|
||||
const buttonRef = useRef( null );
|
||||
|
||||
const hasNonEmailEdits = dirtyEntityRecords.some(
|
||||
( entity ) => entity.name !== 'mailpoet_email'
|
||||
);
|
||||
|
||||
const isSaved = ! isEmpty && ! isSaving && ! hasEdits;
|
||||
const isDisabled = isEmpty || isSaving || isSaved;
|
||||
|
||||
let label = __( 'Save Draft', 'mailpoet' );
|
||||
if ( isSaved ) {
|
||||
label = __( 'Saved', 'mailpoet' );
|
||||
} else if ( isSaving ) {
|
||||
label = __( 'Saving', 'mailpoet' );
|
||||
}
|
||||
|
||||
return hasNonEmailEdits ? (
|
||||
<div ref={ buttonRef }>
|
||||
<Dropdown
|
||||
popoverProps={ {
|
||||
placement: 'bottom',
|
||||
anchor: buttonRef.current,
|
||||
} }
|
||||
contentClassName="mailpoet-email-editor-save-button__dropdown"
|
||||
renderToggle={ ( { onToggle } ) => (
|
||||
<Button onClick={ onToggle } variant="tertiary">
|
||||
{ hasEdits
|
||||
? __( 'Save email & template', 'mailpoet' )
|
||||
: __( 'Save template', 'mailpoet' ) }
|
||||
</Button>
|
||||
) }
|
||||
renderContent={ ( { onToggle } ) => (
|
||||
<EntitiesSavedStates close={ onToggle } />
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
variant="tertiary"
|
||||
disabled={ isDisabled }
|
||||
onClick={ saveEditedEmail }
|
||||
>
|
||||
{ isSaving && <Icon icon={ cloud } /> }
|
||||
{ isSaved && <Icon icon={ check } /> }
|
||||
{ label }
|
||||
</Button>
|
||||
);
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Button } from '@wordpress/components';
|
||||
import {
|
||||
store as editorStore,
|
||||
// @ts-expect-error No types available for useEntitiesSavedStatesIsDirty
|
||||
useEntitiesSavedStatesIsDirty,
|
||||
} from '@wordpress/editor';
|
||||
import { useEntityProp } from '@wordpress/core-data';
|
||||
import { MailPoetEmailData, storeName } from '../../store';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { useContentValidation } from '../../hooks';
|
||||
|
||||
export function SendButton() {
|
||||
const [ mailpoetEmail ] = useEntityProp(
|
||||
'postType',
|
||||
'mailpoet_email',
|
||||
'mailpoet_data'
|
||||
);
|
||||
|
||||
const { isDirty } = useEntitiesSavedStatesIsDirty();
|
||||
|
||||
const { validateContent, isValid } = useContentValidation();
|
||||
const { hasEmptyContent, isEmailSent, isEditingTemplate } = useSelect(
|
||||
( select ) => ( {
|
||||
hasEmptyContent: select( storeName ).hasEmptyContent(),
|
||||
isEmailSent: select( storeName ).isEmailSent(),
|
||||
isEditingTemplate:
|
||||
select( editorStore ).getCurrentPostType() === 'wp_template',
|
||||
} ),
|
||||
[]
|
||||
);
|
||||
|
||||
const isDisabled =
|
||||
isEditingTemplate ||
|
||||
hasEmptyContent ||
|
||||
isEmailSent ||
|
||||
isValid ||
|
||||
isDirty;
|
||||
|
||||
const mailpoetEmailData: MailPoetEmailData = mailpoetEmail;
|
||||
return (
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={ () => {
|
||||
if ( validateContent() ) {
|
||||
window.location.href = `admin.php?page=mailpoet-newsletters#/send/${ mailpoetEmailData.id }`;
|
||||
}
|
||||
} }
|
||||
disabled={ isDisabled }
|
||||
>
|
||||
{ __( 'Send', 'mailpoet' ) }
|
||||
</Button>
|
||||
);
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Button, Modal } from '@wordpress/components';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import { store as coreStore } from '@wordpress/core-data';
|
||||
import { store as noticesStore } from '@wordpress/notices';
|
||||
|
||||
export function TrashModal( {
|
||||
onClose,
|
||||
onRemove,
|
||||
postId,
|
||||
}: {
|
||||
onClose: () => void;
|
||||
onRemove: () => void;
|
||||
postId: number;
|
||||
} ) {
|
||||
const { getLastEntityDeleteError } = useSelect( coreStore );
|
||||
const { deleteEntityRecord } = useDispatch( coreStore );
|
||||
const { createErrorNotice } = useDispatch( noticesStore );
|
||||
const closeCallback = () => {
|
||||
onClose();
|
||||
};
|
||||
const trashCallback = async () => {
|
||||
const success = await deleteEntityRecord(
|
||||
'postType',
|
||||
'mailpoet_email',
|
||||
postId as unknown as string,
|
||||
{},
|
||||
{ throwOnError: false }
|
||||
);
|
||||
if ( success ) {
|
||||
onRemove();
|
||||
} else {
|
||||
const lastError = getLastEntityDeleteError(
|
||||
'postType',
|
||||
'mailpoet_email',
|
||||
postId
|
||||
);
|
||||
// Already deleted.
|
||||
if ( lastError?.code === 410 ) {
|
||||
onRemove();
|
||||
} else {
|
||||
const errorMessage = lastError?.message
|
||||
? ( lastError.message as string )
|
||||
: __(
|
||||
'An error occurred while moving the email to the trash.',
|
||||
'mailpoet'
|
||||
);
|
||||
await createErrorNotice( errorMessage, {
|
||||
type: 'snackbar',
|
||||
isDismissible: true,
|
||||
context: 'email-editor',
|
||||
} );
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Modal
|
||||
className="mailpoet-move-to-trash-modal"
|
||||
title={ __( 'Move to trash', 'mailpoet' ) }
|
||||
onRequestClose={ closeCallback }
|
||||
focusOnMount="firstContentElement"
|
||||
>
|
||||
<p>
|
||||
{ __(
|
||||
'Are you sure you want to move this email to trash?',
|
||||
'mailpoet'
|
||||
) }
|
||||
</p>
|
||||
<div className="mailpoet-send-preview-modal-footer">
|
||||
<Button variant="tertiary" onClick={ closeCallback }>
|
||||
{ __( 'Cancel', 'mailpoet' ) }
|
||||
</Button>
|
||||
<Button variant="primary" onClick={ trashCallback }>
|
||||
{ __( 'Move to trash', 'mailpoet' ) }
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default TrashModal;
|
Reference in New Issue
Block a user