Refactored scheduling options for React (semi-converted to ES6 too)

- fixed issue with Pausing sending (missing self::)
This commit is contained in:
Jonathan Labreuille
2016-06-17 13:05:46 +02:00
parent 90c3f0e4e4
commit 269ddae93a
6 changed files with 396 additions and 437 deletions

View File

@ -9,6 +9,13 @@ import classNames from 'classnames'
import jQuery from 'jquery' import jQuery from 'jquery'
import MailPoet from 'mailpoet' import MailPoet from 'mailpoet'
import {
timeOfDayValues,
weekDayValues,
monthDayValues,
nthWeekDayValues
} from 'newsletters/scheduling/common.jsx'
const messages = { const messages = {
onTrash(response) { onTrash(response) {
const count = ~~response; const count = ~~response;
@ -179,63 +186,6 @@ const NewsletterListNotification = React.createClass({
); );
}, },
renderSettings: function(newsletter) { renderSettings: function(newsletter) {
/// TO REFACTOR in order to avoid duplication with */scheduling.jsx
/// ========================================================================
const SECONDS_IN_DAY = 86400;
const TIME_STEP_SECONDS = 3600;
const numberOfTimeSteps = SECONDS_IN_DAY / TIME_STEP_SECONDS;
const timeOfDayValues = _.object(_.map(
_.times(numberOfTimeSteps,function(step) {
return step * TIME_STEP_SECONDS;
}), function(seconds) {
let date = new Date(null);
date.setSeconds(seconds);
const timeLabel = date.toISOString().substr(11, 5);
return [seconds, timeLabel];
})
);
const weekDayValues = {
0: MailPoet.I18n.t('sunday'),
1: MailPoet.I18n.t('monday'),
2: MailPoet.I18n.t('tuesday'),
3: MailPoet.I18n.t('wednesday'),
4: MailPoet.I18n.t('thursday'),
5: MailPoet.I18n.t('friday'),
6: MailPoet.I18n.t('saturday')
};
const NUMBER_OF_DAYS_IN_MONTH = 28;
const monthDayValues = _.object(
_.map(
_.times(NUMBER_OF_DAYS_IN_MONTH, function(day) {
return day;
}), function(day) {
const labels = {
0: MailPoet.I18n.t('first'),
1: MailPoet.I18n.t('second'),
2: MailPoet.I18n.t('third')
};
let label;
if (labels[day] !== undefined) {
label = labels[day];
} else {
label = MailPoet.I18n.t('nth').replace("%$1d", day + 1);
}
return [day, label];
}
)
);
const nthWeekDayValues = {
'1': MailPoet.I18n.t('first'),
'2': MailPoet.I18n.t('second'),
'3': MailPoet.I18n.t('third'),
'L': MailPoet.I18n.t('last')
};
/// ========================================================================
let sendingFrequency; let sendingFrequency;
let sendingToSegments; let sendingToSegments;

View File

@ -0,0 +1,80 @@
import _ from 'underscore'
import MailPoet from 'mailpoet'
// welcome emails
const _timeDelayValues = {
'immediate': MailPoet.I18n.t('delayImmediately'),
'hours': MailPoet.I18n.t('delayHoursAfter'),
'days': MailPoet.I18n.t('delayDaysAfter'),
'weeks': MailPoet.I18n.t('delayWeeksAfter'),
};
const _intervalValues = {
'daily': MailPoet.I18n.t('daily'),
'weekly': MailPoet.I18n.t('weekly'),
'monthly': MailPoet.I18n.t('monthly'),
'nthWeekDay': MailPoet.I18n.t('monthlyEvery'),
'immediately': MailPoet.I18n.t('immediately'),
};
// notification emails
const SECONDS_IN_DAY = 86400;
const TIME_STEP_SECONDS = 3600;
const numberOfTimeSteps = SECONDS_IN_DAY / TIME_STEP_SECONDS;
const _timeOfDayValues = _.object(_.map(
_.times(numberOfTimeSteps,function(step) {
return step * TIME_STEP_SECONDS;
}), function(seconds) {
let date = new Date(null);
date.setSeconds(seconds);
const timeLabel = date.toISOString().substr(11, 5);
return [seconds, timeLabel];
})
);
const _weekDayValues = {
0: MailPoet.I18n.t('sunday'),
1: MailPoet.I18n.t('monday'),
2: MailPoet.I18n.t('tuesday'),
3: MailPoet.I18n.t('wednesday'),
4: MailPoet.I18n.t('thursday'),
5: MailPoet.I18n.t('friday'),
6: MailPoet.I18n.t('saturday')
};
const NUMBER_OF_DAYS_IN_MONTH = 28;
const _monthDayValues = _.object(
_.map(
_.times(NUMBER_OF_DAYS_IN_MONTH, function(day) {
return day;
}), function(day) {
const labels = {
0: MailPoet.I18n.t('first'),
1: MailPoet.I18n.t('second'),
2: MailPoet.I18n.t('third')
};
let label;
if (labels[day] !== undefined) {
label = labels[day];
} else {
label = MailPoet.I18n.t('nth').replace("%$1d", day + 1);
}
return [day, label];
}
)
);
const _nthWeekDayValues = {
'1': MailPoet.I18n.t('first'),
'2': MailPoet.I18n.t('second'),
'3': MailPoet.I18n.t('third'),
'L': MailPoet.I18n.t('last')
};
export { _timeDelayValues as timeDelayValues };
export { _intervalValues as intervalValues };
export { _timeOfDayValues as timeOfDayValues };
export { _weekDayValues as weekDayValues };
export { _monthDayValues as monthDayValues };
export { _nthWeekDayValues as nthWeekDayValues };

View File

@ -18,7 +18,6 @@ define(
var field = { var field = {
name: 'options', name: 'options',
label: 'Periodicity',
type: 'reactComponent', type: 'reactComponent',
component: Scheduling, component: Scheduling,
}; };

View File

@ -1,200 +1,144 @@
define( import _ from 'underscore'
[ import React from 'react'
'underscore', import MailPoet from 'mailpoet'
'react', import Select from 'form/fields/select.jsx'
'react-router', import {
'mailpoet', intervalValues,
'form/fields/select.jsx' timeOfDayValues,
], weekDayValues,
function( monthDayValues,
_, nthWeekDayValues
React, } from 'newsletters/scheduling/common.jsx'
Router,
MailPoet,
Select
) {
var intervalField = { const intervalField = {
name: 'intervalType', name: 'intervalType',
values: { values: intervalValues
'daily': MailPoet.I18n.t('daily'), };
'weekly': MailPoet.I18n.t('weekly'),
'monthly': MailPoet.I18n.t('monthly'),
'nthWeekDay': MailPoet.I18n.t('monthlyEvery'),
'immediately': MailPoet.I18n.t('immediately'),
},
};
var SECONDS_IN_DAY = 86400; const timeOfDayField = {
var TIME_STEP_SECONDS = 3600; // Default: 3600 name: 'timeOfDay',
var numberOfTimeSteps = SECONDS_IN_DAY / TIME_STEP_SECONDS; values: timeOfDayValues
var timeOfDayValues = _.object(_.map( };
_.times(numberOfTimeSteps, function(step) { return step * TIME_STEP_SECONDS; }),
function(seconds) { const weekDayField = {
var date = new Date(null); name: 'weekDay',
date.setSeconds(seconds); values: weekDayValues
var timeLabel = date.toISOString().substr(11, 5); };
return [seconds, timeLabel];
const monthDayField = {
name: 'monthDay',
values: monthDayValues
};
const nthWeekDayField = {
name: 'nthWeekDay',
values: nthWeekDayValues
};
const NotificationScheduling = React.createClass({
_getCurrentValue: function() {
return (this.props.item[this.props.field.name] || {});
},
handleValueChange: function(name, value) {
const oldValue = this._getCurrentValue();
let newValue = {};
newValue[name] = value;
return this.props.onValueChange({
target: {
name: this.props.field.name,
value: _.extend({}, oldValue, newValue)
} }
));
var timeOfDayField = {
name: 'timeOfDay',
values: timeOfDayValues,
};
var weekDayField = {
name: 'weekDay',
values: {
0: MailPoet.I18n.t('sunday'),
1: MailPoet.I18n.t('monday'),
2: MailPoet.I18n.t('tuesday'),
3: MailPoet.I18n.t('wednesday'),
4: MailPoet.I18n.t('thursday'),
5: MailPoet.I18n.t('friday'),
6: MailPoet.I18n.t('saturday')
},
};
var NUMBER_OF_DAYS_IN_MONTH = 28; // 28 for compatibility with MP2
var monthDayField = {
name: 'monthDay',
values: _.object(_.map(
_.times(NUMBER_OF_DAYS_IN_MONTH, function(day) { return day; }),
function(day) {
var labels = {
0: MailPoet.I18n.t('first'),
1: MailPoet.I18n.t('second'),
2: MailPoet.I18n.t('third')
},
label;
if (labels[day] !== undefined) {
label = labels[day];
} else {
label = MailPoet.I18n.t('nth').replace("%$1d", day + 1);
}
return [day, label];
},
)),
};
var nthWeekDayField = {
name: 'nthWeekDay',
values: {
'1': MailPoet.I18n.t('first'),
'2': MailPoet.I18n.t('second'),
'3': MailPoet.I18n.t('third'),
'L': MailPoet.I18n.t('last'),
},
};
var NotificationScheduling = React.createClass({
_getCurrentValue: function() {
return this.props.item[this.props.field.name] || {};
},
handleValueChange: function(name, value) {
var oldValue = this._getCurrentValue(),
newValue = {};
newValue[name] = value;
return this.props.onValueChange({
target: {
name: this.props.field.name,
value: _.extend({}, oldValue, newValue)
}
});
},
handleIntervalChange: function(event) {
return this.handleValueChange(
'intervalType',
event.target.value
);
},
handleTimeOfDayChange: function(event) {
return this.handleValueChange(
'timeOfDay',
event.target.value
);
},
handleWeekDayChange: function(event) {
return this.handleValueChange(
'weekDay',
event.target.value
);
},
handleMonthDayChange: function(event) {
return this.handleValueChange(
'monthDay',
event.target.value
);
},
handleNthWeekDayChange: function(event) {
return this.handleValueChange(
'nthWeekDay',
event.target.value
);
},
render: function() {
var value = this._getCurrentValue(),
timeOfDaySelection,
weekDaySelection,
monthDaySelection,
nthWeekDaySelection;
if (value.intervalType !== 'immediately') {
timeOfDaySelection = (
<Select
field={timeOfDayField}
item={this._getCurrentValue()}
onValueChange={this.handleTimeOfDayChange} />
);
}
if (value.intervalType === 'weekly'
|| value.intervalType === 'nthWeekDay') {
weekDaySelection = (
<Select
field={weekDayField}
item={this._getCurrentValue()}
onValueChange={this.handleWeekDayChange} />
);
}
if (value.intervalType === 'monthly') {
monthDaySelection = (
<Select
field={monthDayField}
item={this._getCurrentValue()}
onValueChange={this.handleMonthDayChange} />
);
}
if (value.intervalType === 'nthWeekDay') {
nthWeekDaySelection = (
<Select
field={nthWeekDayField}
item={this._getCurrentValue()}
onValueChange={this.handleNthWeekDayChange} />
);
}
return (
<div>
<Select
field={intervalField}
item={this._getCurrentValue()}
onValueChange={this.handleIntervalChange} />
{nthWeekDaySelection}
{monthDaySelection}
{weekDaySelection}
{timeOfDaySelection}
</div>
);
},
}); });
},
handleIntervalChange: function(event) {
return this.handleValueChange(
'intervalType',
event.target.value
);
},
handleTimeOfDayChange: function(event) {
return this.handleValueChange(
'timeOfDay',
event.target.value
);
},
handleWeekDayChange: function(event) {
return this.handleValueChange(
'weekDay',
event.target.value
);
},
handleMonthDayChange: function(event) {
return this.handleValueChange(
'monthDay',
event.target.value
);
},
handleNthWeekDayChange: function(event) {
return this.handleValueChange(
'nthWeekDay',
event.target.value
);
},
render: function() {
const value = this._getCurrentValue();
let timeOfDaySelection;
let weekDaySelection;
let monthDaySelection;
let nthWeekDaySelection;
return NotificationScheduling; if (value.intervalType !== 'immediately') {
timeOfDaySelection = (
<Select
field={timeOfDayField}
item={this._getCurrentValue()}
onValueChange={this.handleTimeOfDayChange} />
);
}
if (value.intervalType === 'weekly' || value.intervalType === 'nthWeekDay') {
weekDaySelection = (
<Select
field={weekDayField}
item={this._getCurrentValue()}
onValueChange={this.handleWeekDayChange} />
);
}
if (value.intervalType === 'monthly') {
monthDaySelection = (
<Select
field={monthDayField}
item={this._getCurrentValue()}
onValueChange={this.handleMonthDayChange} />
);
}
if (value.intervalType === 'nthWeekDay') {
nthWeekDaySelection = (
<Select
field={nthWeekDayField}
item={this._getCurrentValue()}
onValueChange={this.handleNthWeekDayChange} />
);
}
return (
<div>
<Select
field={intervalField}
item={this._getCurrentValue()}
onValueChange={this.handleIntervalChange} />
{nthWeekDaySelection}
{monthDaySelection}
{weekDaySelection}
{timeOfDaySelection}
</div>
);
} }
); });
module.exports = NotificationScheduling;

View File

@ -1,188 +1,174 @@
define( import _ from 'underscore'
[ import React from 'react'
'underscore', import MailPoet from 'mailpoet'
'react', import Select from 'form/fields/select.jsx'
'react-router', import Text from 'form/fields/text.jsx'
'mailpoet', import {
'form/fields/select.jsx', timeDelayValues,
'form/fields/text.jsx' intervalValues
], } from 'newsletters/scheduling/common.jsx'
function(
_,
React,
Router,
MailPoet,
Select,
Text
) {
var availableRoles = window.mailpoet_roles || {}; const availableRoles = window.mailpoet_roles || {};
var availableSegments = window.mailpoet_segments || {}; const availableSegments = window.mailpoet_segments || {};
var events = { const events = {
name: 'event', name: 'event',
values: { values: {
'segment': MailPoet.I18n.t('onSubscriptionToList'), 'segment': MailPoet.I18n.t('onSubscriptionToList'),
'user': MailPoet.I18n.t('onWPUserRegistration'), 'user': MailPoet.I18n.t('onWPUserRegistration'),
}
};
var availableSegmentValues = _.object(_.map(
availableSegments,
function(segment) {
var name = segment.name;
if (segment.subscribers > 0) {
name += ' (%$1s)'.replace('%$1s', parseInt(segment.subscribers).toLocaleString());
}
return [segment.id, name];
}
));
var segmentField = {
name: 'segment',
values: availableSegmentValues,
};
var roleField = {
name: 'role',
values: availableRoles,
};
var afterTimeNumberField = {
name: 'afterTimeNumber',
size: 3,
};
var afterTimeTypeField = {
name: 'afterTimeType',
values: {
'immediate': MailPoet.I18n.t('delayImmediately'),
'hours': MailPoet.I18n.t('delayHoursAfter'),
'days': MailPoet.I18n.t('delayDaysAfter'),
'weeks': MailPoet.I18n.t('delayWeeksAfter'),
}
};
var WelcomeScheduling = React.createClass({
contextTypes: {
router: React.PropTypes.object.isRequired
},
_getCurrentValue: function() {
return this.props.item[this.props.field.name] || {};
},
handleValueChange: function(name, value) {
var oldValue = this._getCurrentValue(),
newValue = {};
newValue[name] = value;
return this.props.onValueChange({
target: {
name: this.props.field.name,
value: _.extend({}, oldValue, newValue)
}
});
},
handleEventChange: function(event) {
return this.handleValueChange(
'event',
event.target.value
);
},
handleSegmentChange: function(event) {
return this.handleValueChange(
'segment',
event.target.value
);
},
handleRoleChange: function(event) {
return this.handleValueChange(
'role',
event.target.value
);
},
handleAfterTimeNumberChange: function(event) {
return this.handleValueChange(
'afterTimeNumber',
event.target.value
);
},
handleAfterTimeTypeChange: function(event) {
return this.handleValueChange(
'afterTimeType',
event.target.value
);
},
handleNext: function() {
MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'create',
data: {
type: 'welcome',
options: this.state,
},
}).done(function(response) {
if(response.result && response.newsletter.id) {
this.showTemplateSelection(response.newsletter.id);
} else {
if(response.errors.length > 0) {
response.errors.map(function(error) {
MailPoet.Notice.error(error);
});
}
}
}.bind(this));
},
showTemplateSelection: function(newsletterId) {
this.context.router.push(`/template/${newsletterId}`);
},
render: function() {
var value = this._getCurrentValue(),
roleSegmentSelection, timeNumber;
if (value.event === 'user') {
roleSegmentSelection = (
<Select
field={roleField}
item={this._getCurrentValue()}
onValueChange={this.handleRoleChange} />
);
} else {
roleSegmentSelection = (
<Select
field={segmentField}
item={this._getCurrentValue()}
onValueChange={this.handleSegmentChange} />
);
}
if (value.afterTimeType !== 'immediate') {
timeNumber = (
<Text
field={afterTimeNumberField}
item={this._getCurrentValue()}
onValueChange={this.handleAfterTimeNumberChange} />
);
}
return (
<div>
<Select
field={events}
item={this._getCurrentValue()}
onValueChange={this.handleEventChange} />
{roleSegmentSelection}
{timeNumber}
<Select
field={afterTimeTypeField}
item={this._getCurrentValue()}
onValueChange={this.handleAfterTimeTypeChange}/>
</div>
);
},
});
return WelcomeScheduling;
} }
); };
const availableSegmentValues = _.object(_.map(
availableSegments,
function(segment) {
let name = segment.name;
if (segment.subscribers > 0) {
name += ' (%$1s)'.replace('%$1s', parseInt(segment.subscribers).toLocaleString());
}
return [segment.id, name];
}
));
const segmentField = {
name: 'segment',
values: availableSegmentValues
};
const roleField = {
name: 'role',
values: availableRoles
};
const afterTimeNumberField = {
name: 'afterTimeNumber',
size: 3
};
const afterTimeTypeField = {
name: 'afterTimeType',
values: timeDelayValues
};
const WelcomeScheduling = React.createClass({
contextTypes: {
router: React.PropTypes.object.isRequired
},
_getCurrentValue: function() {
return (this.props.item[this.props.field.name] || {});
},
handleValueChange: function(name, value) {
const oldValue = this._getCurrentValue();
let newValue = {};
newValue[name] = value;
return this.props.onValueChange({
target: {
name: this.props.field.name,
value: _.extend({}, oldValue, newValue)
}
});
},
handleEventChange: function(event) {
return this.handleValueChange(
'event',
event.target.value
);
},
handleSegmentChange: function(event) {
return this.handleValueChange(
'segment',
event.target.value
);
},
handleRoleChange: function(event) {
return this.handleValueChange(
'role',
event.target.value
);
},
handleAfterTimeNumberChange: function(event) {
return this.handleValueChange(
'afterTimeNumber',
event.target.value
);
},
handleAfterTimeTypeChange: function(event) {
return this.handleValueChange(
'afterTimeType',
event.target.value
);
},
handleNext: function() {
MailPoet.Ajax.post({
endpoint: 'newsletters',
action: 'create',
data: {
type: 'welcome',
options: this.state
}
}).done(function(response) {
if (response.result && response.newsletter.id) {
this.showTemplateSelection(response.newsletter.id);
} else {
if (response.errors.length > 0) {
response.errors.map(function(error) {
MailPoet.Notice.error(error);
});
}
}
}.bind(this));
},
showTemplateSelection: function(newsletterId) {
this.context.router.push(`/template/${ newsletterId }`);
},
render: function() {
const value = this._getCurrentValue();
let roleSegmentSelection;
let timeNumber;
if (value.event === 'user') {
roleSegmentSelection = (
<Select
field={ roleField }
item={ this._getCurrentValue() }
onValueChange={ this.handleRoleChange } />
);
} else {
roleSegmentSelection = (
<Select
field={ segmentField }
item={ this._getCurrentValue() }
onValueChange={ this.handleSegmentChange } />
);
}
if (value.afterTimeType !== 'immediate') {
timeNumber = (
<Text
field={ afterTimeNumberField }
item={ this._getCurrentValue() }
onValueChange={ this.handleAfterTimeNumberChange } />
);
}
return (
<div>
<Select
field={ events }
item={ this._getCurrentValue() }
onValueChange={ this.handleEventChange } />
{ roleSegmentSelection }
{ timeNumber }
<Select
field={ afterTimeTypeField }
item={ this._getCurrentValue() }
onValueChange={ this.handleAfterTimeTypeChange } />
</div>
);
},
});
module.exports = WelcomeScheduling;

View File

@ -18,7 +18,7 @@ class SendingQueue extends Model {
if($this->count_processed === $this->count_total) { if($this->count_processed === $this->count_total) {
return false; return false;
} else { } else {
$this->set('status', STATUS_PAUSED); $this->set('status', self::STATUS_PAUSED);
$this->save(); $this->save();
return ($this->getErrors() === false && $this->id() > 0); return ($this->getErrors() === false && $this->id() > 0);
} }