Add standard newsletter scheduling UI

This commit is contained in:
Tautvidas Sipavičius
2016-05-06 14:31:18 +03:00
parent 65df28d52e
commit f7c70be5eb
10 changed files with 376 additions and 9 deletions

View File

@ -1,6 +1,7 @@
@import 'nib' @import 'nib'
@require 'select2/dist/css/select2.css' @require 'select2/dist/css/select2.css'
@require 'datepicker'
@require 'common' @require 'common'
@require 'modal' @require 'modal'
@ -18,4 +19,4 @@
@require 'settings' @require 'settings'
@require 'progress_bar' @require 'progress_bar'
@require 'subscribers' @require 'subscribers'

View File

@ -0,0 +1,97 @@
/*
Taken from: https://github.com/rtsinani/jquery-datepicker-skins
Skin: Melon
*/
.ui-widget
font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
background: #2e3641;
border: none;
border-radius: 0;
-webkit-border-radius: 0;
-moz-border-radius: 0;
.ui-datepicker
padding: 0;
.ui-datepicker-header
border: none;
background: transparent;
font-weight: normal;
font-size: 15px;
.ui-datepicker-header .ui-state-hover
background: transparent;
border-color: transparent;
cursor: pointer;
border-radius: 0;
-webkit-border-radius: 0;
-moz-border-radius: 0;
.ui-datepicker .ui-datepicker-title
margin-top: .4em;
margin-bottom: .3em;
color: #e9f0f4;
.ui-datepicker .ui-datepicker-prev-hover
.ui-datepicker .ui-datepicker-next-hover
.ui-datepicker .ui-datepicker-next
.ui-datepicker .ui-datepicker-prev
top: .9em;
border:none;
.ui-datepicker .ui-datepicker-prev-hover
left: 2px;
.ui-datepicker .ui-datepicker-next-hover
right: 2px;
.ui-datepicker .ui-datepicker-next span
.ui-datepicker .ui-datepicker-prev span
background-image: url(../img/datepicker/ui-icons_ffffff_256x240.png);
background-position: -32px 0;
margin-top: 0;
top: 0;
font-weight: normal;
.ui-datepicker .ui-datepicker-prev span
background-position: -96px 0;
.ui-datepicker table
margin: 0;
.ui-datepicker th
padding: 1em 0;
color: #ccc;
font-size: 13px;
font-weight: normal;
border: none;
border-top: 1px solid #3a414d;
.ui-datepicker td
background: #f97e76;
border: none;
padding: 0;
td .ui-state-default
background: transparent;
border: none;
text-align: center;
padding: .5em;
margin: 0;
font-weight: normal;
color: #efefef;
font-size: 16px;
.ui-state-disabled
opacity: 1;
.ui-state-disabled .ui-state-default
color: #fba49e;
td .ui-state-active
td .ui-state-hover
background: #2e3641;

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -35,9 +35,9 @@ define(
}, },
getFieldsByNewsletter: function(newsletter) { getFieldsByNewsletter: function(newsletter) {
switch(newsletter.type) { switch(newsletter.type) {
case 'notification': return NotificationNewsletterFields; case 'notification': return NotificationNewsletterFields(newsletter);
case 'welcome': return WelcomeNewsletterFields; case 'welcome': return WelcomeNewsletterFields(newsletter);
default: return StandardNewsletterFields; default: return StandardNewsletterFields(newsletter);
} }
}, },
isAutomatedNewsletter: function() { isAutomatedNewsletter: function() {

View File

@ -1,12 +1,180 @@
define( define(
[ [
'mailpoet' 'react',
'jquery',
'mailpoet',
'form/fields/checkbox.jsx',
'form/fields/select.jsx',
'form/fields/text.jsx',
], ],
function( function(
MailPoet React,
jQuery,
MailPoet,
Checkbox,
Select,
Text
) { ) {
var settings = window.mailpoet_settings || {}; var settings = window.mailpoet_settings || {},
currentTime = window.mailpoet_current_time || '00:00',
timeOfDayItems = window.mailpoet_schedule_time_of_day;
var isScheduledField = {
name: 'isScheduled',
};
var DateText = React.createClass({
componentDidMount: function() {
var $element = jQuery(this.refs.dateInput);
if ($element.datepicker) {
$element.datepicker({
dateFormat: "yy-mm-dd",
});
}
},
render: function() {
return (
<input
type="text"
name={this.props.name || 'date'}
value={this.props.value}
onChange={this.props.onChange}
ref="dateInput" />
);
},
});
var TimeSelect = React.createClass({
render: function() {
const options = Object.keys(timeOfDayItems).map(
(value, index) => {
return (
<option
key={ 'option-' + index }
value={ value }>
{ timeOfDayItems[value] }
</option>
);
}
);
return (
<select
name={this.props.name || 'time'}
value={this.props.value}
onChange={this.props.onChange}
>
{options}
</select>
);
}
});
var DateTime = React.createClass({
_DATE_TIME_SEPARATOR: " ",
getInitialState: function() {
return this._buildStateFromProps(this.props);
},
componentWillReceiveProps: function(nextProps) {
this.setState(this._buildStateFromProps(nextProps));
},
_buildStateFromProps: function(props) {
const [date, time] = props.value.split(this._DATE_TIME_SEPARATOR)
return {
date: date,
time: time,
};
},
handleChange: function(event) {
var newState = {};
newState[event.target.name] = event.target.value;
this.setState(newState, function() {
this.propagateChange();
});
},
propagateChange: function() {
if (this.props.onChange) {
this.props.onChange({
target: {
name: this.props.name || '',
value: this.getDateTime(),
}
})
}
},
getDateTime: function() {
return [this.state.date, this.state.time].join(this._DATE_TIME_SEPARATOR);
},
render: function() {
return (
<span>
<DateText
name="date"
value={this.state.date}
onChange={this.handleChange} />
<TimeSelect
name="time"
value={this.state.time}
onChange={this.handleChange} />
</span>
);
}
});
var StandardScheduling = React.createClass({
getInitialState: function() {
return {
isScheduled: '0',
scheduledAt: '2016-05-04 14:00:00',
};
},
handleChange: function(event) {
var newState = {};
newState[event.target.name] = event.target.value;
this.setState(newState);
},
handleCheckboxChange: function(event) {
event.target.value = this.refs.isScheduled.checked ? '1' : '0';
this.handleChange(event);
},
isScheduled: function() {
return this.state.isScheduled === '1';
},
render: function() {
var isChecked = this.isScheduled(),
schedulingOptions;
if (isChecked) {
schedulingOptions = (
<span>
<DateTime
name="scheduledAt"
value={this.state.scheduledAt}
onChange={this.handleChange} />
<span>
{MailPoet.I18n.t('localTimeIs')} <code>{currentTime}</code>
</span>
</span>
);
}
return (
<div>
<input
ref="isScheduled"
type="checkbox"
value="1"
checked={this.isScheduled()}
name="isScheduled"
onChange={this.handleCheckboxChange} />
{schedulingOptions}
</div>
);
},
});
var fields = [ var fields = [
{ {
@ -84,9 +252,17 @@ define(
placeholder: MailPoet.I18n.t('replyToAddressPlaceholder') placeholder: MailPoet.I18n.t('replyToAddressPlaceholder')
} }
] ]
},
{
name: 'options',
label: MailPoet.I18n.t('scheduleIt'),
type: 'reactComponent',
component: StandardScheduling,
} }
]; ];
return fields; return function(newsletter) {
return fields;
};
} }
); );

