Segment listing

- fixed duplicate entry in Robofile for editor styles
- added Segment menu
- added Segment listing
- added listing methods to Segment model
- fixed syntax in both Segment & Subscriber models (MAX LINE 80!!!)
This commit is contained in:
Jonathan Labreuille
2015-09-04 13:02:23 +02:00
parent 87c529a6c1
commit 7370d19be3
11 changed files with 270 additions and 17 deletions

View File

@ -6,8 +6,7 @@ class RoboFile extends \Robo\Tasks {
'assets/css/src/admin.styl',
'assets/css/src/newsletter_editor/newsletter_editor.styl',
'assets/css/src/public.styl',
'assets/css/src/rtl.styl',
'assets/css/src/newsletter_editor/newsletter_editor.styl'
'assets/css/src/rtl.styl'
);
private $js_files = array(

View File

@ -0,0 +1,101 @@
define(
'list',
[
'react',
'jquery',
'mailpoet',
'listing/listing.jsx',
'classnames'
],
function(
React,
jQuery,
MailPoet,
Listing,
classNames
) {
var columns = [
{
name: 'name',
label: 'Name',
sortable: true
},
{
name: 'created_at',
label: 'Created on',
sortable: true
},
{
name: 'updated_at',
label: 'Last modified on',
sortable: true
}
];
var actions = [
];
var List = React.createClass({
getItems: function(listing) {
MailPoet.Ajax.post({
endpoint: 'segments',
action: 'get',
data: {
offset: (listing.state.page - 1) * listing.state.limit,
limit: listing.state.limit,
group: listing.state.group,
search: listing.state.search,
sort_by: listing.state.sort_by,
sort_order: listing.state.sort_order
},
onSuccess: function(response) {
if(listing.isMounted()) {
listing.setState({
items: response.items || [],
filters: response.filters || [],
groups: response.groups || [],
count: response.count || 0,
loading: false
});
}
}.bind(listing)
});
},
renderItem: function(segment) {
var rowClasses = classNames(
'manage-column',
'column-primary',
'has-row-actions'
);
return (
<div>
<td className={ rowClasses }>
<strong>
<a>{ segment.name }</a>
</strong>
</td>
<td className="column-date" data-colname="Subscribed on">
<abbr>{ segment.created_at }</abbr>
</td>
<td className="column-date" data-colname="Last modified on">
<abbr>{ segment.updated_at }</abbr>
</td>
</div>
);
},
render: function() {
return (
<Listing
onRenderItem={this.renderItem}
items={this.getItems}
columns={columns}
actions={actions} />
);
}
});
return List;
}
);

View File

@ -0,0 +1,54 @@
define(
'segments',
[
'react',
'react-router',
'segments/list.jsx'
],
function(
React,
Router,
List
) {
var DefaultRoute = Router.DefaultRoute;
var Link = Router.Link;
var Route = Router.Route;
var RouteHandler = Router.RouteHandler;
var App = React.createClass({
render: function() {
return (
<div>
<h1>
{ MailPoetI18n.pageTitle }
<span>
<Link className="add-new-h2" to="list">
{ MailPoetI18n.pageTitle }
</Link>
</span>
</h1>
<RouteHandler/>
</div>
);
}
});
var routes = (
<Route name="app" path="/" handler={App}>
<Route name="list" handler={List} />
<DefaultRoute handler={List} />
</Route>
);
var hook = document.getElementById('segments');
if (hook) {
Router.run(routes, function(Handler, state) {
React.render(
<Handler params={state.params} query={state.query} />,
hook
);
});
}
});

View File

@ -21,9 +21,11 @@ define(
return (
<div>
<h1>
{ MailPoetI18n.pageTitle }
{ MailPoetI18n.pageTitle }
<span>
<Link className="add-new-h2" to="list">Subscribers</Link>
<Link className="add-new-h2" to="list">
{ MailPoetI18n.pageTitle }
</Link>
</span>
</h1>

View File

@ -28,32 +28,40 @@ class Menu {
);
add_submenu_page(
'mailpoet',
'Newsletters',
'Newsletters',
__('Newsletters'),
__('Newsletters'),
'manage_options',
'mailpoet-newsletters',
array($this, 'newsletters')
);
add_submenu_page(
'mailpoet',
'Subscribers',
'Subscribers',
__('Subscribers'),
__('Subscribers'),
'manage_options',
'mailpoet-subscribers',
array($this, 'subscribers')
);
add_submenu_page(
'mailpoet',
'Settings',
'Settings',
__('Segments'),
__('Segments'),
'manage_options',
'mailpoet-segments',
array($this, 'segments')
);
add_submenu_page(
'mailpoet',
__('Settings'),
__('Settings'),
'manage_options',
'mailpoet-settings',
array($this, 'settings')
);
add_submenu_page(
'mailpoet',
'Newsletter editor',
'Newsletter editor',
__('Newsletter editor'),
__('Newsletter editor'),
'manage_options',
'mailpoet-newsletter-editor',
array($this, 'newsletterEditor')
@ -75,6 +83,11 @@ class Menu {
echo $this->renderer->render('subscribers.html', $data);
}
function segments() {
$data = array();
echo $this->renderer->render('segments.html', $data);
}
function newsletters() {
$data = array();
echo $this->renderer->render('newsletters.html', $data);

View File

@ -30,6 +30,28 @@ class Segment extends Model {
}
public function subscribers() {
return $this->has_many_through(__NAMESPACE__ . '\Subscriber', __NAMESPACE__ . '\SubscriberSegment', 'segment_id', 'subscriber_id');
return $this->has_many_through(
__NAMESPACE__.'\Subscriber',
__NAMESPACE__.'\SubscriberSegment',
'segment_id',
'subscriber_id'
);
}
static function search($orm, $search = '') {
return $orm->where_like('name', '%'.$search.'%');
}
static function groups() {
return array(
array(
'name' => 'all',
'label' => __('All'),
'count' => Segment::count()
)
);
}
static function group($orm, $group = null) {
}
}

View File

@ -63,6 +63,11 @@ class Subscriber extends Model {
}
public function segments() {
return $this->has_many_through(__NAMESPACE__ . '\Segment', __NAMESPACE__ . '\SubscriberSegment', 'subscriber_id', 'segment_id');
return $this->has_many_through(
__NAMESPACE__.'\Segment',
__NAMESPACE__.'\SubscriberSegment',
'subscriber_id',
'segment_id'
);
}
}

View File

@ -37,7 +37,7 @@ class Router {
}
function securityCheck() {
if (!current_user_can('manage_options')) {die();}
if (!wp_verify_nonce($_POST['token'], 'mailpoet_token')) {die();}
if(!current_user_can('manage_options')) { die(); }
if(!wp_verify_nonce($_POST['token'], 'mailpoet_token')) { die(); }
}
}

44
lib/Router/Segments.php Normal file
View File

@ -0,0 +1,44 @@
<?php
namespace MailPoet\Router;
use \MailPoet\Models\Segment;
use \MailPoet\Listing;
if(!defined('ABSPATH')) exit;
class Segments {
function __construct() {
}
function get($data = array()) {
$listing = new Listing\Handler(
\Model::factory('\MailPoet\Models\Segment'),
$data
);
wp_send_json($listing->get());
}
function getAll() {
$collection = Segment::find_array();
wp_send_json($collection);
}
function save($args) {
$model = Segment::create();
$model->hydrate($args);
$saved = $model->save();
if(!$saved) {
wp_send_json($model->getValidationErrors());
}
wp_send_json(true);
}
function update($args) {
}
function delete($id) {
}
}

12
views/segments.html Normal file
View File

@ -0,0 +1,12 @@
<% extends 'layout.html' %>
<% block content %>
<div id="segments"></div>
<%= localize({
'pageTitle': __('Segments'),
'searchLabel': __('Search'),
'loading': __('Loading segments...'),
'noRecordFound': __('No segments found.')
}) %>
<% endblock %>

View File

@ -62,7 +62,8 @@ config.push(_.extend({}, baseConfig, {
admin: [
'settings.jsx',
'subscribers/subscribers.jsx',
'newsletters/newsletters.jsx'
'newsletters/newsletters.jsx',
'segments/segments.jsx'
],
newsletter_editor: [
'underscore',