Custom fields (in Form & Edit subscriber)
This commit is contained in:
@ -1,31 +1,31 @@
|
|||||||
define([
|
define([
|
||||||
'react',
|
'react'
|
||||||
'react-checkbox-group'
|
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
React,
|
React
|
||||||
CheckboxGroup
|
|
||||||
) {
|
) {
|
||||||
var FormFieldCheckbox = React.createClass({
|
const FormFieldCheckbox = React.createClass({
|
||||||
|
onValueChange: function(e) {
|
||||||
|
e.target.value = this.refs.checkbox.checked ? '1' : '';
|
||||||
|
return this.props.onValueChange(e);
|
||||||
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var selected_values = this.props.item[this.props.field.name] || '';
|
const isChecked = !!(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(
|
const options = Object.keys(this.props.field.values).map(
|
||||||
function(value, index) {
|
function(value, index) {
|
||||||
return (
|
return (
|
||||||
<p key={ 'checkbox-' + index }>
|
<p key={ 'checkbox-' + index }>
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" value={ value } />
|
<input
|
||||||
{ this.props.field.values[value] }
|
ref="checkbox"
|
||||||
|
type="checkbox"
|
||||||
|
value="1"
|
||||||
|
checked={ isChecked }
|
||||||
|
onChange={ this.onValueChange }
|
||||||
|
name={ this.props.field.name }
|
||||||
|
/>
|
||||||
|
{ this.props.field.values[value] }
|
||||||
</label>
|
</label>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
@ -33,30 +33,10 @@ function(
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CheckboxGroup
|
<div>
|
||||||
name={ this.props.field.name }
|
|
||||||
value={ selected_values }
|
|
||||||
ref={ this.props.field.name }
|
|
||||||
onChange={ this.handleValueChange }>
|
|
||||||
{ options }
|
{ options }
|
||||||
</CheckboxGroup>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
|
||||||
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(';')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
181
assets/js/src/form/fields/date.jsx
Normal file
181
assets/js/src/form/fields/date.jsx
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
define([
|
||||||
|
'react',
|
||||||
|
'moment',
|
||||||
|
], function(
|
||||||
|
React,
|
||||||
|
Moment
|
||||||
|
) {
|
||||||
|
class FormFieldDateYear extends React.Component {
|
||||||
|
render() {
|
||||||
|
const years = [];
|
||||||
|
const currentYear = Moment().year();
|
||||||
|
for (let i = currentYear; i >= currentYear - 100; i--) {
|
||||||
|
years.push((
|
||||||
|
<option
|
||||||
|
key={ i }
|
||||||
|
value={ i }
|
||||||
|
>{ i }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
name={ this.props.name + '[year]' }
|
||||||
|
value={ this.props.year }
|
||||||
|
onChange={ this.props.onValueChange }
|
||||||
|
>
|
||||||
|
{ years }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FormFieldDateMonth extends React.Component {
|
||||||
|
render() {
|
||||||
|
const months = [];
|
||||||
|
for (let i = 1; i <= 12; i++) {
|
||||||
|
months.push((
|
||||||
|
<option
|
||||||
|
key={ i }
|
||||||
|
value={ i }
|
||||||
|
>{ this.props.monthNames[i - 1] }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
name={ this.props.name + '[month]' }
|
||||||
|
value={ this.props.month }
|
||||||
|
onChange={ this.props.onValueChange }
|
||||||
|
>
|
||||||
|
{ months }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FormFieldDateDay extends React.Component {
|
||||||
|
render() {
|
||||||
|
const days = [];
|
||||||
|
for (let i = 1; i <= 31; i++) {
|
||||||
|
days.push((
|
||||||
|
<option
|
||||||
|
key={ i }
|
||||||
|
value={ i }
|
||||||
|
>{ i }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
name={ this.props.name + '[day]' }
|
||||||
|
value={ this.props.day }
|
||||||
|
onChange={ this.props.onValueChange }
|
||||||
|
>
|
||||||
|
{ days }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FormFieldDate extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
year: Moment().year(),
|
||||||
|
month: 1,
|
||||||
|
day: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
}
|
||||||
|
componentDidUpdate(prevProps, prevState) {
|
||||||
|
if(
|
||||||
|
(this.props.item !== undefined && prevProps.item !== undefined)
|
||||||
|
&& (this.props.item.id !== prevProps.item.id)
|
||||||
|
) {
|
||||||
|
this.extractTimeStamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extractTimeStamp() {
|
||||||
|
const timeStamp = parseInt(this.props.item[this.props.field.name], 10);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
year: Moment.unix(timeStamp).year(),
|
||||||
|
month: Moment.unix(timeStamp).month() + 1,
|
||||||
|
day: Moment.unix(timeStamp).date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onValueChange(e) {
|
||||||
|
// extract property from name
|
||||||
|
const matches = e.target.name.match(/.*?\[(.*?)\]/);
|
||||||
|
let property = null;
|
||||||
|
if(matches !== null && matches.length === 2) {
|
||||||
|
property = matches[1];
|
||||||
|
}
|
||||||
|
let value = parseInt(e.target.value, 10);
|
||||||
|
|
||||||
|
switch(property) {
|
||||||
|
case 'year':
|
||||||
|
this.setState({ year: value });
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'month':
|
||||||
|
this.setState({ month: value });
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'day':
|
||||||
|
this.setState({ day: value });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const monthNames = window.mailpoet_month_names || [];
|
||||||
|
|
||||||
|
const dateType = this.props.field.params.date_type;
|
||||||
|
|
||||||
|
const dateSelects = dateType.split('_');
|
||||||
|
|
||||||
|
const fields = dateSelects.map(type => {
|
||||||
|
switch(type) {
|
||||||
|
case 'year':
|
||||||
|
return (<FormFieldDateYear
|
||||||
|
onValueChange={ this.onValueChange.bind(this) }
|
||||||
|
ref={ 'year' }
|
||||||
|
key={ 'year' }
|
||||||
|
name={ this.props.field.name }
|
||||||
|
year={ this.state.year }
|
||||||
|
/>);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'month':
|
||||||
|
return (<FormFieldDateMonth
|
||||||
|
onValueChange={ this.onValueChange.bind(this) }
|
||||||
|
ref={ 'month' }
|
||||||
|
key={ 'month' }
|
||||||
|
name={ this.props.field.name }
|
||||||
|
month={ this.state.month }
|
||||||
|
monthNames={ monthNames }
|
||||||
|
/>);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'day':
|
||||||
|
return (<FormFieldDateDay
|
||||||
|
onValueChange={ this.onValueChange.bind(this) }
|
||||||
|
ref={ 'day' }
|
||||||
|
key={ 'day' }
|
||||||
|
name={ this.props.field.name }
|
||||||
|
day={ this.state.day }
|
||||||
|
/>);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{fields}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return FormFieldDate;
|
||||||
|
});
|
@ -5,7 +5,8 @@ define([
|
|||||||
'form/fields/select.jsx',
|
'form/fields/select.jsx',
|
||||||
'form/fields/radio.jsx',
|
'form/fields/radio.jsx',
|
||||||
'form/fields/checkbox.jsx',
|
'form/fields/checkbox.jsx',
|
||||||
'form/fields/selection.jsx'
|
'form/fields/selection.jsx',
|
||||||
|
'form/fields/date.jsx',
|
||||||
],
|
],
|
||||||
function(
|
function(
|
||||||
React,
|
React,
|
||||||
@ -14,7 +15,8 @@ function(
|
|||||||
FormFieldSelect,
|
FormFieldSelect,
|
||||||
FormFieldRadio,
|
FormFieldRadio,
|
||||||
FormFieldCheckbox,
|
FormFieldCheckbox,
|
||||||
FormFieldSelection
|
FormFieldSelection,
|
||||||
|
FormFieldDate
|
||||||
) {
|
) {
|
||||||
var FormField = React.createClass({
|
var FormField = React.createClass({
|
||||||
renderField: function(data, inline = false) {
|
renderField: function(data, inline = false) {
|
||||||
@ -55,6 +57,10 @@ function(
|
|||||||
case 'selection':
|
case 'selection':
|
||||||
field = (<FormFieldSelection {...data} />);
|
field = (<FormFieldSelection {...data} />);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'date':
|
||||||
|
field = (<FormFieldDate {...data} />);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inline === true) {
|
if(inline === true) {
|
||||||
@ -66,10 +72,10 @@ function(
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<p key={ 'field-' + (data.index || 0) }>
|
<div key={ 'field-' + (data.index || 0) }>
|
||||||
{ field }
|
{ field }
|
||||||
{ description }
|
{ description }
|
||||||
</p>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,6 @@ function(
|
|||||||
var FormFieldRadio = React.createClass({
|
var FormFieldRadio = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
var selected_value = this.props.item[this.props.field.name];
|
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(
|
var options = Object.keys(this.props.field.values).map(
|
||||||
function(value, index) {
|
function(value, index) {
|
||||||
@ -20,7 +19,7 @@ function(
|
|||||||
value={ value }
|
value={ value }
|
||||||
onChange={ this.props.onValueChange }
|
onChange={ this.props.onValueChange }
|
||||||
name={ this.props.field.name } />
|
name={ this.props.field.name } />
|
||||||
{ this.props.field.values[value] }
|
{ this.props.field.values[value] }
|
||||||
</label>
|
</label>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
|
@ -51,6 +51,28 @@ define(
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
var custom_fields = window.mailpoet_custom_fields || [];
|
||||||
|
custom_fields.map(custom_field => {
|
||||||
|
if(custom_field.type === 'input') {
|
||||||
|
custom_field.type = 'text';
|
||||||
|
}
|
||||||
|
|
||||||
|
let field = {
|
||||||
|
name: 'cf_' + custom_field.id,
|
||||||
|
label: custom_field.name,
|
||||||
|
type: custom_field.type
|
||||||
|
};
|
||||||
|
if(custom_field.params) {
|
||||||
|
field.params = custom_field.params;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(custom_field.params.values) {
|
||||||
|
field.values = custom_field.params.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.push(field);
|
||||||
|
});
|
||||||
|
|
||||||
var messages = {
|
var messages = {
|
||||||
onUpdate: function() {
|
onUpdate: function() {
|
||||||
MailPoet.Notice.success('Subscriber successfully updated!');
|
MailPoet.Notice.success('Subscriber successfully updated!');
|
||||||
|
608
composer.lock
generated
608
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -296,7 +296,7 @@ class Menu {
|
|||||||
} else {
|
} else {
|
||||||
// check if users can register
|
// check if users can register
|
||||||
$flags['registration_enabled'] =
|
$flags['registration_enabled'] =
|
||||||
(bool) get_option('users_can_register', false);
|
(bool)get_option('users_can_register', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $flags;
|
return $flags;
|
||||||
@ -307,6 +307,29 @@ class Menu {
|
|||||||
|
|
||||||
$data['segments'] = Segment::findArray();
|
$data['segments'] = Segment::findArray();
|
||||||
|
|
||||||
|
$data['custom_fields'] = array_map(function($field) {
|
||||||
|
$field['params'] = unserialize($field['params']);
|
||||||
|
|
||||||
|
if(!empty($field['params']['values'])) {
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
foreach($field['params']['values'] as $value) {
|
||||||
|
$values[$value['value']] = $value['value'];
|
||||||
|
}
|
||||||
|
$field['params']['values'] = $values;
|
||||||
|
}
|
||||||
|
return $field;
|
||||||
|
}, CustomField::findArray());
|
||||||
|
|
||||||
|
$data['date_formats'] = Block\Date::getDateFormats();
|
||||||
|
$data['month_names'] = Block\Date::getMonthNames();
|
||||||
|
|
||||||
|
|
||||||
|
// print "<pre>";
|
||||||
|
// print_r($data['custom_fields']);
|
||||||
|
// print "</pre>";
|
||||||
|
// exit;
|
||||||
|
|
||||||
echo $this->renderer->render('subscribers/subscribers.html', $data);
|
echo $this->renderer->render('subscribers/subscribers.html', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,12 @@ class Checkbox extends Base {
|
|||||||
|
|
||||||
$html .= static::renderLabel($block);
|
$html .= static::renderLabel($block);
|
||||||
|
|
||||||
foreach($block['params']['values'] as $option) {
|
$options = (!empty($block['params']['values'])
|
||||||
|
? $block['params']['values']
|
||||||
|
: array()
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach($options as $option) {
|
||||||
$html .= '<label class="mailpoet_checkbox_label">';
|
$html .= '<label class="mailpoet_checkbox_label">';
|
||||||
|
|
||||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||||
|
@ -13,7 +13,12 @@ class Radio extends Base {
|
|||||||
|
|
||||||
$html .= static::renderLabel($block);
|
$html .= static::renderLabel($block);
|
||||||
|
|
||||||
foreach($block['params']['values'] as $option) {
|
$options = (!empty($block['params']['values'])
|
||||||
|
? $block['params']['values']
|
||||||
|
: array()
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach($options as $option) {
|
||||||
$html .= '<label class="mailpoet_radio_label">';
|
$html .= '<label class="mailpoet_radio_label">';
|
||||||
|
|
||||||
$html .= '<input type="radio" class="mailpoet_radio" ';
|
$html .= '<input type="radio" class="mailpoet_radio" ';
|
||||||
|
@ -13,21 +13,23 @@ class Segment extends Base {
|
|||||||
|
|
||||||
$html .= static::renderLabel($block);
|
$html .= static::renderLabel($block);
|
||||||
|
|
||||||
if(!empty($block['params']['values'])) {
|
$options = (!empty($block['params']['values'])
|
||||||
// display values
|
? $block['params']['values']
|
||||||
foreach($block['params']['values'] as $segment) {
|
: array()
|
||||||
if(!isset($segment['id']) || !isset($segment['name'])) continue;
|
);
|
||||||
|
|
||||||
$is_checked = (isset($segment['is_checked']) && $segment['is_checked']) ? 'checked="checked"' : '';
|
foreach($options as $option) {
|
||||||
|
if(!isset($option['id']) || !isset($option['name'])) continue;
|
||||||
|
|
||||||
$html .= '<label class="mailpoet_checkbox_label">';
|
$is_checked = (isset($option['is_checked']) && $option['is_checked']) ? 'checked="checked"' : '';
|
||||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
|
||||||
$html .= 'name="'.$field_name.'[]" ';
|
$html .= '<label class="mailpoet_checkbox_label">';
|
||||||
$html .= 'value="'.$segment['id'].'" '.$is_checked.' ';
|
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||||
$html .= $field_validation;
|
$html .= 'name="'.$field_name.'[]" ';
|
||||||
$html .= ' />'.$segment['name'];
|
$html .= 'value="'.$option['id'].'" '.$is_checked.' ';
|
||||||
$html .= '</label>';
|
$html .= $field_validation;
|
||||||
}
|
$html .= ' />'.$option['name'];
|
||||||
|
$html .= '</label>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$html .= '<span class="mailpoet_error_'.$block['id'].'"></span>';
|
$html .= '<span class="mailpoet_error_'.$block['id'].'"></span>';
|
||||||
|
@ -247,13 +247,6 @@ class Subscriber extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(!empty($custom_fields)) {
|
|
||||||
foreach($custom_fields as $custom_field_id => $value) {
|
|
||||||
$subscriber->setCustomField($custom_field_id, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($subscriber === false) {
|
if($subscriber === false) {
|
||||||
$subscriber = static::create();
|
$subscriber = static::create();
|
||||||
$subscriber->hydrate($data);
|
$subscriber->hydrate($data);
|
||||||
@ -261,24 +254,28 @@ class Subscriber extends Model {
|
|||||||
$subscriber->set($data);
|
$subscriber->set($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($subscriber->save()) {
|
||||||
|
if(!empty($custom_fields)) {
|
||||||
$subscriber->save();
|
foreach($custom_fields as $custom_field_id => $value) {
|
||||||
|
$subscriber->setCustomField($custom_field_id, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return $subscriber;
|
return $subscriber;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCustomFields() {
|
function getCustomFields() {
|
||||||
$relation = CustomField::select('id')->findArray();
|
$custom_fields = CustomField::select('id')->findArray();
|
||||||
if(empty($relation)) return $this;
|
if(empty($custom_fields)) return $this;
|
||||||
|
|
||||||
$custom_field_ids = Helpers::arrayColumn($relation, 'id');
|
$custom_field_ids = Helpers::arrayColumn($custom_fields, 'id');
|
||||||
$custom_fields = SubscriberCustomField::select('id')
|
$relations = SubscriberCustomField::select('custom_field_id')
|
||||||
->select('value')
|
->select('value')
|
||||||
->whereIn('custom_field_id', $custom_field_ids)
|
->whereIn('custom_field_id', $custom_field_ids)
|
||||||
->where('subscriber_id', $this->id())
|
->where('subscriber_id', $this->id())
|
||||||
->findMany();
|
->findMany();
|
||||||
foreach($custom_fields as $custom_field) {
|
foreach($relations as $relation) {
|
||||||
$this->{'cf_'.$custom_field->id()} = $custom_field->value;
|
$this->{'cf_'.$relation->custom_field_id} = $relation->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
"papaparse": "4.1.1",
|
"papaparse": "4.1.1",
|
||||||
"parsleyjs": "^2.1.2",
|
"parsleyjs": "^2.1.2",
|
||||||
"react": "0.14.3",
|
"react": "0.14.3",
|
||||||
"react-checkbox-group": "0.2.2",
|
|
||||||
"react-dom": "0.14.3",
|
"react-dom": "0.14.3",
|
||||||
"react-infinity": "1.2.2",
|
"react-infinity": "1.2.2",
|
||||||
"react-prefixr": "0.1.0",
|
"react-prefixr": "0.1.0",
|
||||||
|
@ -16,5 +16,7 @@
|
|||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var mailpoet_segments = <%= json_encode(segments) %>;
|
var mailpoet_segments = <%= json_encode(segments) %>;
|
||||||
|
var mailpoet_custom_fields = <%= json_encode(custom_fields) %>;
|
||||||
|
var mailpoet_month_names = <%= json_encode(month_names) %>;
|
||||||
</script>
|
</script>
|
||||||
<% endblock %>
|
<% endblock %>
|
||||||
|
Reference in New Issue
Block a user