diff --git a/assets/css/src/admin.styl b/assets/css/src/admin.styl index 7116966a00..866f4d26db 100644 --- a/assets/css/src/admin.styl +++ b/assets/css/src/admin.styl @@ -9,6 +9,8 @@ @require 'form_editor' @require 'listing' +@require 'listing/newsletters' + @require 'box' @require 'breadcrumb' diff --git a/assets/css/src/listing/newsletters.styl b/assets/css/src/listing/newsletters.styl new file mode 100644 index 0000000000..329c08c0c3 --- /dev/null +++ b/assets/css/src/listing/newsletters.styl @@ -0,0 +1,3 @@ +#newsletters_container + h2.nav-tab-wrapper + margin-bottom: 1rem \ No newline at end of file diff --git a/assets/js/src/forms/list.jsx b/assets/js/src/forms/list.jsx index 495a3e03ed..21e7cbf745 100644 --- a/assets/js/src/forms/list.jsx +++ b/assets/js/src/forms/list.jsx @@ -90,7 +90,7 @@ const item_actions = [ } }, { - name: 'duplicate_form', + name: 'duplicate', label: MailPoet.I18n.t('duplicate'), onClick: function(item, refresh) { return MailPoet.Ajax.post({ @@ -98,9 +98,11 @@ const item_actions = [ action: 'duplicate', data: item.id }).done(function(response) { - MailPoet.Notice.success( - (MailPoet.I18n.t('formDuplicated')).replace('%$1s', response.name) - ); + if (response !== false && response['name'] !== undefined) { + MailPoet.Notice.success( + (MailPoet.I18n.t('formDuplicated')).replace('%$1s', response.name) + ); + } refresh(); }); } diff --git a/assets/js/src/newsletters/listings/standard.jsx b/assets/js/src/newsletters/listings/standard.jsx index 9b7f425b8c..39241dad4e 100644 --- a/assets/js/src/newsletters/listings/standard.jsx +++ b/assets/js/src/newsletters/listings/standard.jsx @@ -106,6 +106,26 @@ var item_actions = [ ); } }, + { + name: 'duplicate', + label: MailPoet.I18n.t('duplicate'), + onClick: function(item, refresh) { + return MailPoet.Ajax.post({ + endpoint: 'newsletters', + action: 'duplicate', + data: item.id + }).done(function(response) { + if (response !== false && response.subject !== undefined) { + MailPoet.Notice.success( + (MailPoet.I18n.t('newsletterDuplicated')).replace( + '%$1s', response.subject + ) + ); + } + refresh(); + }); + } + }, { name: 'trash' } diff --git a/lib/Config/Migrator.php b/lib/Config/Migrator.php index 3a1496a275..a23cc245d6 100644 --- a/lib/Config/Migrator.php +++ b/lib/Config/Migrator.php @@ -2,6 +2,7 @@ namespace MailPoet\Config; use MailPoet\Models\Subscriber; +use MailPoet\Models\Newsletter; if(!defined('ABSPATH')) exit; @@ -174,6 +175,7 @@ class Migrator { 'type varchar(20) NOT NULL DEFAULT "standard",', 'sender_address varchar(150) NOT NULL DEFAULT "",', 'sender_name varchar(150) NOT NULL DEFAULT "",', + 'status varchar(20) NOT NULL DEFAULT "'.Newsletter::STATUS_DRAFT.'",', 'reply_to_address varchar(150) NOT NULL DEFAULT "",', 'reply_to_name varchar(150) NOT NULL DEFAULT "",', 'preheader varchar(250) NOT NULL DEFAULT "",', diff --git a/lib/Models/Newsletter.php b/lib/Models/Newsletter.php index a6c32da012..27f96b6fad 100644 --- a/lib/Models/Newsletter.php +++ b/lib/Models/Newsletter.php @@ -10,6 +10,9 @@ class Newsletter extends Model { const TYPE_WELCOME = 'welcome'; const TYPE_NOTIFICATION = 'notification'; + const STATUS_DRAFT = 'draft'; + const STATUS_SENT = 'sent'; + function __construct() { parent::__construct(); @@ -205,6 +208,16 @@ class Newsletter extends Model { 'label' => __('All'), 'count' => Newsletter::getPublished()->where('type', $data['tab'])->count() ), + array( + 'name' => self::STATUS_DRAFT, + 'label' => __('Draft'), + 'count' => Newsletter::filter('filterDraft', $data)->count() + ), + array( + 'name' => self::STATUS_SENT, + 'label' => __('Sent'), + 'count' => Newsletter::filter('filterSent', $data)->count() + ), array( 'name' => 'trash', 'label' => __('Trash'), @@ -213,22 +226,48 @@ class Newsletter extends Model { ); } + static function groupBy($orm, $data = array()) { + $group = (!empty($data['group'])) ? $data['group'] : 'all'; + + switch($group) { + case self::STATUS_DRAFT: + $orm->filter('filterDraft', $data); + break; + case self::STATUS_SENT: + $orm->filter('filterSent', $data); + break; + case 'trash': + $orm->whereNotNull('deleted_at'); + break; + default: + $orm->whereNull('deleted_at'); + } + return $orm; + } + + static function filterDraft($orm, $data = array()) { + $type = isset($data['tab']) ? $data['tab'] : self::TYPE_STANDARD; + + return $orm + ->where('type', $type) + ->where('status', self::STATUS_DRAFT); + } + + static function filterSent($orm, $data = array()) { + $type = isset($data['tab']) ? $data['tab'] : self::TYPE_STANDARD; + + return $orm + ->where('type', $type) + ->where('status', self::STATUS_SENT); + } + static function listingQuery($data = array()) { return self::where('type', $data['tab']) ->filter('filterBy', $data) - ->filter('groupBy', $data['group']) + ->filter('groupBy', $data) ->filter('search', $data['search']); } - static function groupBy($orm, $group = null) { - if($group === 'trash') { - $orm->whereNotNull('deleted_at'); - } else { - $orm->whereNull('deleted_at'); - } - return $orm; - } - static function createOrUpdate($data = array()) { $newsletter = false; diff --git a/lib/Router/Newsletters.php b/lib/Router/Newsletters.php index 91b09cf954..ce77bd2b6b 100644 --- a/lib/Router/Newsletters.php +++ b/lib/Router/Newsletters.php @@ -124,13 +124,15 @@ class Newsletters { } function duplicate($id = false) { + $result = false; + $newsletter = Newsletter::findOne($id); if($newsletter !== false) { - return $newsletter->duplicate(array( + $result = $newsletter->duplicate(array( 'subject' => sprintf(__('Copy of %s'), $newsletter->subject) ))->asArray(); } - return false; + return $result; } function showPreview($data = array()) { diff --git a/views/newsletters.html b/views/newsletters.html index 531235e0c6..caba914984 100644 --- a/views/newsletters.html +++ b/views/newsletters.html @@ -70,6 +70,8 @@ 'multipleNewslettersRestored': __('%$1d newsletters have been restored from the trash.'), 'trash': __('Trash'), 'edit': __('Edit'), + 'duplicate': __('Duplicate'), + 'newsletterDuplicated': __('Newsletter "%$1s" has been duplicated.'), 'notSentYet': __('Not sent yet.'), 'scheduledFor': __('Scheduled for'), 'scheduleIt': __('Schedule it'),