diff --git a/assets/css/src/progress_bar.styl b/assets/css/src/progress_bar.styl index f2fcb5b03f..b711fca67c 100644 --- a/assets/css/src/progress_bar.styl +++ b/assets/css/src/progress_bar.styl @@ -5,17 +5,25 @@ width: 100% margin: 0 border-radius: 5px + position: relative -.mailpoet_progress span +.mailpoet_progress_label + position: absolute + width: 100% + text-align: center + display: inline-block + margin: 2px 0 0 0 + +.mailpoet_progress_bar + position: absolute display: inline-block height: 100% border-radius: 3px box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset - -.blue span background-color: #34c2e3 background-image: linear-gradient(top, #34c2e3, darken(#34c2e3, 20%)) -.orange span - background-color: #fecf23 - background-image: linear-gradient(top, #fecf23, #fd9215) \ No newline at end of file +.mailpoet_progress_complete + .mailpoet_progress_bar + background-color: #fecf23 + background-image: linear-gradient(top, #fecf23, #fd9215) \ No newline at end of file diff --git a/assets/js/src/form/fields/text.jsx b/assets/js/src/form/fields/text.jsx index 825209d77c..04fac47d08 100644 --- a/assets/js/src/form/fields/text.jsx +++ b/assets/js/src/form/fields/text.jsx @@ -20,7 +20,9 @@ function( value={ this.props.item[this.props.field.name] } placeholder={ this.props.field.placeholder } defaultValue={ this.props.field.defaultValue } - onChange={ this.props.onValueChange } /> + onChange={ this.props.onValueChange } + {...this.props.field.validation} + /> ); } }); diff --git a/assets/js/src/listing/listing.jsx b/assets/js/src/listing/listing.jsx index d7495133b1..a74d42ed2c 100644 --- a/assets/js/src/listing/listing.jsx +++ b/assets/js/src/listing/listing.jsx @@ -397,6 +397,12 @@ define( if(this.isMounted()) { const params = this.props.params || {} this.initWithParams(params) + + if(this.props.auto_refresh) { + jQuery(document).on('heartbeat-tick.mailpoet', function(e, data) { + this.getItems(); + }.bind(this)); + } } }, componentWillReceiveProps: function(nextProps) { diff --git a/assets/js/src/newsletters/list.jsx b/assets/js/src/newsletters/list.jsx index 00f6ac0936..1accdd3ba0 100644 --- a/assets/js/src/newsletters/list.jsx +++ b/assets/js/src/newsletters/list.jsx @@ -123,23 +123,89 @@ define( ]; var NewsletterList = React.createClass({ + pauseSending: function(item) { + MailPoet.Ajax.post({ + endpoint: 'sendingQueue', + action: 'pause', + data: item.id + }).done(function() { + jQuery('#resume_'+item.id).show(); + jQuery('#pause_'+item.id).hide(); + }); + }, + resumeSending: function(item) { + MailPoet.Ajax.post({ + endpoint: 'sendingQueue', + action: 'resume', + data: item.id + }).done(function() { + jQuery('#pause_'+item.id).show(); + jQuery('#resume_'+item.id).hide(); + }); + }, renderStatus: function(item) { if(item.queue === null) { return ( Not sent yet. ); } else { + var progressClasses = classNames( + 'mailpoet_progress', + { 'mailpoet_progress_complete': item.queue.status === 'completed'} + ); + // calculate percentage done var percentage = Math.round( (item.queue.count_processed * 100) / (item.queue.count_total) ); + var label = false; + + if(item.queue.status === 'completed') { + label = ( + + Sent to { + item.queue.count_processed - item.queue.count_failed + } out of { item.queue.count_total }. + + ); + } else { + label = ( + + { item.queue.count_processed } / { item.queue.count_total } +    + Resume + Pause + + ); + } + return (
-
- +
+ + + { percentage + "%" } +
- { item.queue.count_processed } / { item.queue.count_total } +