View File

@ -71,7 +71,9 @@ define(
} }
]; ];
return fields; return function(newsletter) {
return fields;
};
} }
); );

View File

@ -14,6 +14,7 @@ use MailPoet\Subscribers\ImportExport\BootStrapMenu;
use MailPoet\Util\DKIM; use MailPoet\Util\DKIM;
use MailPoet\Util\Permissions; use MailPoet\Util\Permissions;
use MailPoet\Listing; use MailPoet\Listing;
use MailPoet\WP\DateTime;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
@ -402,6 +403,18 @@ class Menu {
$data['roles'] = $wp_roles->get_names(); $data['roles'] = $wp_roles->get_names();
$data['roles']['mailpoet_all'] = __('In any WordPress role'); $data['roles']['mailpoet_all'] = __('In any WordPress role');
$date_time = new DateTime();
$data['current_date'] = $date_time->getCurrentDate(DateTime::INTERNAL_DATE_FORMAT);
$data['current_time'] = $date_time->getCurrentTime();
$data['schedule_time_of_day'] = $date_time->getTimeInterval(
'00:00:00',
'+1 hour',
24
);
wp_enqueue_script('jquery-ui');
wp_enqueue_script('jquery-ui-datepicker');
echo $this->renderer->render('newsletters.html', $data); echo $this->renderer->render('newsletters.html', $data);
} }

