Listings: form

- fixed compileCSS so that it watches over all .styl files
- uniform "new" form for newsletters / segments / subscribers
- cleaned up jsx files
This commit is contained in:
Jonathan Labreuille
2015-09-04 16:41:04 +02:00
parent 7370d19be3
commit 9f37108b0b
11 changed files with 253 additions and 114 deletions

View File

@ -3,10 +3,8 @@
class RoboFile extends \Robo\Tasks { class RoboFile extends \Robo\Tasks {
private $css_files = array( private $css_files = array(
'assets/css/src/admin.styl', 'assets/css/src/*.styl',
'assets/css/src/newsletter_editor/newsletter_editor.styl', 'assets/css/src/**/*.styl'
'assets/css/src/public.styl',
'assets/css/src/rtl.styl'
); );
private $js_files = array( private $js_files = array(
@ -33,11 +31,16 @@ class RoboFile extends \Robo\Tasks {
$js_files = array_merge($js_files, glob($path)); $js_files = array_merge($js_files, glob($path));
}, $this->js_files); }, $this->js_files);
$css_files = array();
array_map(function($path) use(&$css_files) {
$css_files = array_merge($css_files, glob($path));
}, $this->css_files);
$this->taskWatch() $this->taskWatch()
->monitor($js_files, function() { ->monitor($js_files, function() {
$this->compileJs(); $this->compileJs();
}) })
->monitor($this->css_files, function() { ->monitor($css_files, function() {
$this->compileCss(); $this->compileCss();
}) })
->run(); ->run();
@ -53,12 +56,19 @@ class RoboFile extends \Robo\Tasks {
} }
function compileCss() { function compileCss() {
$css_files = array(
'assets/css/src/admin.styl',
'assets/css/src/newsletter_editor/newsletter_editor.styl',
'assets/css/src/public.styl',
'assets/css/src/rtl.styl'
);
$this->_exec(join(' ', array( $this->_exec(join(' ', array(
'./node_modules/stylus/bin/stylus', './node_modules/stylus/bin/stylus',
'--include ./node_modules', '--include ./node_modules',
'--include-css', '--include-css',
'-u nib', '-u nib',
join(' ', $this->css_files), join(' ', $css_files),
'-o assets/css/' '-o assets/css/'
))); )));
} }

View File

@ -6,3 +6,10 @@
// disable outline on link focus // disable outline on link focus
a:focus a:focus
outline: 0 none !important outline: 0 none !important
// success and error messages
.mailpoet_success
color: #090
.mailpoet_error
color: #900

View File

@ -176,17 +176,6 @@ body.mailpoet_modal_opened
background-color: #00ccff background-color: #00ccff
color: #fff color: #fff
// notices
.mailpoet_success,
.mailpoet_error
display: none
.mailpoet_success
color: #090
.mailpoet_error
color: #900
@media screen and (max-width: 782px) @media screen and (max-width: 782px)
#mailpoet_modal_overlay.mailpoet_panel_overlay #mailpoet_modal_overlay.mailpoet_panel_overlay
top: 46px top: 46px

View File

@ -1,77 +1,76 @@
define( define(
'form', 'newsletters_form',
[ [
'react', 'react',
'react-router',
'jquery', 'jquery',
'mailpoet' 'mailpoet'
], ],
function( function(
React, React,
Router,
jQuery, jQuery,
MailPoet MailPoet
) { ) {
var Form = React.createClass({ var Form = React.createClass({
mixins: [
Router.Navigation
],
getInitialState: function() { getInitialState: function() {
return { return {
disabled: false loading: false,
errors: []
}; };
}, },
handleSubmit: function(e) {
e.preventDefault();
this.setState({ loading: true });
post: function(data) {
MailPoet.Ajax.post({ MailPoet.Ajax.post({
endpoint: 'newsletters', endpoint: 'newsletters',
action: 'save', action: 'save',
data: data, data: {
onSuccess: function(response) { subject: React.findDOMNode(this.refs.subject).value,
}.bind(this) body: React.findDOMNode(this.refs.body).value
}) }
}).done(function(response) {
this.setState({ loading: false });
if(response === true) {
this.transitionTo('/');
} else {
this.setState({ errors: response });
}
}.bind(this));
}, },
handleSubmit: function(e) {
e.preventDefault();
this.setState({
disabled: true
});
var subject =
React.findDOMNode(this.refs.subject);
var body =
React.findDOMNode(this.refs.body);
if (!subject.value || !body.value) {
return;
}
this.post({
subject: subject.value,
body: body.value
});
subject.value = '';
body.value = '';
this.setState({
disabled: false
});
return;
},
render: function() { render: function() {
var errors = this.state.errors.map(function(error, index) {
return (
<p key={'error-'+index} className="mailpoet_error">{ error }</p>
);
});
return ( return (
<div> <form onSubmit={ this.handleSubmit }>
<h1>New</h1> { errors }
<form className="newslettersForm" onSubmit={this.handleSubmit}> <p>
<input type="text" placeholder="Subject" ref="subject" /> <input type="text" placeholder="Subject" ref="subject" />
<br /> </p>
<textarea placeholder="Body" ref="body" /> <p>
<br /> <input type="text" placeholder="Body" ref="body" />
<input type="submit" value="Save" disabled={this.state.locked} /> </p>
</form> <input
</div> className="button button-primary"
type="submit"
value="Save"
disabled={this.state.loading} />
</form>
); );
} }
}); });
return Form; return Form;
}); }
);

