From c15359f1b47bee7fe372cd374da9356977c9231a Mon Sep 17 00:00:00 2001 From: Jonathan Labreuille Date: Tue, 6 Oct 2015 10:00:18 +0200 Subject: [PATCH] Listing filters --- assets/js/src/listing/bulk_actions.jsx | 6 +-- assets/js/src/listing/filters.jsx | 70 ++++++++++++++++++++++++-- assets/js/src/listing/listing.jsx | 18 ++++++- lib/Listing/Handler.php | 25 ++++++--- lib/Models/Subscriber.php | 48 +++++++++++++++++- lib/Router/Subscribers.php | 1 - package.json | 8 +-- tests/unit/Models/SubscriberCest.php | 6 +-- 8 files changed, 158 insertions(+), 24 deletions(-) diff --git a/assets/js/src/listing/bulk_actions.jsx b/assets/js/src/listing/bulk_actions.jsx index 8ce1f22a5e..6778bcd247 100644 --- a/assets/js/src/listing/bulk_actions.jsx +++ b/assets/js/src/listing/bulk_actions.jsx @@ -1,10 +1,8 @@ define([ - 'react', - 'mailpoet' + 'react' ], function( - React, - MailPoet + React ) { var ListingBulkActions = React.createClass({ getInitialState: function() { diff --git a/assets/js/src/listing/filters.jsx b/assets/js/src/listing/filters.jsx index f51385a70a..0a8582c519 100644 --- a/assets/js/src/listing/filters.jsx +++ b/assets/js/src/listing/filters.jsx @@ -1,8 +1,72 @@ -define(['react'], function(React) { - +define([ + 'react' +], +function( + React +) { var ListingFilters = React.createClass({ + handleFilterAction: function() { + var filters = this.props.filters.map(function(filter, index) { + var value = this.refs['filter-'+index].getDOMNode().value; + if(value) { + return { + 'name': filter.name, + 'value': value + }; + } + }.bind(this)); + return this.props.onSelectFilter(filters); + }, + handleChangeAction: function() { + return true; + }, render: function() { - return null; + var filters = this.props.filters + .filter(function(filter) { + return !( + filter.options.length === 0 + || ( + filter.options.length === 1 + && !filter.options[0].value + ) + ); + }) + .map(function(filter, i) { + return ( + + ); + }.bind(this)); + + var button = false; + + if(filters.length > 0) { + button = ( + + ); + } + + return ( +
+ { filters } + { button } +
+ ); } }); diff --git a/assets/js/src/listing/listing.jsx b/assets/js/src/listing/listing.jsx index c85c300967..bc8d970a7f 100644 --- a/assets/js/src/listing/listing.jsx +++ b/assets/js/src/listing/listing.jsx @@ -209,6 +209,7 @@ define( groups: [], group: 'all', filters: [], + filter: [], selected_ids: [], selection: false }; @@ -228,6 +229,7 @@ define( offset: (this.state.page - 1) * this.state.limit, limit: this.state.limit, group: this.state.group, + filter: this.state.filter, search: this.state.search, sort_by: this.state.sort_by, sort_order: this.state.sort_order @@ -270,6 +272,7 @@ define( data.listing = { offset: 0, limit: 0, + filter: this.state.filter, group: this.state.group, search: this.state.search, selection: selected_ids @@ -350,13 +353,21 @@ define( selected_ids: [] }); }, + handleFilter: function(filters) { + this.setState({ + filter: filters, + page: 1 + }, function() { + this.getItems(); + }.bind(this)); + }, handleGroup: function(group) { // reset search jQuery('#search_input').val(''); this.setState({ group: group, - filters: [], + filter: [], search: '', page: 1 }, function() { @@ -414,7 +425,10 @@ define( selection={ this.state.selection } selected_ids={ this.state.selected_ids } onBulkAction={ this.handleBulkAction } /> - + (isset($data['sort_order']) ? $data['sort_order'] : 'asc'), // grouping 'group' => (isset($data['group']) ? $data['group'] : null), + // filters + 'filter' => (isset($data['filter']) ? $data['filter'] : null), // selection 'selection' => (isset($data['selection']) ? $data['selection'] : null) ); $this->setSearch(); - $this->setOrder(); $this->setGroup(); + $this->setFilter(); + $this->setOrder(); } private function setSearch() { @@ -39,25 +42,35 @@ class Handler { private function setOrder() { return $this->model - ->{'order_by_'.$this->data['sort_order']}($this->data['sort_by']); + ->tableAlias('model') + ->{'order_by_'.$this->data['sort_order']}( + 'model.'.$this->data['sort_by'] + ); } private function setGroup() { if($this->data['group'] === null) { return; } - return $this->model->filter('group', $this->data['group']); + return $this->model->filter('groupBy', $this->data['group']); + } + + private function setFilter() { + if($this->data['filter'] === null) { + return; + } + return $this->model->filter('filterBy', $this->data['filter']); } function getSelection() { if(!empty($this->data['selection'])) { - $this->model->whereIn('id', $this->data['selection']); + $this->model->whereIn('model.id', $this->data['selection']); } return $this->model; } function getSelectionIds() { - $models = $this->getSelection()->select('id')->findMany(); + $models = $this->getSelection()->select('model.id')->findMany(); return array_map(function($model) { return (int)$model->id; }, $models); @@ -66,7 +79,7 @@ class Handler { function get() { return array( 'count' => $this->model->count(), - 'filters' => [], + 'filters' => $this->model->filter('filters'), 'groups' => $this->model->filter('groups'), 'items' => $this->model ->offset($this->data['offset']) diff --git a/lib/Models/Subscriber.php b/lib/Models/Subscriber.php index bf48e9ab0f..4b1b2cc1b3 100644 --- a/lib/Models/Subscriber.php +++ b/lib/Models/Subscriber.php @@ -33,6 +33,52 @@ class Subscriber extends Model { ); } + static function filters() { + $segments = Segment::orderByAsc('name')->findMany(); + $segment_list = array(); + + $segment_list[] = array( + 'label' => __('All lists'), + 'value' => '' + ); + + foreach($segments as $segment) { + $subscribers_count = $segment->subscribers()->count(); + if($subscribers_count > 0) { + $segment_list[] = array( + 'label' => sprintf('%s (%d)', $segment->name, $subscribers_count), + 'value' => $segment->id() + ); + } + } + + $filters = array( + array( + 'name' => 'segment', + 'options' => $segment_list + ) + ); + + return $filters; + } + + static function filterBy($orm, $filters = null) { + if(empty($filters)) { + return $orm; + } + + foreach($filters as $filter) { + if($filter['name'] === 'segment') { + $segment = Segment::findOne($filter['value']); + if($segment !== false) { + $orm = $segment->subscribers(); + } + } + } + + return $orm; + } + static function groups() { return array( array( @@ -58,7 +104,7 @@ class Subscriber extends Model { ); } - static function group($orm, $group = null) { + static function groupBy($orm, $group = null) { if($group === null or !in_array( $group, array('subscribed', 'unconfirmed', 'unsubscribed') diff --git a/lib/Router/Subscribers.php b/lib/Router/Subscribers.php index 9e2d51a35d..0d8c1e148a 100644 --- a/lib/Router/Subscribers.php +++ b/lib/Router/Subscribers.php @@ -28,7 +28,6 @@ class Subscribers { $data ); - $listing_data = $listing->get(); // fetch segments relations for each returned item diff --git a/package.json b/package.json index 3fa00ed9b5..994b988f0d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,10 @@ }, "napa": { "sticky-kit": "leafo/sticky-kit.git", - "interact.js": "taye/interact.js.git" + "interact.js": "taye/interact.js.git", + "export-loader": "webpack/exports-loader.git", + "import-loader": "webpack/imports-loader.git", + "expose-loader": "webpack/expose-loader.git" }, "dependencies": { "backbone": "1.2.3", @@ -36,9 +39,6 @@ "devDependencies": { "babel-core": "^5.8.22", "babel-loader": "^5.3.2", - "export-loader": "webpack/exports-loader.git", - "import-loader": "webpack/imports-loader.git", - "expose-loader": "webpack/expose-loader.git", "amd-inject-loader": "latest", "chai": "2.2.0", "chai-jq": "0.0.8", diff --git a/tests/unit/Models/SubscriberCest.php b/tests/unit/Models/SubscriberCest.php index 3db206081f..603044f48a 100644 --- a/tests/unit/Models/SubscriberCest.php +++ b/tests/unit/Models/SubscriberCest.php @@ -84,17 +84,17 @@ class SubscriberCest { } function itHasAGroupFilter() { - $subscribers = Subscriber::filter('group', 'unconfirmed')->findMany(); + $subscribers = Subscriber::filter('groupBy', 'unconfirmed')->findMany(); foreach($subscribers as $subscriber) { expect($subscriber->status)->equals('unconfirmed'); } - $subscribers = Subscriber::filter('group', 'subscribed')->findMany(); + $subscribers = Subscriber::filter('groupBy', 'subscribed')->findMany(); foreach($subscribers as $subscriber) { expect($subscriber->status)->equals('subscribed'); } - $subscribers = Subscriber::filter('group', 'unsubscribed')->findMany(); + $subscribers = Subscriber::filter('groupBy', 'unsubscribed')->findMany(); foreach($subscribers as $subscriber) { expect($subscriber->status)->equals('unsubscribed'); }