Fix code style by updated eslint
[MAILPOET-3511]
This commit is contained in:
@ -31,6 +31,7 @@
|
||||
// PropTypes
|
||||
"react/prop-types": 0,
|
||||
"react/jsx-props-no-spreading": 0,
|
||||
"react/require-default-props": 0,
|
||||
// Hooks
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react-hooks/exhaustive-deps": "warn",
|
||||
@ -255,4 +256,3 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
/* eslint-disable react/no-unused-prop-types */
|
||||
interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
children?: React.ReactNode;
|
||||
dimension?: 'extra-small' | 'small' | 'large';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
export default async function ({ endpoint, action, data }) {
|
||||
export default async function callApi({ endpoint, action, data }) {
|
||||
try {
|
||||
const res = await MailPoet.Ajax.post({
|
||||
api_version: MailPoet.apiVersion,
|
||||
|
@ -2,7 +2,7 @@ import MailPoet from 'mailpoet';
|
||||
|
||||
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
export default async function ({ name, data, timeout = 0 }) {
|
||||
export default async function trackEvent({ name, data, timeout = 0 }) {
|
||||
MailPoet.trackEvent(name, data);
|
||||
return sleep(timeout);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
/* eslint-disable react/no-unused-prop-types */
|
||||
type Props = {
|
||||
title?: string;
|
||||
iconStart?: JSX.Element;
|
||||
|
@ -5,5 +5,6 @@ export default function useSegmentsContext(data) {
|
||||
all: data.mailpoetSegments,
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
updateAll: (segments) => { data.mailpoetSegments = segments; },
|
||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||
}), [data.mailpoetSegments]);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ FormFieldCheckbox.propTypes = {
|
||||
onValueChange: PropTypes.func.isRequired,
|
||||
field: PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
values: PropTypes.object.isRequired,
|
||||
values: PropTypes.objectOf(PropTypes.string),
|
||||
}).isRequired,
|
||||
item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
};
|
||||
|
@ -191,13 +191,13 @@ FormField.propTypes = {
|
||||
onValueChange: PropTypes.func,
|
||||
field: PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
values: PropTypes.object,
|
||||
values: PropTypes.objectOf(PropTypes.string),
|
||||
tip: PropTypes.oneOfType([
|
||||
PropTypes.array,
|
||||
PropTypes.string,
|
||||
]),
|
||||
label: PropTypes.string,
|
||||
fields: PropTypes.array,
|
||||
fields: PropTypes.arrayOf(PropTypes.object),
|
||||
description: PropTypes.string,
|
||||
}).isRequired,
|
||||
item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
|
@ -43,7 +43,7 @@ FormFieldRadio.propTypes = {
|
||||
onValueChange: PropTypes.func,
|
||||
field: PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
values: PropTypes.object,
|
||||
values: PropTypes.objectOf(PropTypes.string),
|
||||
}).isRequired,
|
||||
item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
};
|
||||
@ -54,5 +54,4 @@ FormFieldRadio.defaultProps = {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
export default FormFieldRadio;
|
||||
|
@ -78,11 +78,17 @@ FormFieldSelect.propTypes = {
|
||||
onValueChange: PropTypes.func,
|
||||
field: PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
values: PropTypes.object,
|
||||
values: PropTypes.objectOf(PropTypes.string),
|
||||
placeholder: PropTypes.string,
|
||||
filter: PropTypes.func,
|
||||
sortBy: PropTypes.func,
|
||||
validation: PropTypes.object,
|
||||
validation: PropTypes.shape({
|
||||
'data-parsley-required': PropTypes.bool,
|
||||
'data-parsley-required-message': PropTypes.string,
|
||||
'data-parsley-type': PropTypes.string,
|
||||
'data-parsley-errors-container': PropTypes.string,
|
||||
maxLength: PropTypes.number,
|
||||
}),
|
||||
}).isRequired,
|
||||
item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
automationId: PropTypes.string,
|
||||
@ -95,5 +101,4 @@ FormFieldSelect.defaultProps = {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
export default FormFieldSelect;
|
||||
|
@ -346,13 +346,19 @@ Selection.propTypes = {
|
||||
getCount: PropTypes.func,
|
||||
getTag: PropTypes.func,
|
||||
placeholder: PropTypes.string,
|
||||
remoteQuery: PropTypes.object,
|
||||
extendSelect2Options: PropTypes.object,
|
||||
remoteQuery: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
extendSelect2Options: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
multiple: PropTypes.bool,
|
||||
forceSelect2: PropTypes.bool,
|
||||
transformChangedValue: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
validation: PropTypes.object,
|
||||
validation: PropTypes.shape({
|
||||
'data-parsley-required': PropTypes.bool,
|
||||
'data-parsley-required-message': PropTypes.string,
|
||||
'data-parsley-type': PropTypes.string,
|
||||
'data-parsley-errors-container': PropTypes.string,
|
||||
maxLength: PropTypes.number,
|
||||
}),
|
||||
}).isRequired,
|
||||
item: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
disabled: PropTypes.bool,
|
||||
@ -368,5 +374,4 @@ Selection.defaultProps = {
|
||||
item: undefined,
|
||||
};
|
||||
|
||||
|
||||
export default Selection;
|
||||
|
@ -71,7 +71,13 @@ FormFieldText.propTypes = {
|
||||
]),
|
||||
disabled: PropTypes.func,
|
||||
placeholder: PropTypes.string,
|
||||
validation: PropTypes.object,
|
||||
validation: PropTypes.shape({
|
||||
'data-parsley-required': PropTypes.bool,
|
||||
'data-parsley-required-message': PropTypes.string,
|
||||
'data-parsley-type': PropTypes.string,
|
||||
'data-parsley-errors-container': PropTypes.string,
|
||||
maxLength: PropTypes.number,
|
||||
}),
|
||||
customLabel: PropTypes.string,
|
||||
tooltip: PropTypes.string,
|
||||
}).isRequired,
|
||||
|
@ -24,7 +24,13 @@ FormFieldTextarea.propTypes = {
|
||||
name: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
defaultValue: PropTypes.string,
|
||||
validation: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
validation: PropTypes.shape({
|
||||
'data-parsley-required': PropTypes.bool,
|
||||
'data-parsley-required-message': PropTypes.string,
|
||||
'data-parsley-type': PropTypes.string,
|
||||
'data-parsley-errors-container': PropTypes.string,
|
||||
maxLength: PropTypes.number,
|
||||
}),
|
||||
className: PropTypes.string,
|
||||
customLabel: PropTypes.string,
|
||||
tooltip: PropTypes.string,
|
||||
|
@ -11,7 +11,6 @@ import MailPoet from 'mailpoet';
|
||||
import icon from './icon.jsx';
|
||||
import AddCustomFieldForm from './add_custom_field_form.jsx';
|
||||
|
||||
|
||||
const AddCustomField = ({ clientId }) => {
|
||||
const { createCustomField } = useDispatch('mailpoet-form-editor');
|
||||
|
||||
|
@ -105,7 +105,6 @@ const CustomCheckboxEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
return attributes.label;
|
||||
};
|
||||
|
||||
|
||||
let checkboxLabel = getCheckboxLabel();
|
||||
if (attributes.mandatory) {
|
||||
checkboxLabel += ' *';
|
||||
|
@ -46,6 +46,7 @@ const CustomHtmlEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
[]
|
||||
);
|
||||
const [renderedContent, setRenderedContent] = useState(attributes.content);
|
||||
/* eslint-disable-next-line react-hooks/exhaustive-deps -- because we use external function */
|
||||
const setRenderedContentDebounced = useCallback(debounce((content) => {
|
||||
setRenderedContent(content);
|
||||
}, 300), []);
|
||||
|
@ -63,7 +63,6 @@ const Preview = ({
|
||||
updateSegment(segment);
|
||||
};
|
||||
|
||||
|
||||
const onDragEnd = (result) => {
|
||||
const from = result.source.index;
|
||||
const to = result.destination.index;
|
||||
|
@ -33,7 +33,6 @@ export const Settings: React.FunctionComponent = () => (
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
export const SettingsInSidebar: React.FunctionComponent = () => (
|
||||
<div className="edit-post-sidebar mailpoet_form_editor_sidebar">
|
||||
<SizeSettings
|
||||
|
@ -25,7 +25,6 @@ const CustomCssPanel = ({ onToggle, isOpened }) => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
CustomCssPanel.propTypes = {
|
||||
onToggle: PropTypes.func.isRequired,
|
||||
isOpened: PropTypes.bool.isRequired,
|
||||
|
@ -321,13 +321,19 @@ Selection.propTypes = {
|
||||
getSearchLabel: PropTypes.func,
|
||||
getValue: PropTypes.func,
|
||||
placeholder: PropTypes.string,
|
||||
remoteQuery: PropTypes.object,
|
||||
extendSelect2Options: PropTypes.object,
|
||||
remoteQuery: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
extendSelect2Options: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
multiple: PropTypes.bool,
|
||||
forceSelect2: PropTypes.bool,
|
||||
transformChangedValue: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
validation: PropTypes.object,
|
||||
validation: PropTypes.shape({
|
||||
'data-parsley-required': PropTypes.bool,
|
||||
'data-parsley-required-message': PropTypes.string,
|
||||
'data-parsley-type': PropTypes.string,
|
||||
'data-parsley-errors-container': PropTypes.string,
|
||||
maxLength: PropTypes.number,
|
||||
}),
|
||||
}).isRequired,
|
||||
item: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
disabled: PropTypes.bool,
|
||||
@ -345,5 +351,4 @@ Selection.defaultProps = {
|
||||
dropDownParent: undefined,
|
||||
};
|
||||
|
||||
|
||||
export default Selection;
|
||||
|
@ -11,7 +11,6 @@ import Preview from 'common/preview/preview.jsx';
|
||||
import Modal from 'common/modal/modal';
|
||||
import PlacementSettingsPanel from 'form_editor/components/form_settings/form_placement_options/settings_panel';
|
||||
|
||||
|
||||
const FormPreview: React.FunctionComponent = () => {
|
||||
const iframeElement = useRef(null);
|
||||
const [iframeLoaded, setIframeLoaded] = useState(false);
|
||||
|
@ -2,6 +2,6 @@ import '@wordpress/format-library'; // load default formats (bold, italic, ...)
|
||||
import { registerFormatType } from '@wordpress/rich-text';
|
||||
import * as FontSelectionFormat from './font_selection_format';
|
||||
|
||||
export default function (): void {
|
||||
export default function Init(): void {
|
||||
registerFormatType(FontSelectionFormat.name, FontSelectionFormat.settings);
|
||||
}
|
||||
|
@ -109,7 +109,6 @@ const historyMove = (state, increment: number) => {
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export const historyUndo = (state) => (historyMove(state, 1));
|
||||
|
||||
export const historyRedo = (state) => (historyMove(state, -1));
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
function asNum(num?: string): number | undefined {
|
||||
const numI = parseInt(num, 10);
|
||||
if (Number.isNaN(numI)) {
|
||||
|
@ -93,7 +93,6 @@ Handlebars.registerHelper('lookup', function lookupHelper(obj, field) {
|
||||
return obj && obj[field];
|
||||
});
|
||||
|
||||
|
||||
Handlebars.registerHelper('rsa_key', function rsaKeyHelper(value) {
|
||||
var lines;
|
||||
// extract all lines into an array
|
||||
|
@ -11,18 +11,6 @@ class ListingBulkActions extends React.Component {
|
||||
this.handleApplyAction = this.handleApplyAction.bind(this);
|
||||
}
|
||||
|
||||
getSelectedAction(actionName) {
|
||||
const selectedAction = actionName;
|
||||
if (selectedAction.length > 0) {
|
||||
const action = this.props.bulk_actions.filter((act) => (act.name === selectedAction));
|
||||
|
||||
if (action.length > 0) {
|
||||
return action[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
handleApplyAction(actionName) {
|
||||
const action = this.getSelectedAction(actionName);
|
||||
|
||||
@ -67,6 +55,18 @@ class ListingBulkActions extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
getSelectedAction(actionName) {
|
||||
const selectedAction = actionName;
|
||||
if (selectedAction.length > 0) {
|
||||
const action = this.props.bulk_actions.filter((act) => (act.name === selectedAction));
|
||||
|
||||
if (action.length > 0) {
|
||||
return action[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.bulk_actions.length === 0) {
|
||||
return null;
|
||||
|
@ -42,17 +42,17 @@ class ListingSearch extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
onChange(e) {
|
||||
this.setState({ search: e.target.value });
|
||||
this.debouncedHandleSearch();
|
||||
}
|
||||
|
||||
handleSearch() {
|
||||
this.props.onSearch(
|
||||
this.state.search.trim()
|
||||
);
|
||||
}
|
||||
|
||||
onChange(e) {
|
||||
this.setState({ search: e.target.value });
|
||||
this.debouncedHandleSearch();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.search === false) {
|
||||
return false;
|
||||
|
@ -59,7 +59,6 @@ const Log: React.FunctionComponent<LogProps> = ({ log }: LogProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export type FilterType = {
|
||||
from?: string;
|
||||
to?: string;
|
||||
|
@ -81,7 +81,6 @@ BL.DraggableBehavior = Marionette.Behavior.extend({
|
||||
|
||||
event.interaction.element = clone;
|
||||
|
||||
|
||||
if (that.options.hideOriginal === true) {
|
||||
that.view.$el.addClass('mailpoet_hidden');
|
||||
}
|
||||
|
@ -105,5 +105,4 @@ App.on('before:start', function beforeAppStart(BeforeStartApp) {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
export default Module;
|
||||
|
@ -113,5 +113,4 @@ App.on('start', function appOnStart(Application, options) {
|
||||
}, this);
|
||||
});
|
||||
|
||||
|
||||
export default Module;
|
||||
|
@ -95,10 +95,4 @@ export const EventOptions = ({
|
||||
);
|
||||
};
|
||||
|
||||
EventOptions.defaultProps = {
|
||||
eventOptions: null,
|
||||
selected: [],
|
||||
onValueChange: null,
|
||||
};
|
||||
|
||||
export default EventOptions;
|
||||
|
@ -33,34 +33,25 @@ class EventScheduling extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
displayAfterTimeNumberField() {
|
||||
const { afterTimeNumberSize, event } = this.props;
|
||||
const { afterTimeType, afterTimeNumber } = this.state;
|
||||
if (afterTimeType === 'immediate') return null;
|
||||
if (
|
||||
event.timeDelayValues
|
||||
&& event.timeDelayValues[afterTimeType]
|
||||
&& !event.timeDelayValues[afterTimeType].displayAfterTimeNumberField
|
||||
) return null;
|
||||
handleChange(e, property) {
|
||||
let { value } = e.target;
|
||||
if (property === 'afterTimeNumber') {
|
||||
value = parseInt(e.target.value, 10);
|
||||
value = Number.isNaN(value) ? null : value;
|
||||
}
|
||||
const data = { [property]: value };
|
||||
|
||||
const props = {
|
||||
field: {
|
||||
id: 'scheduling_time_duration',
|
||||
name: 'scheduling_time_duration',
|
||||
defaultValue: afterTimeNumber ? afterTimeNumber.toString() : '',
|
||||
size: afterTimeNumberSize,
|
||||
},
|
||||
item: {},
|
||||
onValueChange: _.partial(this.handleChange, _, 'afterTimeNumber'),
|
||||
};
|
||||
|
||||
return (
|
||||
<Text
|
||||
field={props.field}
|
||||
item={props.item}
|
||||
onValueChange={props.onValueChange}
|
||||
/>
|
||||
);
|
||||
// Reset afterTimeNumber to default when switching between minutes and other types
|
||||
const { afterTimeType } = this.state;
|
||||
if (property === 'afterTimeType' && afterTimeType !== value) {
|
||||
if (afterTimeType === 'minutes') {
|
||||
data.afterTimeNumber = defaultAfterTimeNumber;
|
||||
}
|
||||
if (value === 'minutes') {
|
||||
data.afterTimeNumber = defaultAfterTimeNumberForMinutes;
|
||||
}
|
||||
}
|
||||
this.setState(data, this.propagateChange(data));
|
||||
}
|
||||
|
||||
displayAfterTimeTypeOptions() {
|
||||
@ -97,25 +88,34 @@ class EventScheduling extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
handleChange(e, property) {
|
||||
let { value } = e.target;
|
||||
if (property === 'afterTimeNumber') {
|
||||
value = parseInt(e.target.value, 10);
|
||||
value = Number.isNaN(value) ? null : value;
|
||||
}
|
||||
const data = { [property]: value };
|
||||
displayAfterTimeNumberField() {
|
||||
const { afterTimeNumberSize, event } = this.props;
|
||||
const { afterTimeType, afterTimeNumber } = this.state;
|
||||
if (afterTimeType === 'immediate') return null;
|
||||
if (
|
||||
event.timeDelayValues
|
||||
&& event.timeDelayValues[afterTimeType]
|
||||
&& !event.timeDelayValues[afterTimeType].displayAfterTimeNumberField
|
||||
) return null;
|
||||
|
||||
// Reset afterTimeNumber to default when switching between minutes and other types
|
||||
const { afterTimeType } = this.state;
|
||||
if (property === 'afterTimeType' && afterTimeType !== value) {
|
||||
if (afterTimeType === 'minutes') {
|
||||
data.afterTimeNumber = defaultAfterTimeNumber;
|
||||
}
|
||||
if (value === 'minutes') {
|
||||
data.afterTimeNumber = defaultAfterTimeNumberForMinutes;
|
||||
}
|
||||
}
|
||||
this.setState(data, this.propagateChange(data));
|
||||
const props = {
|
||||
field: {
|
||||
id: 'scheduling_time_duration',
|
||||
name: 'scheduling_time_duration',
|
||||
defaultValue: afterTimeNumber ? afterTimeNumber.toString() : '',
|
||||
size: afterTimeNumberSize,
|
||||
},
|
||||
item: {},
|
||||
onValueChange: _.partial(this.handleChange, _, 'afterTimeNumber'),
|
||||
};
|
||||
|
||||
return (
|
||||
<Text
|
||||
field={props.field}
|
||||
item={props.item}
|
||||
onValueChange={props.onValueChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
propagateChange(data) {
|
||||
|
@ -50,6 +50,78 @@ class EventsConditions extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
handleChange(data) {
|
||||
const { segment, afterTimeNumber } = this.state;
|
||||
const newState = data;
|
||||
|
||||
if (newState.eventSlug) {
|
||||
newState.event = this.getEvent(newState.eventSlug);
|
||||
|
||||
// keep the existing segment (if set) or set it to the first segment in the list
|
||||
newState.segment = (newState.event.sendToLists)
|
||||
? segment || this.constructor.getFirstSegment() : null;
|
||||
|
||||
// if the new event doesn't have options, reset the currently selected option value
|
||||
const eventOptions = this.constructor.getEventOptions(newState.event);
|
||||
newState.eventOptionValue = (eventOptions)
|
||||
? this.constructor.getEventOptionsFirstValue(eventOptions) : null;
|
||||
}
|
||||
|
||||
if (newState.afterTimeType && newState.afterTimeType === 'immediate') {
|
||||
newState.afterTimeNumber = null;
|
||||
} else if (newState.afterTimeType && !newState.afterTimeNumber && !afterTimeNumber) {
|
||||
newState.afterTimeNumber = defaultAfterTimeNumber;
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
handleNextStep() {
|
||||
const { history } = this.props;
|
||||
const {
|
||||
eventSlug, afterTimeType, afterTimeNumber, event, segment, eventOptionValue,
|
||||
} = this.state;
|
||||
const options = {
|
||||
group: this.email.slug,
|
||||
event: eventSlug,
|
||||
afterTimeType,
|
||||
};
|
||||
|
||||
if (afterTimeNumber) options.afterTimeNumber = afterTimeNumber;
|
||||
options.sendTo = (event.sendToLists) ? 'segment' : 'user';
|
||||
if (segment) options.segment = segment;
|
||||
if (eventOptionValue) {
|
||||
options.meta = JSON.stringify({ option: eventOptionValue });
|
||||
}
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'newsletters',
|
||||
action: 'create',
|
||||
data: {
|
||||
type: 'automatic',
|
||||
subject: MailPoet.I18n.t('draftNewsletterTitle'),
|
||||
options,
|
||||
},
|
||||
}).done((response) => {
|
||||
MailPoet.trackEvent('Emails > New Automatic Email Created', {
|
||||
'MailPoet Premium version': window.mailpoet_premium_version,
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
'Event type': options.event,
|
||||
'Schedule type': options.afterTimeType,
|
||||
'Schedule value': options.afterTimeNumber,
|
||||
});
|
||||
history.push(`/template/${response.data.id}`);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getEvent(eventSlug) {
|
||||
return this.emailEvents[eventSlug];
|
||||
}
|
||||
@ -140,78 +212,6 @@ class EventsConditions extends React.Component {
|
||||
) : null;
|
||||
}
|
||||
|
||||
handleChange(data) {
|
||||
const { segment, afterTimeNumber } = this.state;
|
||||
const newState = data;
|
||||
|
||||
if (newState.eventSlug) {
|
||||
newState.event = this.getEvent(newState.eventSlug);
|
||||
|
||||
// keep the existing segment (if set) or set it to the first segment in the list
|
||||
newState.segment = (newState.event.sendToLists)
|
||||
? segment || this.constructor.getFirstSegment() : null;
|
||||
|
||||
// if the new event doesn't have options, reset the currently selected option value
|
||||
const eventOptions = this.constructor.getEventOptions(newState.event);
|
||||
newState.eventOptionValue = (eventOptions)
|
||||
? this.constructor.getEventOptionsFirstValue(eventOptions) : null;
|
||||
}
|
||||
|
||||
if (newState.afterTimeType && newState.afterTimeType === 'immediate') {
|
||||
newState.afterTimeNumber = null;
|
||||
} else if (newState.afterTimeType && !newState.afterTimeNumber && !afterTimeNumber) {
|
||||
newState.afterTimeNumber = defaultAfterTimeNumber;
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
handleNextStep() {
|
||||
const { history } = this.props;
|
||||
const {
|
||||
eventSlug, afterTimeType, afterTimeNumber, event, segment, eventOptionValue,
|
||||
} = this.state;
|
||||
const options = {
|
||||
group: this.email.slug,
|
||||
event: eventSlug,
|
||||
afterTimeType,
|
||||
};
|
||||
|
||||
if (afterTimeNumber) options.afterTimeNumber = afterTimeNumber;
|
||||
options.sendTo = (event.sendToLists) ? 'segment' : 'user';
|
||||
if (segment) options.segment = segment;
|
||||
if (eventOptionValue) {
|
||||
options.meta = JSON.stringify({ option: eventOptionValue });
|
||||
}
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'newsletters',
|
||||
action: 'create',
|
||||
data: {
|
||||
type: 'automatic',
|
||||
subject: MailPoet.I18n.t('draftNewsletterTitle'),
|
||||
options,
|
||||
},
|
||||
}).done((response) => {
|
||||
MailPoet.trackEvent('Emails > New Automatic Email Created', {
|
||||
'MailPoet Premium version': window.mailpoet_premium_version,
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
'Event type': options.event,
|
||||
'Schedule type': options.afterTimeType,
|
||||
'Schedule value': options.afterTimeNumber,
|
||||
});
|
||||
history.push(`/template/${response.data.id}`);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
|
@ -34,9 +34,64 @@ class SendEventConditions extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
displayHeader() {
|
||||
const { event } = this.state;
|
||||
return event.title;
|
||||
handleChange(data) {
|
||||
const { afterTimeNumber } = this.state;
|
||||
const newState = data;
|
||||
|
||||
if (newState.afterTimeType && newState.afterTimeType === 'immediate') {
|
||||
newState.afterTimeNumber = null;
|
||||
} else if (newState.afterTimeType && !newState.afterTimeNumber && !afterTimeNumber) {
|
||||
newState.afterTimeNumber = defaultAfterTimeNumber;
|
||||
}
|
||||
|
||||
this.setState(data, this.propagateChange);
|
||||
}
|
||||
|
||||
displayScheduling() {
|
||||
const { afterTimeNumber, afterTimeType, event } = this.state;
|
||||
const props = {
|
||||
item: {
|
||||
afterTimeNumber,
|
||||
afterTimeType,
|
||||
},
|
||||
event,
|
||||
onValueChange: this.handleChange,
|
||||
};
|
||||
|
||||
return (
|
||||
<EventScheduling
|
||||
item={props.item}
|
||||
event={props.event}
|
||||
onValueChange={props.onValueChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
displaySegments() {
|
||||
const { segment } = this.state;
|
||||
if (this.emailOptions.sendTo === 'user') return null;
|
||||
|
||||
const props = {
|
||||
field: {
|
||||
id: 'segments',
|
||||
forceSelect2: true,
|
||||
values: this.segments,
|
||||
extendSelect2Options: {
|
||||
minimumResultsForSearch: Infinity,
|
||||
},
|
||||
selected: () => segment,
|
||||
},
|
||||
onValueChange: (e) => this.handleChange({ segment: e.target.value }),
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="event-segment-selection">
|
||||
<Selection
|
||||
field={props.field}
|
||||
onValueChange={props.onValueChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
displayEventOptions() {
|
||||
@ -75,64 +130,9 @@ class SendEventConditions extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
displaySegments() {
|
||||
const { segment } = this.state;
|
||||
if (this.emailOptions.sendTo === 'user') return null;
|
||||
|
||||
const props = {
|
||||
field: {
|
||||
id: 'segments',
|
||||
forceSelect2: true,
|
||||
values: this.segments,
|
||||
extendSelect2Options: {
|
||||
minimumResultsForSearch: Infinity,
|
||||
},
|
||||
selected: () => segment,
|
||||
},
|
||||
onValueChange: (e) => this.handleChange({ segment: e.target.value }),
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="event-segment-selection">
|
||||
<Selection
|
||||
field={props.field}
|
||||
onValueChange={props.onValueChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
displayScheduling() {
|
||||
const { afterTimeNumber, afterTimeType, event } = this.state;
|
||||
const props = {
|
||||
item: {
|
||||
afterTimeNumber,
|
||||
afterTimeType,
|
||||
},
|
||||
event,
|
||||
onValueChange: this.handleChange,
|
||||
};
|
||||
|
||||
return (
|
||||
<EventScheduling
|
||||
item={props.item}
|
||||
event={props.event}
|
||||
onValueChange={props.onValueChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
handleChange(data) {
|
||||
const { afterTimeNumber } = this.state;
|
||||
const newState = data;
|
||||
|
||||
if (newState.afterTimeType && newState.afterTimeType === 'immediate') {
|
||||
newState.afterTimeNumber = null;
|
||||
} else if (newState.afterTimeType && !newState.afterTimeNumber && !afterTimeNumber) {
|
||||
newState.afterTimeNumber = defaultAfterTimeNumber;
|
||||
}
|
||||
|
||||
this.setState(data, this.propagateChange);
|
||||
displayHeader() {
|
||||
const { event } = this.state;
|
||||
return event.title;
|
||||
}
|
||||
|
||||
propagateChange() {
|
||||
|
@ -274,7 +274,6 @@ class NewsletterListNotification extends React.Component {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<span>
|
||||
{ sendingToSegments }
|
||||
|
@ -201,7 +201,9 @@ NewsletterListNotificationHistory.propTypes = {
|
||||
pathname: PropTypes.string,
|
||||
}).isRequired,
|
||||
match: PropTypes.shape({
|
||||
params: PropTypes.object,
|
||||
params: PropTypes.shape({
|
||||
id: PropTypes.node,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
|
@ -16,6 +16,8 @@ const QueuePropType = PropTypes.shape({
|
||||
|
||||
const NewsletterPropType = PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
sent_at: PropTypes.string,
|
||||
status: PropTypes.string.isRequired,
|
||||
queue: PropTypes.oneOfType([
|
||||
QueuePropType,
|
||||
PropTypes.bool,
|
||||
|
@ -138,7 +138,13 @@ DateText.propTypes = {
|
||||
storageFormat: PropTypes.string.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
disabled: PropTypes.bool.isRequired,
|
||||
validation: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
validation: PropTypes.shape({
|
||||
'data-parsley-required': PropTypes.bool,
|
||||
'data-parsley-required-message': PropTypes.string,
|
||||
'data-parsley-type': PropTypes.string,
|
||||
'data-parsley-errors-container': PropTypes.string,
|
||||
maxLength: PropTypes.number,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
DateText.defaultProps = {
|
||||
|
@ -12,6 +12,31 @@ class ImportTemplate extends React.Component {
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (_.size(this.fileRef.current.files) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const file = _.first(this.fileRef.current.files);
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (evt) => {
|
||||
try {
|
||||
this.saveTemplate(JSON.parse(evt.target.result));
|
||||
MailPoet.trackEvent('Emails > Template imported', {
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
});
|
||||
} catch (err) {
|
||||
this.context.notices.error(<p>{MailPoet.I18n.t('templateFileMalformedError')}</p>);
|
||||
}
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
saveTemplate(saveTemplate) {
|
||||
const template = saveTemplate;
|
||||
const { beforeImport, afterImport } = this.props;
|
||||
@ -41,7 +66,6 @@ class ImportTemplate extends React.Component {
|
||||
|
||||
template.categories = JSON.stringify(template.categories);
|
||||
|
||||
|
||||
beforeImport();
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
@ -61,31 +85,6 @@ class ImportTemplate extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (_.size(this.fileRef.current.files) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const file = _.first(this.fileRef.current.files);
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (evt) => {
|
||||
try {
|
||||
this.saveTemplate(JSON.parse(evt.target.result));
|
||||
MailPoet.trackEvent('Emails > Template imported', {
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
});
|
||||
} catch (err) {
|
||||
this.context.notices.error(<p>{MailPoet.I18n.t('templateFileMalformedError')}</p>);
|
||||
}
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
|
@ -77,7 +77,6 @@ const NewsletterTypes: React.FunctionComponent<Props> = ({
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
const renderType = (type): JSX.Element => {
|
||||
const badgeClassName = (window.mailpoet_is_new_user === true) ? 'mailpoet_badge mailpoet_badge_video' : 'mailpoet_badge mailpoet_badge_video mailpoet_badge_video_grey';
|
||||
|
||||
|
@ -27,7 +27,6 @@ jQuery(($) => {
|
||||
setTimeout(renderCaptcha, 400, element, 1);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @param form jQuery object of form form.mailpoet_form
|
||||
*/
|
||||
|
@ -59,6 +59,45 @@ class DynamicSegmentForm extends React.Component {
|
||||
this.onItemLoad = this.onItemLoad.bind(this);
|
||||
}
|
||||
|
||||
handleValueChange(e) {
|
||||
const { item } = this.state;
|
||||
const field = e.target.name;
|
||||
|
||||
item[field] = e.target.value;
|
||||
|
||||
this.setState({
|
||||
item,
|
||||
});
|
||||
this.loadFields();
|
||||
return true;
|
||||
}
|
||||
|
||||
handleSave(e) {
|
||||
const { item } = this.state;
|
||||
const { history, match } = this.props;
|
||||
|
||||
e.preventDefault();
|
||||
this.setState({ errors: undefined });
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'dynamic_segments',
|
||||
action: 'save',
|
||||
data: item,
|
||||
}).done(() => {
|
||||
history.push('/segments');
|
||||
|
||||
if (match.params.id !== undefined) {
|
||||
messages.onUpdate();
|
||||
} else {
|
||||
messages.onCreate(item);
|
||||
}
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
this.setState({ errors: response.errors });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onItemLoad(loadedData) {
|
||||
const item = _.mapObject(loadedData, (val) => (_.isNull(val) ? '' : val));
|
||||
this.setState({ item }, this.loadFields);
|
||||
@ -165,45 +204,6 @@ class DynamicSegmentForm extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
handleValueChange(e) {
|
||||
const { item } = this.state;
|
||||
const field = e.target.name;
|
||||
|
||||
item[field] = e.target.value;
|
||||
|
||||
this.setState({
|
||||
item,
|
||||
});
|
||||
this.loadFields();
|
||||
return true;
|
||||
}
|
||||
|
||||
handleSave(e) {
|
||||
const { item } = this.state;
|
||||
const { history, match } = this.props;
|
||||
|
||||
e.preventDefault();
|
||||
this.setState({ errors: undefined });
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
endpoint: 'dynamic_segments',
|
||||
action: 'save',
|
||||
data: item,
|
||||
}).done(() => {
|
||||
history.push('/segments');
|
||||
|
||||
if (match.params.id !== undefined) {
|
||||
messages.onUpdate();
|
||||
} else {
|
||||
messages.onCreate(item);
|
||||
}
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
this.setState({ errors: response.errors });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const fields = this.getFields();
|
||||
const { match } = this.props;
|
||||
|
@ -30,7 +30,6 @@ const MssNotActiveMessage = ({ activationCallback }: MssNotActiveMessageProps) =
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
type Props = {
|
||||
keyMessage?: string;
|
||||
activationCallback: () => void;
|
||||
|
@ -33,7 +33,7 @@ const NotValidMessage = ({ message }: NotValidMessageProps) => (
|
||||
</div>
|
||||
);
|
||||
NotValidMessage.defaultProps = {
|
||||
keyMessage: '',
|
||||
message: '',
|
||||
};
|
||||
|
||||
type Props = {
|
||||
|
@ -15,5 +15,4 @@ export type Tail<T extends any[]> =
|
||||
export type ExcludeFirstParam<F extends ((...args: any[]) => any)> =
|
||||
(...args: Tail<Parameters<F>>) => ReturnType<F>
|
||||
|
||||
|
||||
export type ValueAndSetter<T> = [T, (value: T) => any]
|
||||
|
@ -1,7 +1,6 @@
|
||||
import jQuery from 'jquery';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
|
||||
export default (onCreateSegment) => {
|
||||
MailPoet.Modal.popup({
|
||||
title: MailPoet.I18n.t('addNewList'),
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
export default (subscribers, header) => {
|
||||
const displayedColumns = [];
|
||||
const displayedColumnsIds = [];
|
||||
|
@ -53,5 +53,4 @@ LastSentQuestion.propTypes = {
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
||||
export default LastSentQuestion;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
const notFreeAddress = ({ name, address }) => ({
|
||||
sender: { name, address },
|
||||
reply_to: { name, address },
|
||||
|
@ -24,7 +24,6 @@ export const Controls = (props) => (
|
||||
href={props.mailpoetAccountUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
window.open(props.mailpoetAccountUrl);
|
||||
|
@ -33,7 +33,6 @@ const data = {
|
||||
deleted_at: null,
|
||||
};
|
||||
|
||||
|
||||
describe('Form Data Load Mapper', () => {
|
||||
it('Returns ID', () => {
|
||||
expect(map(data)).to.have.property('id', '1');
|
||||
|
@ -33,7 +33,6 @@ const data = {
|
||||
deleted_at: null,
|
||||
};
|
||||
|
||||
|
||||
describe('Form Data Save Mapper', () => {
|
||||
it('Returns ID', () => {
|
||||
expect(map(data)).to.have.property('id', '1');
|
||||
@ -50,7 +49,7 @@ describe('Form Data Save Mapper', () => {
|
||||
it('Returns dates', () => {
|
||||
expect(map(data)).to.have.property('created_at', '2020-01-15 07:39:15');
|
||||
expect(map(data)).to.have.property('updated_at', '2020-01-28 10:28:02');
|
||||
expect(map(data)).to.have.property('deleted_at').that.is.null;
|
||||
expect(map(data)).to.have.property('deleted_at').that.is.null;// eslint-disable-line no-unused-expressions
|
||||
});
|
||||
|
||||
describe('Settings', () => {
|
||||
|
@ -33,7 +33,6 @@ global.$ = jQuery;
|
||||
global.jQuery = jQuery;
|
||||
global.window.jQuery = jQuery;
|
||||
|
||||
|
||||
testHelpers.loadScript('tests/javascript_newsletter_editor/testBundles/vendor.js', global.window);
|
||||
const Handlebars = global.window.Handlebars;
|
||||
global.Handlebars = global.window.Handlebars;
|
||||
@ -186,7 +185,6 @@ testHelpers.loadTemplate('components/sidebar/layout.hbs', window, { id: 'newslet
|
||||
testHelpers.loadTemplate('components/sidebar/preview.hbs', window, { id: 'newsletter_editor_template_sidebar_preview' });
|
||||
testHelpers.loadTemplate('components/sidebar/styles.hbs', window, { id: 'newsletter_editor_template_sidebar_styles' });
|
||||
|
||||
|
||||
global.templates = {
|
||||
styles: Handlebars.compile(jQuery('#newsletter_editor_template_styles').html()),
|
||||
save: Handlebars.compile(jQuery('#newsletter_editor_template_save').html()),
|
||||
|
Reference in New Issue
Block a user