This commit is contained in:
Jonathan Labreuille
2015-08-25 18:51:47 +02:00
committed by marco
parent 5b93e1c8a6
commit 097b638e6b
7 changed files with 182 additions and 69 deletions

View File

@ -7,11 +7,4 @@
@require 'notice' @require 'notice'
@require 'validation_engine' @require 'validation_engine'
@require 'form_editor' @require 'form_editor'
.infinite-scroll-example__scrollable-parent {
height: 500px;
overflow-y: scroll;
position: relative;
}

View File

@ -40,10 +40,11 @@ define('subscribers.listing',
<input <input
type="search" type="search"
ref="search" ref="search"
id="search_input" /> id="search_input"
defaultValue={this.props.search} />
<input <input
type="submit" type="submit"
value="Search" defaultValue="Search"
className="button" /> className="button" />
</p> </p>
</form> </form>
@ -60,10 +61,80 @@ define('subscribers.listing',
}); });
var ListingPages = React.createClass({ var ListingPages = React.createClass({
setFirstPage: function() {
this.props.onSetPage(1);
},
setLastPage: function() {
var last_page = Math.ceil(this.props.count / this.props.limit);
this.props.onSetPage(last_page);
},
setPreviousPage: function() {
this.props.onSetPage(this.getPageValue(this.props.page - 1));
},
setNextPage: function() {
this.props.onSetPage(this.getPageValue(this.props.page + 1));
},
getPageValue: function(page) {
var last_page = Math.ceil(this.props.count / this.props.limit);
return Math.min(Math.max(1, Math.abs(~~page)), last_page);
},
handleSetPage: function() {
this.props.onSetPage(
this.getPageValue(this.refs.page.getDOMNode().value)
);
},
render: function() { render: function() {
return ( return (
<div className="tablenav-pages"> <div className="tablenav-pages">
<span className="displaying-num">{this.props.items.length} item(s)</span> <span className="displaying-num">{this.props.count} item(s)</span>
<span className="pagination-links">
<a href="javascript:;"
onClick={this.setFirstPage}
className="first-page">
<span className="screen-reader-text">First page</span>
<span aria-hidden="true">«</span>
</a>
<a href="javascript:;"
onClick={this.setPreviousPage}
className="prev-page">
<span className="screen-reader-text">Previous page</span>
<span aria-hidden="true"></span>
</a>
<span className="paging-input">
<label
className="screen-reader-text"
htmlFor="current-page-selector">Current Page</label>
<input
type="text"
onChange={this.handleSetPage}
aria-describedby="table-paging"
size="1"
ref="page"
value={this.props.page}
name="paged"
id="current-page-selector"
className="current-page" />
&nbsp;of&nbsp;
<span className="total-pages">
{Math.ceil(this.props.count / this.props.limit)}
</span>
</span>
<a href="javascript:;"
onClick={this.setNextPage}
className="next-page">
<span className="screen-reader-text">Next page</span>
<span aria-hidden="true"></span>
</a>
<a href="javascript:;"
onClick={this.setLastPage}
className="last-page">
<span className="screen-reader-text">Last page</span>
<span aria-hidden="true">»</span>
</a>
</span>
</div> </div>
); );
} }
@ -148,7 +219,7 @@ define('subscribers.listing',
Select { this.props.item.email }</label> Select { this.props.item.email }</label>
<input <input
type="checkbox" type="checkbox"
value={ this.props.item.id } defaultValue={ this.props.item.id }
name="item[]" id="cb-select-1" /> name="item[]" id="cb-select-1" />
</th> </th>
<td className="title column-title has-row-actions column-primary page-title"> <td className="title column-title has-row-actions column-primary page-title">
@ -205,6 +276,7 @@ define('subscribers.listing',
return { return {
search: '', search: '',
page: 1, page: 1,
count: 0,
limit: 10, limit: 10,
sort_by: 'email', sort_by: 'email',
sort_order: 'asc', sort_order: 'asc',
@ -218,52 +290,47 @@ define('subscribers.listing',
MailPoet.Ajax.post({ MailPoet.Ajax.post({
endpoint: 'subscribers', endpoint: 'subscribers',
action: 'get', action: 'get',
data: {
offset: (this.state.page - 1) * this.state.limit,
limit: this.state.limit,
search: this.state.search,
sort_by: this.state.sort_by,
sort_order: this.state.sort_order
},
onSuccess: function(response) { onSuccess: function(response) {
if(this.isMounted()) { if(this.isMounted()) {
this.setState({ this.setState({
items: response items: response.items,
count: response.count
}); });
} }
}.bind(this) }.bind(this)
}); });
}, },
handleSearch: function(search) { handleSearch: function(search) {
this.setState({ search: search }); this.setState({ search: search }, function() {
this.getItems();
}.bind(this));
}, },
handleSort: function(sort_by, sort_order = 'asc') { handleSort: function(sort_by, sort_order = 'asc') {
this.setState({ this.setState({
sort_by: sort_by, sort_by: sort_by,
sort_order: sort_order sort_order: sort_order
}); }, function() {
this.getItems();
}.bind(this));
},
handleSetPage: function(page) {
this.setState({ page: page }, function() {
this.getItems();
}.bind(this));
}, },
render: function() { render: function() {
var items = this.state.items, var items = this.state.items,
search = this.state.search.trim().toLowerCase(),
sort_by = this.state.sort_by, sort_by = this.state.sort_by,
sort_order = this.state.sort_order; sort_order = this.state.sort_order;
// search // set sortable columns
if(search.length > 0) {
items = items.filter(function(item){
return item.email.toLowerCase().match(search)
|| item.first_name.toLowerCase().match(search)
|| item.last_name.toLowerCase().match(search);
});
}
// sorting
items = items.sort(function(a, b) {
if(a[sort_by] === b[sort_by]) {
return 0;
} else {
if(sort_order === 'asc') {
return (a[sort_by] > b[sort_by]) ? 1 : -1;
} else {
return (a[sort_by] < b[sort_by]) ? 1 : -1;
}
}
});
columns = columns.map(function(column) { columns = columns.map(function(column) {
column.sorted = (column.name === sort_by) ? sort_order : false; column.sorted = (column.name === sort_by) ? sort_order : false;
return column; return column;
@ -271,10 +338,18 @@ define('subscribers.listing',
return ( return (
<div> <div>
<ListingSearch onSearch={this.handleSearch} /> <ListingGroups />
<ListingSearch
onSearch={this.handleSearch}
search={this.state.search} />
<div className="tablenav top clearfix"> <div className="tablenav top clearfix">
<ListingGroups /> <ListingBulkActions />
<ListingPages items={items} /> <ListingFilters />
<ListingPages
count={this.state.count}
page={this.state.page}
limit={this.state.limit}
onSetPage={this.handleSetPage} />
</div> </div>
<table className="wp-list-table widefat fixed"> <table className="wp-list-table widefat fixed">
<thead> <thead>
@ -299,8 +374,12 @@ define('subscribers.listing',
</table> </table>
<div className="tablenav bottom"> <div className="tablenav bottom">
<ListingGroups /> <ListingBulkActions />
<ListingPages items={items} /> <ListingPages
count={this.state.count}
page={this.state.page}
limit={this.state.limit}
onSetPage={this.handleSetPage} />
</div> </div>
</div> </div>
); );
@ -324,10 +403,6 @@ define('subscribers.listing',
label: 'Lastname', label: 'Lastname',
sortable: true sortable: true
}, },
{
name: 'status',
label: 'Status'
},
{ {
name: 'created_at', name: 'created_at',
label: 'Subscribed on', label: 'Subscribed on',
@ -349,16 +424,4 @@ define('subscribers.listing',
); );
} }
} }
); );
/*
<ListingGroups />
<ListingSearch />
<ListingBulkActions />
<ListingFilters />
<ListingPages />
<ListingItems />
<ListingBulkActions />
<ListingPages />
*/

View File

@ -42,10 +42,50 @@ define('subscribers.table',
}; };
}, },
_renderLoadingMessage: function() {
if (this.state.loading) {
return (
<p>
Loading {this.state.limit} more items
</p>
);
} else {
return (
<p>{this.state.items.length} items</p>
);
}
},
_renderItems: function() { _renderItems: function() {
return this.state.items.map(function(subscriber, index) { return this.state.items.map(function(subscriber, index) {
return ( return (
<p key={index}>{subscriber.email}</p> <tr>
<th className="check-column" scope="row">
<label htmlFor="cb-select-1" className="screen-reader-text">
Select { subscriber.email }</label>
<input
type="checkbox"
value={ subscriber.id }
name="item[]" id="cb-select-1" />
</th>
<td className="title column-title has-row-actions column-primary page-title">
<strong>
<a className="row-title">{ subscriber.email }</a>
</strong>
</td>
<td>
{ subscriber.first_name }
</td>
<td>
{ subscriber.last_name }
</td>
<td className="date column-date">
<abbr title="">{ subscriber.created_at }</abbr>
</td>
<td className="date column-date">
<abbr title="">{ subscriber.updated_at }</abbr>
</td>
</tr>
); );
}); });
}, },
@ -55,16 +95,15 @@ define('subscribers.table',
return ( return (
<Waypoint <Waypoint
onEnter={this._loadMoreItems} onEnter={this._loadMoreItems}
threshold={2.0} /> threshold={0.8} />
); );
} }
}, },
render: function() { render: function() {
//MailPoet.Modal.loading(this.state.loading);
return ( return (
<div> <div>
<p>{this.state.items.length} items</p> {this._renderLoadingMessage()}
<div className="infinite-scroll-example"> <div className="infinite-scroll-example">
<div className="infinite-scroll-example__scrollable-parent"> <div className="infinite-scroll-example__scrollable-parent">
{this._renderItems()} {this._renderItems()}

View File

@ -28,6 +28,7 @@ class Initializer {
\ORM::configure(Env::$db_source_name); \ORM::configure(Env::$db_source_name);
\ORM::configure('username', Env::$db_username); \ORM::configure('username', Env::$db_username);
\ORM::configure('password', Env::$db_password); \ORM::configure('password', Env::$db_password);
\ORM::configure('logging', WP_DEBUG);
$subscribers = Env::$db_prefix . 'subscribers'; $subscribers = Env::$db_prefix . 'subscribers';
$settings = Env::$db_prefix . 'settings'; $settings = Env::$db_prefix . 'settings';

View File

@ -13,7 +13,26 @@ class Subscribers {
$data = $_POST['data']; $data = $_POST['data'];
$offset = (isset($data['offset']) ? (int)$data['offset'] : 0); $offset = (isset($data['offset']) ? (int)$data['offset'] : 0);
$limit = (isset($data['limit']) ? (int)$data['limit'] : 50); $limit = (isset($data['limit']) ? (int)$data['limit'] : 50);
$collection = Subscriber::offset($offset)->limit($limit)->find_array(); $search = (isset($data['search']) ? $data['search'] : null);
$sort_by = (isset($data['sort_by']) ? $data['sort_by'] : 'id');
$sort_order = (isset($data['sort_order']) ? $data['sort_order'] : 'desc');
$collection = Subscriber::{'order_by_'.$sort_order}($sort_by);
if($search !== null) {
$collection->where_raw(
'(`email` LIKE ? OR `first_name` LIKE ? OR `last_name` LIKE ?)',
array('%'.$search.'%', '%'.$search.'%', '%'.$search.'%')
);
}
$collection = array(
'count' => $collection->count(),
'items' => $collection
->offset($offset)
->limit($limit)
->find_array()
);
} else { } else {
$collection = Subscriber::find_array(); $collection = Subscriber::find_array();
} }

View File

@ -2,6 +2,5 @@
<% block content %> <% block content %>
<h1><%= __('Subscribers') %></h1> <h1><%= __('Subscribers') %></h1>
<!-- <div id="mailpoet_subscribers_listing"></div> --> <div id="mailpoet_subscribers_listing"></div>
<div id="example"></div>
<% endblock %> <% endblock %>

View File

@ -36,8 +36,7 @@ config.push(_.extend({}, baseConfig, {
vendor: ['handlebars', 'handlebars_helpers'], vendor: ['handlebars', 'handlebars_helpers'],
mailpoet: ['mailpoet', 'ajax', 'modal', 'notice'], mailpoet: ['mailpoet', 'ajax', 'modal', 'notice'],
admin: [ admin: [
'subscribers/table.jsx', 'subscribers/listing.jsx',
// 'subscribers/listing.jsx',
'settings.jsx', 'settings.jsx',
'subscribers.jsx', 'subscribers.jsx',
'newsletters_list.jsx', 'newsletters_list.jsx',