Add code to create segment from template

[MAILPOET-5394]
This commit is contained in:
Rodrigo Primo
2023-09-05 13:53:42 -03:00
committed by Aschepikov
parent 41bed445e7
commit dba4ba4dfc
8 changed files with 116 additions and 11 deletions

View File

@ -59,15 +59,30 @@
.mailpoet-templates-card {
align-items: flex-end;
border: 1px solid white;
cursor: pointer;
display: flex;
flex-direction: column;
flex-shrink: 0;
width: 336px;
width: 334px;
> div {
display: grid;
grid-template-rows: auto 1fr;
}
&:hover {
background: #fff;
border: 1px solid #dcdcde;
box-shadow: 0 3px 6px rgba(0, 0, 0, .15);
color: inherit;
}
&:focus {
border-color: #2271b1;
box-shadow: 0 3px 6px rgba(0, 0, 0, .15);
color: inherit;
}
}
.mailpoet-templates-card-header {
@ -83,7 +98,7 @@
justify-content: center;
position: absolute;
right: 24px;
top: 0;
top: -1px;
width: 24px;
svg {
@ -91,7 +106,7 @@
}
}
a.is-link {
button.is-link {
font-size: 14px;
font-style: normal;
font-weight: 600;

View File

@ -13,11 +13,15 @@ import { storeName } from './store';
export function Editor(): JSX.Element {
const match = useRouteMatch<{ id: string }>();
const { pageLoaded } = useDispatch(storeName);
const { pageLoaded, pageUnloaded } = useDispatch(storeName);
useEffect(() => {
void pageLoaded(match.params.id);
}, [match.params.id, pageLoaded]);
return () => {
void pageUnloaded();
};
}, [match.params.id, pageLoaded, pageUnloaded]);
return (
<>

View File

@ -2,8 +2,10 @@ import { ChangeEvent } from 'react';
import { select } from '@wordpress/data';
import { MailPoet } from 'mailpoet';
import * as ROUTES from '../../routes';
import {
Actions,
ActionType,
AnyFormItem,
SetSegmentActionType,
SetErrorsActionType,
@ -21,6 +23,12 @@ export function setSegment(segment: AnyFormItem): SetSegmentActionType {
};
}
function unsetSegment(): ActionType {
return {
type: Actions.UNSET_SEGMENT,
};
}
export function setErrors(errors: string[]): SetErrorsActionType {
return {
type: Actions.SET_ERRORS,
@ -103,6 +111,10 @@ export function* pageLoaded(segmentId?: number | string): Generator<{
MailPoet.Modal.loading(false);
}
export function* pageUnloaded() {
yield unsetSegment();
}
const messages = {
onUpdate: (): void => {
MailPoet.Notice.success(MailPoet.I18n.t('dynamicSegmentUpdated'));
@ -141,3 +153,26 @@ export function* handleSave(segmentId?: number): Generator<{
yield setErrors(error as string[]);
}
}
export function* createFromTemplate(): Generator<{
type: string;
segment?: AnyFormItem;
}> {
MailPoet.Modal.loading(true);
const segment = select(storeName).getSegment();
yield setErrors([]);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore -- I don't know how to configure typescript to understand this
const { error, success } = yield {
type: 'SAVE_SEGMENT',
segment,
};
if (success) {
window.location.href = `admin.php?page=mailpoet-segments#${ROUTES.EDIT_DYNAMIC_SEGMENT}/${segment.id}`;
} else {
yield setErrors(error as string[]);
}
MailPoet.Modal.loading(false);
}

View File

@ -55,12 +55,13 @@ export async function SAVE_SEGMENT(actionData): Promise<{
}> {
const segment: AnyFormItem = actionData.segment;
try {
await MailPoet.Ajax.post({
const response = await MailPoet.Ajax.post({
api_version: MailPoet.apiVersion,
endpoint: 'dynamic_segments',
action: 'save',
data: segment,
});
segment.id = response.data.id;
return {
success: true,
};

View File

@ -16,6 +16,13 @@ function setSegment(state: StateType, action: SetSegmentActionType): StateType {
};
}
function unsetSegment(state: StateType): StateType {
return {
...state,
segment: { filters: [] },
};
}
function setErrors(state: StateType, action: SetErrorsActionType): StateType {
return {
...state,
@ -69,6 +76,8 @@ export const createReducer =
switch (action.type) {
case Actions.SET_SEGMENT:
return setSegment(state, action as SetSegmentActionType);
case Actions.UNSET_SEGMENT:
return unsetSegment(state);
case Actions.SET_ERRORS:
return setErrors(state, action as SetErrorsActionType);
case Actions.UPDATE_SEGMENT:

View File

@ -9,8 +9,10 @@ import {
import { __ } from '@wordpress/i18n';
import { starFilled } from '@wordpress/icons';
import { Tag } from '@woocommerce/components';
import { SegmentTemplate } from 'segments/types';
import { Segment, SegmentTemplate } from 'segments/types';
import { getCategoryNameBySlug } from 'segments/dynamic/templates/templates';
import { useDispatch, useSelect } from '@wordpress/data';
import { storeName } from 'segments/dynamic/store';
type TemplateListItemProps = {
template: SegmentTemplate;
@ -19,8 +21,36 @@ type TemplateListItemProps = {
export function TemplateListItem({
template,
}: TemplateListItemProps): JSX.Element {
const segment: Segment = useSelect(
(select) => select(storeName).getSegment(),
[],
);
const { updateSegment, createFromTemplate } = useDispatch(storeName);
function handleSelectTemplate(segmentTemplate: SegmentTemplate): void {
segment.name = segmentTemplate.name;
segment.description = segmentTemplate.description;
segment.filters = segmentTemplate.filters;
if (segmentTemplate.filtersConnect) {
segment.filters_connect = segmentTemplate.filtersConnect;
}
updateSegment({
...segment,
});
createFromTemplate();
}
return (
<Card className="mailpoet-templates-card">
<Card
className="mailpoet-templates-card"
onClick={(e): void => {
e.preventDefault();
handleSelectTemplate(template);
}}
>
<CardHeader className="mailpoet-templates-card-header">
{template.isEssential && (
<Tooltip text={__('Essential segment', 'mailpoet')}>
@ -29,9 +59,7 @@ export function TemplateListItem({
</div>
</Tooltip>
)}
<Button variant="link" href="#/">
{template.name}
</Button>
<Button variant="link">{template.name}</Button>
</CardHeader>
<CardBody className="mailpoet-templates-card-body">
<p>{template.description}</p>

View File

@ -17,6 +17,9 @@ import {
templateCategories,
} from 'segments/dynamic/templates/templates';
import * as ROUTES from 'segments/routes';
import { useSelect } from '@wordpress/data';
import { storeName } from 'segments/dynamic/store';
import { APIErrorsNotice } from 'notices/api_errors_notice';
const tabs = [
{
@ -47,6 +50,11 @@ templateCategories.forEach((category) => {
});
export function SegmentTemplates(): JSX.Element {
const errors: string[] = useSelect(
(select) => select(storeName).getErrors(),
[],
);
return (
<div className="mailpoet-templates-container">
<HideScreenOptions />
@ -79,6 +87,10 @@ export function SegmentTemplates(): JSX.Element {
</FlexItem>
</Flex>
{errors.length > 0 && (
<APIErrorsNotice errors={errors.map((error) => ({ message: error }))} />
)}
<TabPanel tabs={tabs}>
{(tab) => (
<div className="mailpoet-templates-card-grid">

View File

@ -302,6 +302,7 @@ export interface StateType {
export enum Actions {
SET_SEGMENT = 'SET_SEGMENT',
SET_ERRORS = 'SET_ERRORS',
UNSET_SEGMENT = 'UNSET_SEGMENT',
UPDATE_SEGMENT = 'UPDATE_SEGMENT',
UPDATE_SEGMENT_FILTER = 'UPDATE_SEGMENT_FILTER',
UPDATE_SUBSCRIBER_COUNT = 'UPDATE_SUBSCRIBER_COUNT',