View File

@ -23,13 +23,9 @@ define(
return ( return (
<div> <div>
<h1> <h1>
{ MailPoetI18n.pageTitle } { MailPoetI18n.pageTitle }
<span> &nbsp;
<Link className="add-new-h2" to="list">Newsletters</Link> <Link className="add-new-h2" to="form">New</Link>
</span>
<span>
<Link className="add-new-h2" to="form">New</Link>
</span>
</h1> </h1>
<RouteHandler/> <RouteHandler/>
@ -40,14 +36,14 @@ define(
var routes = ( var routes = (
<Route name="app" path="/" handler={App}> <Route name="app" path="/" handler={App}>
<Route name="list" handler={List}/> <Route name="list" handler={List} />
<Route name="form" handler={Form}/> <Route name="form" handler={Form} />
<DefaultRoute handler={List}/> <DefaultRoute handler={List} />
</Route> </Route>
); );
var hook = document.getElementById('newsletters'); var hook = document.getElementById('newsletters');
if (hook) { if(hook) {
Router.run(routes, function(Handler, state) { Router.run(routes, function(Handler, state) {
React.render( React.render(
<Handler params={state.params} query={state.query} />, <Handler params={state.params} query={state.query} />,
@ -55,4 +51,5 @@ define(
); );
}); });
} }
}); }
);

View File

@ -0,0 +1,72 @@
define(
'segments_form',
[
'react',
'react-router',
'jquery',
'mailpoet'
],
function(
React,
Router,
jQuery,
MailPoet
) {
var Form = React.createClass({
mixins: [
Router.Navigation
],
getInitialState: function() {
return {
loading: false,
errors: []
};
},
handleSubmit: function(e) {
e.preventDefault();
this.setState({ loading: true });
MailPoet.Ajax.post({
endpoint: 'segments',
action: 'save',
data: {
name: React.findDOMNode(this.refs.name).value
}
}).done(function(response) {
this.setState({ loading: false });
if(response === true) {
this.transitionTo('/');
} else {
this.setState({ errors: response });
}
}.bind(this));
},
render: function() {
var errors = this.state.errors.map(function(error, index) {
return (
<p key={'error-'+index} className="mailpoet_error">{ error }</p>
);
});
return (
<form onSubmit={ this.handleSubmit }>
{ errors }
<p>
<input type="text" placeholder="Name" ref="name" />
</p>
<input
className="button button-primary"
type="submit"
value="Save"
disabled={this.state.loading} />
</form>
);
}
});
return Form;
}
);

View File

@ -1,5 +1,5 @@
define( define(
'list', 'segments_list',
[ [
'react', 'react',
'jquery', 'jquery',

View File

@ -3,12 +3,14 @@ define(
[ [
'react', 'react',
'react-router', 'react-router',
'segments/list.jsx' 'segments/list.jsx',
'segments/form.jsx'
], ],
function( function(
React, React,
Router, Router,
List List,
Form
) { ) {
var DefaultRoute = Router.DefaultRoute; var DefaultRoute = Router.DefaultRoute;
@ -22,11 +24,8 @@ define(
<div> <div>
<h1> <h1>
{ MailPoetI18n.pageTitle } { MailPoetI18n.pageTitle }
<span> &nbsp;
<Link className="add-new-h2" to="list"> <Link className="add-new-h2" to="form">New</Link>
{ MailPoetI18n.pageTitle }
</Link>
</span>
</h1> </h1>
<RouteHandler/> <RouteHandler/>
@ -38,12 +37,13 @@ define(
var routes = ( var routes = (
<Route name="app" path="/" handler={App}> <Route name="app" path="/" handler={App}>
<Route name="list" handler={List} /> <Route name="list" handler={List} />
<Route name="form" handler={Form} />
<DefaultRoute handler={List} /> <DefaultRoute handler={List} />
</Route> </Route>
); );
var hook = document.getElementById('segments'); var hook = document.getElementById('segments');
if (hook) { if(hook) {
Router.run(routes, function(Handler, state) { Router.run(routes, function(Handler, state) {
React.render( React.render(
<Handler params={state.params} query={state.query} />, <Handler params={state.params} query={state.query} />,
@ -51,4 +51,5 @@ define(
); );
}); });
} }
}); }
);

View File

@ -0,0 +1,80 @@
define(
'subscribers_form',
[
'react',
'react-router',
'jquery',
'mailpoet'
],
function(
React,
Router,
jQuery,
MailPoet
) {
var Form = React.createClass({
mixins: [
Router.Navigation
],
getInitialState: function() {
return {
loading: false,
errors: []
};
},
handleSubmit: function(e) {
e.preventDefault();
this.setState({ loading: true });
MailPoet.Ajax.post({
endpoint: 'subscribers',
action: 'save',
data: {
email: React.findDOMNode(this.refs.email).value,
firstname: React.findDOMNode(this.refs.firstname).value,
lastname: React.findDOMNode(this.refs.lastname).value
}
}).done(function(response) {
this.setState({ loading: false });
if(response === true) {
this.transitionTo('/');
} else {
this.setState({ errors: response });
}
}.bind(this));
},
render: function() {
var errors = this.state.errors.map(function(error, index) {
return (
<p key={'error-'+index} className="mailpoet_error">{ error }</p>
);
});
return (
<form onSubmit={ this.handleSubmit }>
{ errors }
<p>
<input type="text" placeholder="Email" ref="email" />
</p>
<p>
<input type="text" placeholder="First name" ref="firstname" />
</p>
<p>
<input type="text" placeholder="Last name" ref="lastname" />
</p>
<input
className="button button-primary"
type="submit"
value="Save"
disabled={this.state.loading} />
</form>
);
}
});
return Form;
}
);

View File

@ -1,5 +1,5 @@
define( define(
'list', 'subscribers_list',
[ [
'react', 'react',
'jquery', 'jquery',
@ -53,27 +53,10 @@ define(
name: 'move', name: 'move',
label: 'Move to list...', label: 'Move to list...',
onSelect: function(e) { onSelect: function(e) {
// display list selector console.log(e);
jQuery(e.target).after(
'<select id="bulk_action_list">'+
'<option value="">Select a list</option>'+
'<option value="1">List #1</option>'+
'<option value="2">List #2</option>'+
'<option value="3">List #3</option>'+
'</select>'
);
}, },
onApply: function(selected) { onApply: function(selected) {
var list = jQuery('#bulk_action_list').val(); console.log(selected);
MailPoet.Ajax.post({
endpoint: 'subscribers',
action: 'move',
data: {
selected: selected,
list: list
}
});
} }
}, },
{ {

View File

@ -3,12 +3,14 @@ define(
[ [
'react', 'react',
'react-router', 'react-router',
'subscribers/list.jsx' 'subscribers/list.jsx',
'subscribers/form.jsx'
], ],
function( function(
React, React,
Router, Router,
List List,
Form
) { ) {
var DefaultRoute = Router.DefaultRoute; var DefaultRoute = Router.DefaultRoute;
@ -22,11 +24,8 @@ define(
<div> <div>
<h1> <h1>
{ MailPoetI18n.pageTitle } { MailPoetI18n.pageTitle }
<span> &nbsp;
<Link className="add-new-h2" to="list"> <Link className="add-new-h2" to="form">New</Link>
{ MailPoetI18n.pageTitle }
</Link>
</span>
</h1> </h1>
<RouteHandler/> <RouteHandler/>
@ -38,6 +37,7 @@ define(
var routes = ( var routes = (
<Route name="app" path="/" handler={App}> <Route name="app" path="/" handler={App}>
<Route name="list" handler={List} /> <Route name="list" handler={List} />
<Route name="form" handler={Form} />
<DefaultRoute handler={List} /> <DefaultRoute handler={List} />
</Route> </Route>
); );
@ -51,4 +51,5 @@ define(
); );
}); });
} }
}); }
);