Listing & form
- improved Listing in order to make it more DRY - form builder with all field types - added support for data array in ValidModel->set() - updated models to comply with Listing & Form methods
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
.mailpoet_listing_loading tbody tr,
|
||||
.mailpoet_form_loading
|
||||
.mailpoet_form_loading tbody tr
|
||||
opacity: 0.2;
|
||||
|
||||
.widefat tfoot td.mailpoet_check_column,
|
||||
|
@ -3,17 +3,191 @@ define(
|
||||
'react',
|
||||
'mailpoet',
|
||||
'classnames',
|
||||
'react-router'
|
||||
'react-router',
|
||||
'react-checkbox-group'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
MailPoet,
|
||||
classNames,
|
||||
Router
|
||||
Router,
|
||||
CheckboxGroup
|
||||
) {
|
||||
|
||||
|
||||
var FormFieldSelect = React.createClass({
|
||||
render: function() {
|
||||
var options =
|
||||
Object.keys(this.props.field.values).map(function(value, index) {
|
||||
return (
|
||||
<option
|
||||
key={ 'option-' + index }
|
||||
value={ value }>
|
||||
{ this.props.field.values[value] }
|
||||
</option>
|
||||
);
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
return (
|
||||
<select
|
||||
name={ this.props.field.name }
|
||||
id={ 'field_'+this.props.field.name }
|
||||
value={ this.props.item[this.props.field.name] }
|
||||
onChange={ this.props.onValueChange } >
|
||||
{options}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var FormFieldRadio = React.createClass({
|
||||
render: function() {
|
||||
var selected_value = this.props.item[this.props.field.name];
|
||||
var count = Object.keys(this.props.field.values).length;
|
||||
|
||||
var options = Object.keys(this.props.field.values).map(
|
||||
function(value, index) {
|
||||
return (
|
||||
<p key={ 'radio-' + index }>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
checked={ selected_value === value }
|
||||
value={ value }
|
||||
onChange={ this.props.onValueChange }
|
||||
name={ this.props.field.name } />
|
||||
{ this.props.field.values[value] }
|
||||
</label>
|
||||
</p>
|
||||
);
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ options }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var FormFieldCheckbox = React.createClass({
|
||||
render: function() {
|
||||
var selected_values = this.props.item[this.props.field.name] || '';
|
||||
if(
|
||||
selected_values !== undefined
|
||||
&& selected_values.constructor !== Array
|
||||
) {
|
||||
selected_values = selected_values.split(';').map(function(value) {
|
||||
return value.trim();
|
||||
});
|
||||
}
|
||||
var count = Object.keys(this.props.field.values).length;
|
||||
|
||||
var options = Object.keys(this.props.field.values).map(
|
||||
function(value, index) {
|
||||
return (
|
||||
<p key={ 'checkbox-' + index }>
|
||||
<label>
|
||||
<input type="checkbox" value={ value } />
|
||||
{ this.props.field.values[value] }
|
||||
</label>
|
||||
</p>
|
||||
);
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
return (
|
||||
<CheckboxGroup
|
||||
name={ this.props.field.name }
|
||||
value={ selected_values }
|
||||
ref={ this.props.field.name }
|
||||
onChange={ this.handleValueChange }>
|
||||
{ options }
|
||||
</CheckboxGroup>
|
||||
);
|
||||
},
|
||||
handleValueChange: function() {
|
||||
var field = this.props.field.name;
|
||||
var group = this.refs[field];
|
||||
var selected_values = [];
|
||||
|
||||
if(group !== undefined) {
|
||||
selected_values = group.getCheckedValues();
|
||||
}
|
||||
|
||||
return this.props.onValueChange({
|
||||
target: {
|
||||
name: field,
|
||||
value: selected_values.join(';')
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var FormFieldText = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<input
|
||||
type="text"
|
||||
className="regular-text"
|
||||
name={ this.props.field.name }
|
||||
id={ 'field_'+this.props.field.name }
|
||||
value={ this.props.item[this.props.field.name] }
|
||||
onChange={ this.props.onValueChange } />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var FormFieldTextarea = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<textarea
|
||||
type="text"
|
||||
className="regular-text"
|
||||
name={ this.props.field.name }
|
||||
id={ 'field_'+this.props.field.name }
|
||||
value={ this.props.item[this.props.field.name] }
|
||||
onChange={ this.props.onValueChange } />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var FormField = React.createClass({
|
||||
render: function() {
|
||||
|
||||
var description = false;
|
||||
if(this.props.field.description) {
|
||||
description = (
|
||||
<p className="description">{ this.props.field.description }</p>
|
||||
);
|
||||
}
|
||||
|
||||
var field = false;
|
||||
|
||||
switch(this.props.field.type) {
|
||||
case 'text':
|
||||
field = (<FormFieldText {...this.props} />);
|
||||
break;
|
||||
|
||||
case 'textarea':
|
||||
field = (<FormFieldTextarea {...this.props} />);
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
field = (<FormFieldSelect {...this.props} />);
|
||||
break;
|
||||
|
||||
case 'radio':
|
||||
field = (<FormFieldRadio {...this.props} />);
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
field = (<FormFieldCheckbox {...this.props} />);
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<th scope="row">
|
||||
@ -22,12 +196,8 @@ define(
|
||||
>{ this.props.field.label }</label>
|
||||
</th>
|
||||
<td>
|
||||
<input
|
||||
type="text"
|
||||
name={ this.props.field.name }
|
||||
id={ 'field_'+this.props.field.name }
|
||||
value={ this.props.item[this.props.field.name] }
|
||||
onChange={ this.props.onValueChange } />
|
||||
{ field }
|
||||
{ description }
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
@ -66,7 +236,7 @@ define(
|
||||
this.setState({ loading: true });
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'subscribers',
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'get',
|
||||
data: { id: id }
|
||||
}).done(function(response) {
|
||||
@ -91,7 +261,7 @@ define(
|
||||
this.setState({ loading: true });
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'subscribers',
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'save',
|
||||
data: this.state.item
|
||||
}).done(function(response) {
|
||||
@ -100,19 +270,21 @@ define(
|
||||
if(response === true) {
|
||||
this.transitionTo('/');
|
||||
if(this.props.params.id !== undefined) {
|
||||
MailPoet.Notice.success('Subscriber succesfully updated!');
|
||||
this.props.messages['updated']();
|
||||
} else {
|
||||
MailPoet.Notice.success('Subscriber succesfully added!');
|
||||
this.props.messages['created']();
|
||||
}
|
||||
|
||||
} else {
|
||||
this.setState({ errors: response });
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
handleValueChange: function(e) {
|
||||
var item = this.state.item;
|
||||
item[e.target.name] = e.target.value;
|
||||
var item = this.state.item,
|
||||
field = e.target.name;
|
||||
|
||||
item[field] = e.target.value;
|
||||
|
||||
this.setState({
|
||||
item: item
|
||||
});
|
||||
@ -121,7 +293,9 @@ define(
|
||||
render: function() {
|
||||
var errors = this.state.errors.map(function(error, index) {
|
||||
return (
|
||||
<p key={'error-'+index} className="mailpoet_error">{ error }</p>
|
||||
<p key={ 'error-'+index } className="mailpoet_error">
|
||||
{ error }
|
||||
</p>
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -159,7 +159,30 @@ define(
|
||||
},
|
||||
getItems: function() {
|
||||
this.setState({ loading: true });
|
||||
this.props.items.bind(null, this)();
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: this.props.endpoint,
|
||||
action: 'listing',
|
||||
data: {
|
||||
offset: (this.state.page - 1) * this.state.limit,
|
||||
limit: this.state.limit,
|
||||
group: this.state.group,
|
||||
search: this.state.search,
|
||||
sort_by: this.state.sort_by,
|
||||
sort_order: this.state.sort_order
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
if(this.isMounted()) {
|
||||
this.setState({
|
||||
items: response.items || [],
|
||||
filters: response.filters || [],
|
||||
groups: response.groups || [],
|
||||
count: response.count || 0,
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
handleSearch: function(search) {
|
||||
this.setState({
|
||||
|
@ -1,75 +1,50 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'react-router',
|
||||
'jquery',
|
||||
'mailpoet'
|
||||
'mailpoet',
|
||||
'form/form.jsx'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
Router,
|
||||
jQuery,
|
||||
MailPoet
|
||||
MailPoet,
|
||||
Form
|
||||
) {
|
||||
|
||||
var Form = React.createClass({
|
||||
mixins: [
|
||||
Router.Navigation
|
||||
],
|
||||
getInitialState: function() {
|
||||
return {
|
||||
loading: false,
|
||||
errors: []
|
||||
};
|
||||
var fields = [
|
||||
{
|
||||
name: 'subject',
|
||||
label: 'Subject',
|
||||
type: 'text'
|
||||
},
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
{
|
||||
name: 'body',
|
||||
label: 'Body',
|
||||
type: 'textarea'
|
||||
}
|
||||
];
|
||||
|
||||
this.setState({ loading: true });
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'save',
|
||||
data: {
|
||||
subject: React.findDOMNode(this.refs.subject).value,
|
||||
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));
|
||||
var messages = {
|
||||
updated: function() {
|
||||
MailPoet.Notice.success('Newsletter succesfully updated!');
|
||||
},
|
||||
created: function() {
|
||||
MailPoet.Notice.success('Newsletter succesfully added!');
|
||||
}
|
||||
};
|
||||
|
||||
var NewsletterForm = React.createClass({
|
||||
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="Subject" ref="subject" />
|
||||
</p>
|
||||
<p>
|
||||
<input type="text" placeholder="Body" ref="body" />
|
||||
</p>
|
||||
<input
|
||||
className="button button-primary"
|
||||
type="submit"
|
||||
value="Save"
|
||||
disabled={this.state.loading} />
|
||||
</form>
|
||||
<Form
|
||||
endpoint="newsletters"
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages } />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return Form;
|
||||
return NewsletterForm;
|
||||
}
|
||||
);
|
||||
);
|
@ -1,18 +1,17 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'jquery',
|
||||
'mailpoet',
|
||||
'react-router',
|
||||
'listing/listing.jsx',
|
||||
'classnames'
|
||||
'classnames',
|
||||
],
|
||||
function(
|
||||
React,
|
||||
jQuery,
|
||||
MailPoet,
|
||||
Router,
|
||||
Listing,
|
||||
classNames
|
||||
) {
|
||||
var Link = Router.Link;
|
||||
|
||||
var columns = [
|
||||
{
|
||||
@ -32,32 +31,7 @@ define(
|
||||
}
|
||||
];
|
||||
|
||||
var List = React.createClass({
|
||||
getItems: function(listing) {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
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)
|
||||
});
|
||||
},
|
||||
var NewsletterList = React.createClass({
|
||||
renderItem: function(newsletter) {
|
||||
var rowClasses = classNames(
|
||||
'manage-column',
|
||||
@ -71,6 +45,12 @@ define(
|
||||
<strong>
|
||||
<a>{ newsletter.subject }</a>
|
||||
</strong>
|
||||
|
||||
<div className="row-actions">
|
||||
<span className="edit">
|
||||
<Link to="edit" params={{ id: newsletter.id }}>Edit</Link>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Subscribed on">
|
||||
<abbr>{ newsletter.created_at }</abbr>
|
||||
@ -84,6 +64,7 @@ define(
|
||||
render: function() {
|
||||
return (
|
||||
<Listing
|
||||
endpoint="newsletters"
|
||||
onRenderItem={this.renderItem}
|
||||
items={this.getItems}
|
||||
columns={columns} />
|
||||
@ -91,6 +72,6 @@ define(
|
||||
}
|
||||
});
|
||||
|
||||
return List;
|
||||
return NewsletterList;
|
||||
}
|
||||
);
|
@ -2,20 +2,20 @@ define(
|
||||
[
|
||||
'react',
|
||||
'react-router',
|
||||
'newsletters/form.jsx',
|
||||
'newsletters/list.jsx'
|
||||
'newsletters/list.jsx',
|
||||
'newsletters/form.jsx'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
Router,
|
||||
Form,
|
||||
List
|
||||
List,
|
||||
Form
|
||||
) {
|
||||
|
||||
var DefaultRoute = Router.DefaultRoute;
|
||||
var Link = Router.Link;
|
||||
var Route = Router.Route;
|
||||
var RouteHandler = Router.RouteHandler;
|
||||
var NotFoundRoute = Router.NotFoundRoute;
|
||||
|
||||
var App = React.createClass({
|
||||
render: function() {
|
||||
@ -24,7 +24,7 @@ define(
|
||||
<h1>
|
||||
{ MailPoetI18n.pageTitle }
|
||||
|
||||
<Link className="add-new-h2" to="form">New</Link>
|
||||
<Link className="add-new-h2" to="new">New</Link>
|
||||
</h1>
|
||||
|
||||
<RouteHandler/>
|
||||
@ -35,8 +35,9 @@ define(
|
||||
|
||||
var routes = (
|
||||
<Route name="app" path="/" handler={App}>
|
||||
<Route name="list" handler={List} />
|
||||
<Route name="form" handler={Form} />
|
||||
<Route name="new" path="/new" handler={Form} />
|
||||
<Route name="edit" path="/edit/:id" handler={Form} />
|
||||
<NotFoundRoute handler={List} />
|
||||
<DefaultRoute handler={List} />
|
||||
</Route>
|
||||
);
|
||||
|
@ -1,71 +1,45 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'react-router',
|
||||
'jquery',
|
||||
'mailpoet'
|
||||
'mailpoet',
|
||||
'form/form.jsx'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
Router,
|
||||
jQuery,
|
||||
MailPoet
|
||||
MailPoet,
|
||||
Form
|
||||
) {
|
||||
|
||||
var Form = React.createClass({
|
||||
mixins: [
|
||||
Router.Navigation
|
||||
],
|
||||
getInitialState: function() {
|
||||
return {
|
||||
loading: false,
|
||||
errors: []
|
||||
};
|
||||
var fields = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
type: 'text'
|
||||
}
|
||||
];
|
||||
|
||||
var messages = {
|
||||
updated: function() {
|
||||
MailPoet.Notice.success('Segment succesfully updated!');
|
||||
},
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
created: function() {
|
||||
MailPoet.Notice.success('Segment succesfully added!');
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
},
|
||||
var SegmentForm = React.createClass({
|
||||
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>
|
||||
<Form
|
||||
endpoint="segments"
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages } />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return Form;
|
||||
return SegmentForm;
|
||||
}
|
||||
);
|
@ -1,18 +1,17 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'jquery',
|
||||
'mailpoet',
|
||||
'react-router',
|
||||
'listing/listing.jsx',
|
||||
'classnames'
|
||||
'classnames',
|
||||
],
|
||||
function(
|
||||
React,
|
||||
jQuery,
|
||||
MailPoet,
|
||||
Router,
|
||||
Listing,
|
||||
classNames
|
||||
) {
|
||||
var Link = Router.Link;
|
||||
|
||||
var columns = [
|
||||
{
|
||||
@ -32,32 +31,7 @@ define(
|
||||
}
|
||||
];
|
||||
|
||||
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)
|
||||
});
|
||||
},
|
||||
var SegmentList = React.createClass({
|
||||
renderItem: function(segment) {
|
||||
var rowClasses = classNames(
|
||||
'manage-column',
|
||||
@ -71,6 +45,12 @@ define(
|
||||
<strong>
|
||||
<a>{ segment.name }</a>
|
||||
</strong>
|
||||
|
||||
<div className="row-actions">
|
||||
<span className="edit">
|
||||
<Link to="edit" params={{ id: segment.id }}>Edit</Link>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="column-date" data-colname="Subscribed on">
|
||||
<abbr>{ segment.created_at }</abbr>
|
||||
@ -84,6 +64,7 @@ define(
|
||||
render: function() {
|
||||
return (
|
||||
<Listing
|
||||
endpoint="segments"
|
||||
onRenderItem={this.renderItem}
|
||||
items={this.getItems}
|
||||
columns={columns} />
|
||||
@ -91,6 +72,6 @@ define(
|
||||
}
|
||||
});
|
||||
|
||||
return List;
|
||||
return SegmentList;
|
||||
}
|
||||
);
|
@ -11,11 +11,11 @@ define(
|
||||
List,
|
||||
Form
|
||||
) {
|
||||
|
||||
var DefaultRoute = Router.DefaultRoute;
|
||||
var Link = Router.Link;
|
||||
var Route = Router.Route;
|
||||
var RouteHandler = Router.RouteHandler;
|
||||
var NotFoundRoute = Router.NotFoundRoute;
|
||||
|
||||
var App = React.createClass({
|
||||
render: function() {
|
||||
@ -24,7 +24,7 @@ define(
|
||||
<h1>
|
||||
{ MailPoetI18n.pageTitle }
|
||||
|
||||
<Link className="add-new-h2" to="form">New</Link>
|
||||
<Link className="add-new-h2" to="new">New</Link>
|
||||
</h1>
|
||||
|
||||
<RouteHandler/>
|
||||
@ -35,8 +35,9 @@ define(
|
||||
|
||||
var routes = (
|
||||
<Route name="app" path="/" handler={App}>
|
||||
<Route name="list" handler={List} />
|
||||
<Route name="form" handler={Form} />
|
||||
<Route name="new" path="/new" handler={Form} />
|
||||
<Route name="edit" path="/edit/:id" handler={Form} />
|
||||
<NotFoundRoute handler={List} />
|
||||
<DefaultRoute handler={List} />
|
||||
</Route>
|
||||
);
|
||||
|
@ -1,41 +1,61 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'react-router',
|
||||
'jquery',
|
||||
'mailpoet',
|
||||
'classnames',
|
||||
'form/form.jsx'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
Router,
|
||||
jQuery,
|
||||
MailPoet,
|
||||
classNames,
|
||||
Form
|
||||
) {
|
||||
|
||||
var fields = [
|
||||
{
|
||||
name: 'email',
|
||||
label: 'E-mail'
|
||||
label: 'E-mail',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'first_name',
|
||||
label: 'Firstname'
|
||||
label: 'Firstname',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'last_name',
|
||||
label: 'Lastname'
|
||||
label: 'Lastname',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
type: 'select',
|
||||
values: {
|
||||
'subscribed': 'Subscribed',
|
||||
'unconfirmed': 'Unconfirmed',
|
||||
'unsubscribed': 'Unsubscribed'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
var messages = {
|
||||
updated: function() {
|
||||
MailPoet.Notice.success('Subscriber succesfully updated!');
|
||||
},
|
||||
created: function() {
|
||||
MailPoet.Notice.success('Subscriber succesfully added!');
|
||||
}
|
||||
};
|
||||
|
||||
var SubscriberForm = React.createClass({
|
||||
render: function() {
|
||||
|
||||
return (
|
||||
<Form fields={ fields } params={ this.props.params } />
|
||||
<Form
|
||||
endpoint="subscribers"
|
||||
fields={ fields }
|
||||
params={ this.props.params }
|
||||
messages={ messages } />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -2,18 +2,15 @@ define(
|
||||
[
|
||||
'react',
|
||||
'react-router',
|
||||
'mailpoet',
|
||||
'listing/listing.jsx',
|
||||
'classnames',
|
||||
],
|
||||
function(
|
||||
React,
|
||||
Router,
|
||||
MailPoet,
|
||||
Listing,
|
||||
classNames
|
||||
) {
|
||||
|
||||
var Link = Router.Link;
|
||||
|
||||
var columns = [
|
||||
@ -65,31 +62,6 @@ define(
|
||||
];
|
||||
|
||||
var List = React.createClass({
|
||||
getItems: function(listing) {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'subscribers',
|
||||
action: 'listing',
|
||||
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(subscriber) {
|
||||
var rowClasses = classNames(
|
||||
'manage-column',
|
||||
@ -151,6 +123,7 @@ define(
|
||||
render: function() {
|
||||
return (
|
||||
<Listing
|
||||
endpoint="subscribers"
|
||||
onRenderItem={ this.renderItem }
|
||||
items={ this.getItems }
|
||||
columns={ columns }
|
||||
|
@ -11,7 +11,6 @@ define(
|
||||
List,
|
||||
Form
|
||||
) {
|
||||
|
||||
var DefaultRoute = Router.DefaultRoute;
|
||||
var Link = Router.Link;
|
||||
var Route = Router.Route;
|
||||
|
@ -35,4 +35,28 @@ class Newsletter extends Model {
|
||||
|
||||
static function group($orm, $group = null) {
|
||||
}
|
||||
|
||||
public static function createOrUpdate($data = array()) {
|
||||
$newsletter = false;
|
||||
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$newsletter = self::findOne((int)$data['id']);
|
||||
}
|
||||
|
||||
if($newsletter === false) {
|
||||
$newsletter = self::create();
|
||||
$newsletter->hydrate($data);
|
||||
} else {
|
||||
unset($data['id']);
|
||||
$newsletter->set($data);
|
||||
}
|
||||
|
||||
$saved = $newsletter->save();
|
||||
|
||||
if($saved === false) {
|
||||
return $newsletter->getValidationErrors();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,20 +15,6 @@ class Segment extends Model {
|
||||
));
|
||||
}
|
||||
|
||||
public static function createOrUpdate($model) {
|
||||
$exists = self::where('name', $model['name'])
|
||||
->find_one();
|
||||
|
||||
if($exists === false) {
|
||||
$new_model = self::create();
|
||||
$new_model->name = $model['name'];
|
||||
return $new_model->save();
|
||||
}
|
||||
|
||||
$exists->name = $model['name_updated'];
|
||||
return $exists->save();
|
||||
}
|
||||
|
||||
public function subscribers() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Subscriber',
|
||||
@ -54,4 +40,28 @@ class Segment extends Model {
|
||||
|
||||
static function group($orm, $group = null) {
|
||||
}
|
||||
|
||||
public static function createOrUpdate($data = array()) {
|
||||
$segment = false;
|
||||
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$segment = self::findOne((int)$data['id']);
|
||||
}
|
||||
|
||||
if($segment === false) {
|
||||
$segment = self::create();
|
||||
$segment->hydrate($data);
|
||||
} else {
|
||||
unset($data['id']);
|
||||
$segment->set($data);
|
||||
}
|
||||
|
||||
$saved = $segment->save();
|
||||
|
||||
if($saved === false) {
|
||||
return $segment->getValidationErrors();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,10 +80,18 @@ class Subscriber extends Model {
|
||||
|
||||
if($subscriber === false) {
|
||||
$subscriber = self::create();
|
||||
$subscriber->hydrate($data);
|
||||
} else {
|
||||
unset($data['id']);
|
||||
$subscriber->set($data);
|
||||
}
|
||||
|
||||
$subscriber->hydrate($data);
|
||||
return $subscriber->save();
|
||||
$saved = $subscriber->save();
|
||||
|
||||
if($saved === false) {
|
||||
return $subscriber->getValidationErrors();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,17 @@ class Newsletters {
|
||||
}
|
||||
|
||||
function get($data = array()) {
|
||||
$id = (isset($data['id']) ? (int)$data['id'] : 0);
|
||||
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter === false) {
|
||||
wp_send_json(false);
|
||||
} else {
|
||||
wp_send_json($newsletter->asArray());
|
||||
}
|
||||
}
|
||||
|
||||
function listing($data = array()) {
|
||||
$listing = new Listing\Handler(
|
||||
\Model::factory('\MailPoet\Models\Newsletter'),
|
||||
$data
|
||||
@ -24,11 +35,14 @@ class Newsletters {
|
||||
wp_send_json($collection);
|
||||
}
|
||||
|
||||
function save($args) {
|
||||
$model = Newsletter::create();
|
||||
$model->hydrate($args);
|
||||
$result = $model->save();
|
||||
wp_send_json($result);
|
||||
function save($data = array()) {
|
||||
$result = Newsletter::createOrUpdate($data);
|
||||
|
||||
if($result !== true) {
|
||||
wp_send_json($result);
|
||||
} else {
|
||||
wp_send_json(true);
|
||||
}
|
||||
}
|
||||
|
||||
function update($args) {
|
||||
|
@ -10,6 +10,17 @@ class Segments {
|
||||
}
|
||||
|
||||
function get($data = array()) {
|
||||
$id = (isset($data['id']) ? (int)$data['id'] : 0);
|
||||
|
||||
$segment = Segment::findOne($id);
|
||||
if($segment === false) {
|
||||
wp_send_json(false);
|
||||
} else {
|
||||
wp_send_json($segment->asArray());
|
||||
}
|
||||
}
|
||||
|
||||
function listing($data = array()) {
|
||||
$listing = new Listing\Handler(
|
||||
\Model::factory('\MailPoet\Models\Segment'),
|
||||
$data
|
||||
@ -22,11 +33,14 @@ class Segments {
|
||||
wp_send_json($collection);
|
||||
}
|
||||
|
||||
function save($args) {
|
||||
$model = Segment::create();
|
||||
$model->hydrate($args);
|
||||
$result = $model->save();
|
||||
wp_send_json($result);
|
||||
function save($data = array()) {
|
||||
$result = Segment::createOrUpdate($data);
|
||||
|
||||
if($result !== true) {
|
||||
wp_send_json($result);
|
||||
} else {
|
||||
wp_send_json(true);
|
||||
}
|
||||
}
|
||||
|
||||
function update($args) {
|
||||
|
@ -10,7 +10,7 @@ abstract class ValidModel extends \Model
|
||||
'indexedErrors' => false, // If True getValidationErrors will return an array with the index
|
||||
// being the field name and the value the error. If multiple errors
|
||||
// are triggered for a field only the first will be kept.
|
||||
'throw' => self::ON_SAVE // One of self::ON_SET|ON_SAVE|NEVER.
|
||||
'throw' => self::ON_SAVE // One of self::ON_SET|ON_SAVE|NEVER.
|
||||
// + ON_SET throws immediately when field is set()
|
||||
// + ON_SAVE throws on save()
|
||||
// + NEVER means an exception is never thrown; check for ->getValidaionErrors()
|
||||
@ -130,11 +130,17 @@ abstract class ValidModel extends \Model
|
||||
|
||||
/**
|
||||
* Overload set; to call validateAndSet
|
||||
* // TODO: handle multiple sets if $name is a field=>val array
|
||||
*/
|
||||
public function set($name, $value = null)
|
||||
public function set($key, $value = null)
|
||||
{
|
||||
$this->validateAndSet($name, $value);
|
||||
if(is_array($key)) {
|
||||
// multiple values
|
||||
foreach($key as $field => $value) {
|
||||
$this->validateAndSet($field, $value);
|
||||
}
|
||||
} else {
|
||||
$this->validateAndSet($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,10 +23,11 @@
|
||||
"napa": "^1.2.0",
|
||||
"papaparse": "4.1.1",
|
||||
"react": "^0.13.3",
|
||||
"react-checkbox-group": "^0.2.0",
|
||||
"react-infinity": "^1.2.2",
|
||||
"react-prefixr": "^0.1.0",
|
||||
"react-waypoint": "^1.0.2",
|
||||
"react-router": "^0.13.3",
|
||||
"react-waypoint": "^1.0.2",
|
||||
"select2": "3.5.1",
|
||||
"spectrum-colorpicker": "^1.6.2",
|
||||
"tinymce": "4.1.10",
|
||||
|
Reference in New Issue
Block a user