implemented all bulk actions for Subscribers

This commit is contained in:
Jonathan Labreuille
2015-09-16 19:44:46 +02:00
parent 4e6768c4f1
commit cbcd614b6f
7 changed files with 319 additions and 29 deletions

View File

@ -35,18 +35,22 @@ define('ajax', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
this.options.token = window.mailpoet_token;
}
},
request: function(method, options) {
// set options
this.init(options);
// set request params
var params = {
getParams: function() {
return {
action: 'mailpoet',
token: this.options.token,
endpoint: this.options.endpoint,
method: this.options.action,
data: this.options.data || {}
}, jqXHR;
}
},
request: function(method, options) {
// set options
this.init(options);
// set request params
var params = this.getParams();
var jqXHR;
// make ajax request depending on method
if(method === 'get') {

View File

@ -1,21 +1,54 @@
define(['react'], function(React) {
define([
'react',
'mailpoet'
],
function(
React,
MailPoet
) {
var ListingBulkActions = React.createClass({
getInitialState: function() {
return {
action: false,
extra: false
}
},
handleChangeAction: function(e) {
this.setState({
action: e.target.value,
extra: false
});
var action = this.getSelectedAction();
// action on select callback
if(action !== null && action['onSelect'] !== undefined) {
action.onSelect(e);
this.setState({
extra: action.onSelect(e)
});
}
},
handleApplyAction: function(e) {
e.preventDefault();
var action = this.getSelectedAction();
var selected_ids = (this.props.selection !== 'all')
? this.props.selected_ids
: [];
var data = (action['getData'] !== undefined)
? action.getData()
: {};
if(action !== null && action['onApply'] !== undefined) {
action.onApply();
data.action = this.state.action;
if(data.action) {
this.props.onBulkAction(selected_ids, data);
}
this.setState({
action: false,
extra: false
});
},
getSelectedAction: function() {
var selected_action = jQuery(this.refs.action.getDOMNode()).val();
@ -43,13 +76,13 @@ define(['react'], function(React) {
Select bulk action
</label>
<select ref="action" onChange={this.handleChangeAction}>
<select ref="action" value={ this.state.action } onChange={this.handleChangeAction}>
<option value="">Bulk Actions</option>
{this.props.bulk_actions.map(function(action, index) {
return (
<option
value={action.name}
key={index}
value={ action.name }
key={ 'action-' + index }
>{ action.label }</option>
);
}.bind(this))}
@ -59,6 +92,8 @@ define(['react'], function(React) {
type="submit"
defaultValue="Apply"
className="button action" />
{ this.state.extra }
</div>
);
}

View File

@ -200,6 +200,8 @@ define(
getItems: function() {
this.setState({ loading: true });
this.clearSelection();
MailPoet.Ajax.post({
endpoint: this.props.endpoint,
action: 'listing',
@ -234,6 +236,27 @@ define(
this.getItems();
}.bind(this));
},
handleBulkAction: function(selected_ids, params) {
this.setState({ loading: true });
var data = params || {};
data.selection = selected_ids;
data.listing = {
offset: 0,
limit: 0,
group: this.state.group,
search: this.state.search
}
MailPoet.Ajax.post({
endpoint: this.props.endpoint,
action: 'bulk_action',
data: data
}).done(function() {
this.getItems();
}.bind(this));
},
handleSearch: function(search) {
this.setState({
search: search,
@ -248,7 +271,6 @@ define(
sort_by: sort_by,
sort_order: sort_order,
}, function() {
this.clearSelection();
this.getItems();
}.bind(this));
},
@ -268,7 +290,6 @@ define(
},
handleSelectItems: function(is_checked) {
if(is_checked === false) {
this.clearSelection();
} else {
var selected_ids = this.state.items.map(function(item) {
return ~~item.id;
@ -282,7 +303,6 @@ define(
},
handleSelectAll: function() {
if(this.state.selection === 'all') {
this.clearSelection();
} else {
this.setState({
selection: 'all',
@ -306,7 +326,6 @@ define(
search: '',
page: 1
}, function() {
this.clearSelection();
this.getItems();
}.bind(this));
},
@ -354,7 +373,10 @@ define(
search={ this.state.search } />
<div className="tablenav top clearfix">
<ListingBulkActions
bulk_actions={ bulk_actions } />
bulk_actions={ bulk_actions }
selection={ this.state.selection }
selected_ids={ this.state.selected_ids }
onBulkAction={ this.handleBulkAction } />
<ListingFilters filters={ this.state.filters } />
<ListingPages
count={ this.state.count }
@ -381,8 +403,8 @@ define(
is_selectable={ bulk_actions.length > 0 }
onSelectItem={ this.handleSelectItem }
onSelectAll={ this.handleSelectAll }
selected_ids={ this.state.selected_ids }
selection={ this.state.selection }
selected_ids={ this.state.selected_ids }
loading={ this.state.loading }
count={ this.state.count }
limit={ this.state.limit }
@ -402,7 +424,10 @@ define(
</table>
<div className="tablenav bottom">
<ListingBulkActions
bulk_actions={ bulk_actions } />
bulk_actions={ bulk_actions }
selection={ this.state.selection }
selected_ids={ this.state.selected_ids }
onBulkAction={ this.handleBulkAction } />
<ListingPages
count={ this.state.count }
page={ this.state.page }

View File

@ -2,12 +2,17 @@ define(
[
'react',
'listing/listing.jsx',
'classnames'
'classnames',
'mailpoet',
'jquery',
'select2'
],
function(
React,
Listing,
classNames
classNames,
MailPoet,
jQuery
) {
var columns = [
{
@ -42,18 +47,154 @@ define(
},
];
var ItemSelection = React.createClass({
getInitialState: function() {
return {
loading: false,
items: [],
selected: false,
multiple: false
}
},
componentDidMount: function() {
this.loadItems();
},
loadItems: function() {
this.setState({ loading: true });
MailPoet.Ajax.post({
endpoint: this.props.endpoint,
action: 'listing',
data: {
'offset': 0,
'limit': 5,
'search': '',
'sort_by': 'name',
'sort_order': 'asc'
}
})
.done(function(response) {
if(this.isMounted()) {
if(response === false) {
this.setState({
loading: false,
items: []
});
} else {
this.setState({
loading: false,
items: response.items
});
}
}
}.bind(this));
},
handleChange: function() {
var new_value = this.refs.selection.getDOMNode().value;
if(this.state.multiple === false) {
if(new_value.trim().length === 0) {
new_value = false;
}
this.setState({
selected: new_value
});
} else {
var selected_values = this.state.selected || [];
if(selected_values.indexOf(new_value) !== -1) {
// value already present so remove it
selected_values.splice(selected_values.indexOf(new_value), 1);
} else {
selected_values.push(new_value);
}
this.setState({
selected: selected_values
});
}
},
getSelected: function() {
return this.state.selected;
},
render: function() {
var options = this.state.items.map(function(item, index) {
return (
<option
key={ 'action-' + index }
value={ item.id }>
{ item.name }
</option>
);
});
return (
<select
ref="selection"
id={ this.props.id }
value={ this.state.selected }
onChange={ this.handleChange }
multiple={ this.state.multiple }>
<option value="">Select a list</option>
{ options }
</select>
);
}
});
var bulk_actions = [
{
name: 'move',
label: 'Move to list...'
label: 'Move to list...',
onSelect: function() {
return (
<ItemSelection
endpoint="segments"
id="move_to_segment" />
);
},
getData: function() {
return {
segment_id: ~~(jQuery('#move_to_segment').val())
}
}
},
{
name: 'add',
label: 'Add to list...'
label: 'Add to list...',
onSelect: function() {
return (
<ItemSelection
endpoint="segments"
id="add_to_segment" />
);
},
getData: function() {
return {
segment_id: ~~(jQuery('#add_to_segment').val())
}
}
},
{
name: 'remove',
label: 'Remove from list...'
label: 'Remove from list...',
onSelect: function() {
return (
<ItemSelection
endpoint="segments"
id="remove_from_segment" />
);
},
getData: function() {
return {
segment_id: ~~(jQuery('#remove_from_segment').val())
}
}
},
{
name: 'trash',
label: 'Trash'
}
];

View File

@ -29,7 +29,7 @@ class Handler {
}
private function setSearch() {
if($this->data['search'] === null) {
if(empty($this->data['search'])) {
return;
}
return $this->model->filter('search', $this->data['search']);
@ -47,6 +47,20 @@ class Handler {
return $this->model->filter('group', $this->data['group']);
}
function getSelection($ids = array()) {
if(!empty($ids)) {
$this->model->whereIn('id', $ids);
}
return $this->model;
}
function getSelectionIds($ids = array()) {
$subscribers = $this->getSelection($ids)->select('id')->findMany();
return array_map(function($subscriber) {
return (int)$subscriber->id;
}, $subscribers);
}
function get() {
return array(
'count' => $this->model->count(),
@ -55,7 +69,7 @@ class Handler {
'items' => $this->model
->offset($this->data['offset'])
->limit($this->data['limit'])
->find_array()
->findArray()
);
}
}

View File

@ -15,6 +15,13 @@ class Subscriber extends Model {
));
}
function delete() {
// delete all relations to segments
SubscriberSegment::where('subscriber_id', $this->id)->deleteMany();
parent::delete();
}
static function search($orm, $search = '') {
if(strlen(trim($search) === 0)) {
return $orm;

View File

@ -3,6 +3,7 @@ namespace MailPoet\Router;
use MailPoet\Listing;
use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment;
if(!defined('ABSPATH')) exit;
@ -29,6 +30,69 @@ class Subscribers {
wp_send_json($listing->get());
}
function bulk_action($data = array()) {
$action = $data['action'];
$selection = (isset($data['selection']) ? $data['selection'] : null);
$listing_data = $data['listing'];
$listing = new Listing\Handler(
\Model::factory('\MailPoet\Models\Subscriber'),
$listing_data
);
$selected = $listing->getSelection($selection);
$subscribers = $selected->findMany();
$result = false;
switch($action) {
case 'move':
$segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
foreach($subscribers as $subscriber) {
// remove subscriber from all segments
SubscriberSegment::where('subscriber_id', $subscriber->id)->deleteMany();
// create relation with segment
$association = SubscriberSegment::create();
$association->subscriber_id = $subscriber->id;
$association->segment_id = $segment_id;
$association->save();
}
$result = true;
break;
case 'remove':
$segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
// delete relations with segment
$subscriber_ids = $listing->getSelectionIds($selection);
$result = SubscriberSegment::whereIn('subscriber_id', $subscriber_ids)
->where('segment_id', $segment_id)
->deleteMany();
break;
case 'add':
$segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
foreach($subscribers as $subscriber) {
// create relation with segment
$association = SubscriberSegment::create();
$association->subscriber_id = $subscriber->id;
$association->segment_id = $segment_id;
$association->save();
}
$result = true;
break;
case 'trash':
// delete relations with all segments
$subscriber_ids = $listing->getSelectionIds($selection);
SubscriberSegment::whereIn('subscriber_id', $subscriber_ids)->deleteMany();
$result = $selected->deleteMany();
break;
}
wp_send_json($result);
}
function getAll() {
$collection = Subscriber::findArray();
wp_send_json($collection);