+ { label } +

); } @@ -194,7 +260,8 @@ define( columns={columns} bulk_actions={ bulk_actions } item_actions={ item_actions } - messages={ messages } /> + messages={ messages } + auto_refresh={ true } />
); } diff --git a/assets/js/src/newsletters/send.jsx b/assets/js/src/newsletters/send.jsx index d4476481f7..0c9bcbc2d1 100644 --- a/assets/js/src/newsletters/send.jsx +++ b/assets/js/src/newsletters/send.jsx @@ -48,14 +48,21 @@ define( name: 'from_name', type: 'text', placeholder: 'John Doe', - defaultValue: settings.from_name + defaultValue: (settings.sender !== undefined) ? settings.sender.name : '', + validation: { + 'data-parsley-required': true + } }, { name: 'from_email', type: 'text', placeholder: 'john.doe@email.com', - defaultValue: settings.from_address - }, + defaultValue: (settings.sender !== undefined) ? settings.sender.address : '', + validation: { + 'data-parsley-required': true, + 'data-parsley-type': 'email' + } + } ] }, { @@ -93,33 +100,40 @@ define( Router.History ], handleSend: function() { - MailPoet.Ajax.post({ - endpoint: 'sendingQueue', - action: 'addQueue', - data: { - newsletter_id: this.props.params.id, - segments: jQuery('#mailpoet_segments').val() - } - }).done(function(response) { - if(response === true) { - //this.history.pushState(null, '/'); + if(jQuery('#mailpoet_newsletter').parsley().validate() === true) { + MailPoet.Ajax.post({ + endpoint: 'sendingQueue', + action: 'add', + data: { + newsletter_id: this.props.params.id, + segments: jQuery('#mailpoet_segments').val() + } + }).done(function(response) { + if(response.result === true) { + this.history.pushState(null, '/'); - MailPoet.Notice.success( - 'The newsletter has been sent!' - ); - } else { - if(response.errors) { - MailPoet.Notice.error( - response.errors.join("
") + MailPoet.Notice.success( + 'The newsletter is being sent...' ); } else { - MailPoet.Notice.error( - 'An error occurred while trying to send. '+ - 'Check your settings.' - ); + if(response.errors) { + MailPoet.Notice.error( + response.errors.join("
") + ); + } else { + MailPoet.Notice.error( + 'An error occurred while trying to send. '+ + 'Check your settings.' + ); + } } - } - }.bind(this)); + }.bind(this)); + } + }, + componentDidMount: function() { + if(this.isMounted()) { + jQuery('#mailpoet_newsletter').parsley(); + } }, render: function() { return ( diff --git a/assets/js/src/settings/tabs.js b/assets/js/src/settings/tabs.js index a81318cd00..860581c9c4 100644 --- a/assets/js/src/settings/tabs.js +++ b/assets/js/src/settings/tabs.js @@ -36,7 +36,7 @@ define( } else { // hide DKIM option when using MailPoet's API jQuery('#mailpoet_mta_dkim')[ - (method === 'mailpoet') + (method === 'MailPoet') ? 'hide' : 'show' ](); diff --git a/lib/Config/Menu.php b/lib/Config/Menu.php index b20a0696b8..1d0aaac4e5 100644 --- a/lib/Config/Menu.php +++ b/lib/Config/Menu.php @@ -320,20 +320,27 @@ class Menu { } function newsletters() { + add_filter('heartbeat_received', array($this, 'getQueueStatus'), 10, 3); + global $wp_roles; $data = array(); $data['segments'] = Segment::findArray(); - $settings = Setting::findArray(); - $data['settings'] = array(); - foreach ($settings as $setting) { - $data['settings'][$setting['name']] = $setting['value']; - } + $data['settings'] = Setting::getAll(); $data['roles'] = $wp_roles->get_names(); echo $this->renderer->render('newsletters.html', $data); } + function getQueueStatus($response, $data, $screen_id) { + if(isset($data['mailpoet'])) { + $response['mailpoet'] = array( + 'hello' => 'world' + ); + } + return $response; + } + function newletterEditor() { $data = array(); wp_enqueue_media(); @@ -364,7 +371,7 @@ class Menu { $data = array( 'form' => $form, 'pages' => Pages::getAll(), - 'segments' => Segment::getPublished() + 'segments' => Segment::getPublic() ->findArray(), 'styles' => FormRenderer::getStyles($form), 'date_types' => Block\Date::getDateTypes(), diff --git a/lib/Models/Newsletter.php b/lib/Models/Newsletter.php index 09ef11774e..02135b6adb 100644 --- a/lib/Models/Newsletter.php +++ b/lib/Models/Newsletter.php @@ -43,6 +43,12 @@ class Newsletter extends Model { )->select_expr(MP_NEWSLETTER_OPTION_TABLE.'.value'); } + function getQueue() { + return SendingQueue::where('newsletter_id', $this->id) + ->orderByDesc('updated_at') + ->findOne(); + } + static function search($orm, $search = '') { return $orm->where_like('subject', '%' . $search . '%'); } diff --git a/lib/Models/SendingQueue.php b/lib/Models/SendingQueue.php index d1c9762132..9a5bcf405b 100644 --- a/lib/Models/SendingQueue.php +++ b/lib/Models/SendingQueue.php @@ -9,4 +9,27 @@ class SendingQueue extends Model { function __construct() { parent::__construct(); } + + function pause() { + if($this->count_processed === $this->count_total) { + return false; + } else { + $this->set('status', 'paused'); + return $this->save(); + } + } + + function resume() { + if($this->count_processed === $this->count_total) { + return $this->complete(); + } else { + $this->set_expr('status', 'NULL'); + return $this->save(); + } + } + + function complete() { + $this->set('status', 'completed'); + return $this->save(); + } } \ No newline at end of file diff --git a/lib/Router/Queue.php b/lib/Router/Queue.php index 4a2ae14b3b..c20eacd7f7 100644 --- a/lib/Router/Queue.php +++ b/lib/Router/Queue.php @@ -92,6 +92,8 @@ class Queue { ); } + + function addQueues($data) { $result = array_map(function ($queueData) { $queue = SendingQueue::create(); diff --git a/lib/Router/SendingQueue.php b/lib/Router/SendingQueue.php index 2cb67e0c89..6f493a0b5c 100644 --- a/lib/Router/SendingQueue.php +++ b/lib/Router/SendingQueue.php @@ -1,13 +1,14 @@ whereNull('status') ->findArray(); @@ -18,6 +19,7 @@ class SendingQueue { 'errors' => array(__('Send operation is already in progress.')) ) ); + exit; } $queue = \MailPoet\Models\SendingQueue::create(); $queue->newsletter_id = $data['newsletter_id']; @@ -39,18 +41,60 @@ class SendingQueue { ) ); $queue->count_total = $queue->count_to_process = count($subscriber_ids); - $queue->save(); - wp_send_json( - !$queue->save() ? + $result = $queue->save(); + if($result === false) { + $errors = array(__('Queue could not be created.')); + + if(!empty($queue->getValidationErrors())) { + $errors = array_merge($errors, $queue->getValidationErrors()); + } + + wp_send_json( array( 'result' => false, - 'errors' => array(__('Queue could not be created.')) - ) : + 'errors' => $errors + ) + ); + } else { + wp_send_json( array( 'result' => true, 'data' => array($queue->id) ) - ); + ); + } + } + + function pause($newsletter_id) { + $newsletter = Newsletter::findOne($newsletter_id); + $result = false; + + if($newsletter !== false) { + $queue = $newsletter->getQueue(); + if($queue !== false && $queue->id() > 0) { + $result = $queue->pause(); + } + } + + wp_send_json(array( + 'result' => $result + )); + } + + function resume($newsletter_id) { + $newsletter = Newsletter::findOne($newsletter_id); + $result = false; + + if($newsletter !== false) { + $queue = $newsletter->getQueue(); + if($queue !== false && $queue->id() > 0) { + $result = $queue->resume(); + } + } + + wp_send_json(array( + 'result' => $result + )); } function addQueues($data) { diff --git a/lib/Settings/Hosts.php b/lib/Settings/Hosts.php index 95264d047c..fc9d125543 100644 --- a/lib/Settings/Hosts.php +++ b/lib/Settings/Hosts.php @@ -3,25 +3,25 @@ namespace MailPoet\Settings; class Hosts { private static $_smtp = array( - 'amazon' => array( + 'AmazonSES' => array( 'name' => 'Amazon SES', 'api' => false, 'emails' => 100, 'interval' => 5 ), - 'elasticemail' => array( + 'ElasticEmail' => array( 'name' => 'ElasticEmail', 'api' => true, 'emails' => 100, 'interval' => 5 ), - 'mailgun' => array( + 'MailGun' => array( 'name' => 'MailGun', 'api' => false, 'emails' => 100, 'interval' => 5 ), - 'sendgrid' => array( + 'SendGrid' => array( 'name' => 'SendGrid', 'api' => true, 'emails' => 100, diff --git a/package.json b/package.json index d90d3231b0..9a2955db2e 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "moment": "^2.10.3", "napa": "^1.2.0", "papaparse": "4.1.1", - "parsley": "^0.1.0", + "parsleyjs": "^2.1.2", "react": "^0.14.1", "react-checkbox-group": "0.2.2", "react-dom": "^0.14.1", diff --git a/views/settings/mta.html b/views/settings/mta.html index 426b00197c..cca8431a19 100644 --- a/views/settings/mta.html +++ b/views/settings/mta.html @@ -17,6 +17,7 @@ name="mta[method]" value="<%= settings.mta.method %>" /> +