View File

@ -140,6 +140,14 @@ class Populator {
function newsletter_option_fields() { function newsletter_option_fields() {
return array( return array(
array(
'name' => 'isScheduled',
'newsletter_type' => 'standard',
),
array(
'name' => 'scheduledAt',
'newsletter_type' => 'standard',
),
array( array(
'name' => 'event', 'name' => 'event',
'newsletter_type' => 'welcome', 'newsletter_type' => 'welcome',

65
lib/WP/DateTime.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace MailPoet\WP;
class DateTime {
const INTERNAL_DATE_FORMAT = 'Y-m-d';
const INTERNAL_TIME_FORMAT = 'H:i:s';
const INTERNAL_DATE_TIME_FORMAT = 'Y-m-d H:i:s';
function __construct() {
}
function getTimeFormat() {
$time_format = get_option('time_format');
if (empty($time_format)) $time_format = self::INTERNAL_TIME_FORMAT;
return $time_format;
}
function getDateFormat() {
$date_format = get_option('date_format');
if (empty($date_format)) $date_format = self::INTERNAL_DATE_FORMAT;
return $date_format;
}
function getCurrentTime($format=false) {
if (empty($format)) $format = $this->getTimeFormat();
return current_time($format);
}
function getCurrentDate($format=false) {
if (empty($format)) $format = $this->getDateFormat();
return $this->getCurrentTime($format);
}
function getTime($time, $format=false) {
if (empty($format)) $format = $this->getTimeFormat();
return date($format, $time);
}
/**
* Generates a list of time strings within an interval,
* formatted and mapped from INTERNAL_TIME_FORMAT to Wordpress time strings.
*/
function getTimeInterval(
$start_time='00:00:00',
$time_step='+1 hour',
$total_steps=24
) {
$steps = array();
$internal_time = $start_time;
$timestamp = strtotime($internal_time);
for ($step = 0; $step < $total_steps; $step += 1) {
$wordpress_time = $this->getTime($timestamp);
$steps[$internal_time] = $wordpress_time;
$timestamp = strtotime($time_step, $timestamp);
$internal_time = $this->getTime($timestamp, self::INTERNAL_TIME_FORMAT);
}
return $steps;
}
}

View File

@ -9,6 +9,9 @@
var mailpoet_settings = <%= json_encode(settings) %>; var mailpoet_settings = <%= json_encode(settings) %>;
var mailpoet_lists = <%= json_encode(lists) %>; var mailpoet_lists = <%= json_encode(lists) %>;
var mailpoet_roles = <%= json_encode(roles) %>; var mailpoet_roles = <%= json_encode(roles) %>;
var mailpoet_current_date = <%= json_encode(current_date) %>;
var mailpoet_current_time = <%= json_encode(current_time) %>;
var mailpoet_schedule_time_of_day = <%= json_encode(schedule_time_of_day) %>;
</script> </script>
<% endblock %> <% endblock %>
@ -62,6 +65,7 @@
'edit': __('Edit'), 'edit': __('Edit'),
'notSentYet': __('Not sent yet.'), 'notSentYet': __('Not sent yet.'),
'scheduledFor': __('Scheduled for'), 'scheduledFor': __('Scheduled for'),
'scheduleIt': __('Schedule it'),
'newsletterQueueCompleted': __('Sent to %$1d of %$2d.'), 'newsletterQueueCompleted': __('Sent to %$1d of %$2d.'),
'resume': __('Resume'), 'resume': __('Resume'),
'pause': __('Pause'), 'pause': __('Pause'),
@ -145,5 +149,6 @@
'saveDraftAndClose': __('Save as draft and close'), 'saveDraftAndClose': __('Save as draft and close'),
'orSimply': __('or simply'), 'orSimply': __('or simply'),
'goBackToDesign': __('go back to design'), 'goBackToDesign': __('go back to design'),
'localTimeIs': __('Local time is'),
}) %> }) %>
<% endblock %> <% endblock %>