Updated all React components to their latest version

- updated code due to deprecated warnings (mostly router stuff & input default value)
- set default sender based on settings when creating new newsletter
- fixed erroneous UTC offset when displaying dates (PHP takes care of it)
This commit is contained in:
Jonathan Labreuille
2016-04-28 16:54:43 +02:00
parent 59199140bf
commit 4047b41a7f
26 changed files with 128 additions and 109 deletions

View File

@ -41,9 +41,7 @@ define('date',
}, },
format: function(date, options) { format: function(date, options) {
this.init(options); this.init(options);
return Moment.utc(date) return Moment(date).format(this.convertFormat(this.options.format));
.local()
.format(this.convertFormat(this.options.format));
}, },
short: function(date) { short: function(date) {
return this.format(date, { return this.format(date, {

View File

@ -7,7 +7,10 @@ function(
var FormFieldText = React.createClass({ var FormFieldText = React.createClass({
render: function() { render: function() {
var value = this.props.item[this.props.field.name]; var value = this.props.item[this.props.field.name];
if(!value) { value = null; } if(value === undefined) {
value = this.props.field.defaultValue || '';
}
return ( return (
<input <input
type="text" type="text"
@ -21,7 +24,6 @@ function(
id={ 'field_'+this.props.field.name } id={ 'field_'+this.props.field.name }
value={ value } value={ value }
placeholder={ this.props.field.placeholder } placeholder={ this.props.field.placeholder }
defaultValue={ this.props.field.defaultValue }
onChange={ this.props.onValueChange } onChange={ this.props.onValueChange }
{...this.props.field.validation} {...this.props.field.validation}
/> />

View File

@ -13,10 +13,11 @@ define(
Router, Router,
FormField FormField
) { ) {
var Form = React.createClass({ var Form = React.createClass({
mixins: [ contextTypes: {
Router.History router: React.PropTypes.object.isRequired
], },
getDefaultProps: function() { getDefaultProps: function() {
return { return {
params: {}, params: {},
@ -68,7 +69,7 @@ define(
loading: false, loading: false,
item: {} item: {}
}, function() { }, function() {
this.history.pushState(null, '/new'); this.context.router.push('/new');
}.bind(this)); }.bind(this));
} else { } else {
this.setState({ this.setState({
@ -118,7 +119,16 @@ define(
if(this.props.onSuccess !== undefined) { if(this.props.onSuccess !== undefined) {
this.props.onSuccess(); this.props.onSuccess();
} else { } else {
this.history.pushState(null, '/') var isChrome = (/Chrome/.test(navigator.userAgent))
&& (/Google Inc/.test(navigator.vendor));
if(
(isChrome && history.length > 2)
|| (!isChrome && history.length > 1)
) {
this.context.router.goBack();
} else {
this.context.router.push('/');
}
} }
if(this.props.params.id !== undefined) { if(this.props.params.id !== undefined) {

View File

@ -1,10 +1,10 @@
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { Router, Route, IndexRoute } from 'react-router' import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
import FormList from 'forms/list.jsx' import FormList from 'forms/list.jsx'
import createHashHistory from 'history/lib/createHashHistory'
let history = createHashHistory({ queryKey: false }) const history = useRouterHistory(createHashHistory)({ queryKey: false });
const App = React.createClass({ const App = React.createClass({
render() { render() {
@ -12,7 +12,7 @@ const App = React.createClass({
} }
}); });
let container = document.getElementById('forms_container'); const container = document.getElementById('forms_container');
if(container) { if(container) {
ReactDOM.render(( ReactDOM.render((

View File

@ -295,9 +295,9 @@ define(
}); });
var Listing = React.createClass({ var Listing = React.createClass({
mixins: [ contextTypes: {
Router.History router: React.PropTypes.object.isRequired
], },
getInitialState: function() { getInitialState: function() {
return { return {
loading: false, loading: false,
@ -359,9 +359,12 @@ define(
} }
}) })
} }
// default overrides
if(this.props.limit !== undefined) { if(this.props.limit !== undefined) {
state.limit = Math.abs(~~this.props.limit); state.limit = Math.abs(~~this.props.limit);
} }
this.setState(state, function() { this.setState(state, function() {
this.getItems(); this.getItems();
}.bind(this)); }.bind(this));
@ -398,7 +401,7 @@ define(
if(this.props.location) { if(this.props.location) {
if(this.props.location.pathname !== params) { if(this.props.location.pathname !== params) {
this.history.pushState(null, `${params}`) this.context.router.push(`${params}`);
} }
} }
}, },
@ -753,8 +756,8 @@ define(
onSort={ this.handleSort } onSort={ this.handleSort }
onSelectItems={ this.handleSelectItems } onSelectItems={ this.handleSelectItems }
selection={ this.state.selection } selection={ this.state.selection }
sort_by={ this.state.sort_by } sort_by={ sort_by }
sort_order={ this.state.sort_order } sort_order={ sort_order }
columns={ this.props.columns } columns={ this.props.columns }
is_selectable={ bulk_actions.length > 0 } /> is_selectable={ bulk_actions.length > 0 } />
</thead> </thead>
@ -783,8 +786,8 @@ define(
onSort={ this.handleSort } onSort={ this.handleSort }
onSelectItems={ this.handleSelectItems } onSelectItems={ this.handleSelectItems }
selection={ this.state.selection } selection={ this.state.selection }
sort_by={ this.state.sort_by } sort_by={ sort_by }
sort_order={ this.state.sort_order } sort_order={ sort_order }
columns={ this.props.columns } columns={ this.props.columns }
is_selectable={ bulk_actions.length > 0 } /> is_selectable={ bulk_actions.length > 0 } />
</tfoot> </tfoot>

View File

@ -14,9 +14,6 @@ define(
var Link = Router.Link; var Link = Router.Link;
var Breadcrumb = React.createClass({ var Breadcrumb = React.createClass({
mixins: [
Router.History
],
getInitialState: function() { getInitialState: function() {
return { return {
step: null, step: null,

View File

@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { Router, Route, IndexRoute, Link } from 'react-router' import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
import NewsletterList from 'newsletters/list.jsx' import NewsletterList from 'newsletters/list.jsx'
import NewsletterTypes from 'newsletters/types.jsx' import NewsletterTypes from 'newsletters/types.jsx'
import NewsletterTemplates from 'newsletters/templates.jsx' import NewsletterTemplates from 'newsletters/templates.jsx'
@ -8,9 +9,8 @@ import NewsletterSend from 'newsletters/send.jsx'
import NewsletterStandard from 'newsletters/types/standard.jsx' import NewsletterStandard from 'newsletters/types/standard.jsx'
import NewsletterWelcome from 'newsletters/types/welcome/welcome.jsx' import NewsletterWelcome from 'newsletters/types/welcome/welcome.jsx'
import NewsletterNotification from 'newsletters/types/notification/notification.jsx' import NewsletterNotification from 'newsletters/types/notification/notification.jsx'
import createHashHistory from 'history/lib/createHashHistory'
let history = createHashHistory({ queryKey: false }) const history = useRouterHistory(createHashHistory)({ queryKey: false });
const App = React.createClass({ const App = React.createClass({
render() { render() {
@ -18,7 +18,7 @@ const App = React.createClass({
} }
}); });
let container = document.getElementById('newsletters_container'); const container = document.getElementById('newsletters_container');
if(container) { if(container) {
ReactDOM.render(( ReactDOM.render((

View File

@ -23,9 +23,9 @@ define(
) { ) {
var NewsletterSend = React.createClass({ var NewsletterSend = React.createClass({
mixins: [ contextTypes: {
Router.History router: React.PropTypes.object.isRequired
], },
getInitialState: function() { getInitialState: function() {
return { return {
fields: [], fields: [],
@ -68,7 +68,7 @@ define(
loading: false, loading: false,
item: {}, item: {},
}, function() { }, function() {
this.history.pushState(null, '/new'); this.context.router.push('/new');
}.bind(this)); }.bind(this));
} else { } else {
this.setState({ this.setState({
@ -106,8 +106,10 @@ define(
}).done((response) => { }).done((response) => {
this.setState({ loading: false }); this.setState({ loading: false });
if(response.result === true) { if(response.result === true) {
this.history.pushState(null, '/'); this.context.router.push('/');
MailPoet.Notice.success(
MailPoet.Notice.success(response.data.message); MailPoet.Notice.success(response.data.message);
);
} else { } else {
if(response.errors) { if(response.errors) {
MailPoet.Notice.error(response.errors); MailPoet.Notice.error(response.errors);
@ -133,7 +135,7 @@ define(
this.setState({ loading: false }); this.setState({ loading: false });
if(response.result === true) { if(response.result === true) {
this.history.pushState(null, '/'); this.context.router.push('/');
MailPoet.Notice.success( MailPoet.Notice.success(
MailPoet.I18n.t('newsletterUpdated') MailPoet.I18n.t('newsletterUpdated')
); );

View File

@ -60,7 +60,6 @@ define(
name: 'sender_name', name: 'sender_name',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('senderNamePlaceholder'), placeholder: MailPoet.I18n.t('senderNamePlaceholder'),
defaultValue: (settings.sender !== undefined) ? settings.sender.name : '',
validation: { validation: {
'data-parsley-required': true 'data-parsley-required': true
} }
@ -69,7 +68,6 @@ define(
name: 'sender_address', name: 'sender_address',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('senderAddressPlaceholder'), placeholder: MailPoet.I18n.t('senderAddressPlaceholder'),
defaultValue: (settings.sender !== undefined) ? settings.sender.address : '',
validation: { validation: {
'data-parsley-required': true, 'data-parsley-required': true,
'data-parsley-type': 'email' 'data-parsley-type': 'email'
@ -86,15 +84,13 @@ define(
{ {
name: 'reply_to_name', name: 'reply_to_name',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('replyToNamePlaceholder'), placeholder: MailPoet.I18n.t('replyToNamePlaceholder')
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.name : '',
}, },
{ {
name: 'reply_to_address', name: 'reply_to_address',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('replyToAddressPlaceholder'), placeholder: MailPoet.I18n.t('replyToAddressPlaceholder')
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.address : '' }
},
] ]
} }
]; ];

View File

@ -52,7 +52,6 @@ define(
name: 'sender_name', name: 'sender_name',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('senderNamePlaceholder'), placeholder: MailPoet.I18n.t('senderNamePlaceholder'),
defaultValue: (settings.sender !== undefined) ? settings.sender.name : '',
validation: { validation: {
'data-parsley-required': true 'data-parsley-required': true
} }
@ -61,7 +60,6 @@ define(
name: 'sender_address', name: 'sender_address',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('senderAddressPlaceholder'), placeholder: MailPoet.I18n.t('senderAddressPlaceholder'),
defaultValue: (settings.sender !== undefined) ? settings.sender.address : '',
validation: { validation: {
'data-parsley-required': true, 'data-parsley-required': true,
'data-parsley-type': 'email' 'data-parsley-type': 'email'
@ -78,15 +76,13 @@ define(
{ {
name: 'reply_to_name', name: 'reply_to_name',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('replyToNamePlaceholder'), placeholder: MailPoet.I18n.t('replyToNamePlaceholder')
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.name : '',
}, },
{ {
name: 'reply_to_address', name: 'reply_to_address',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('replyToAddressPlaceholder'), placeholder: MailPoet.I18n.t('replyToAddressPlaceholder')
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.address : '' }
},
] ]
} }
]; ];

View File

@ -36,7 +36,6 @@ define(
name: 'sender_name', name: 'sender_name',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('senderNamePlaceholder'), placeholder: MailPoet.I18n.t('senderNamePlaceholder'),
defaultValue: (settings.sender !== undefined) ? settings.sender.name : '',
validation: { validation: {
'data-parsley-required': true 'data-parsley-required': true
} }
@ -45,7 +44,6 @@ define(
name: 'sender_address', name: 'sender_address',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('senderAddressPlaceholder'), placeholder: MailPoet.I18n.t('senderAddressPlaceholder'),
defaultValue: (settings.sender !== undefined) ? settings.sender.address : '',
validation: { validation: {
'data-parsley-required': true, 'data-parsley-required': true,
'data-parsley-type': 'email' 'data-parsley-type': 'email'
@ -62,15 +60,13 @@ define(
{ {
name: 'reply_to_name', name: 'reply_to_name',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('replyToNamePlaceholder'), placeholder: MailPoet.I18n.t('replyToNamePlaceholder')
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.name : '',
}, },
{ {
name: 'reply_to_address', name: 'reply_to_address',
type: 'text', type: 'text',
placeholder: MailPoet.I18n.t('replyToAddressPlaceholder'), placeholder: MailPoet.I18n.t('replyToAddressPlaceholder')
defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.address : '' }
},
] ]
} }
]; ];

View File

@ -80,9 +80,6 @@ define(
}); });
var NewsletterTemplates = React.createClass({ var NewsletterTemplates = React.createClass({
mixins: [
Router.History
],
getInitialState: function() { getInitialState: function() {
return { return {
loading: false, loading: false,

View File

@ -12,12 +12,12 @@ define(
Breadcrumb Breadcrumb
) { ) {
var NewsletterTypes = React.createClass({ var NewsletterTypes = React.createClass({
mixins: [ contextTypes: {
Router.History router: React.PropTypes.object.isRequired
], },
setupNewsletter: function(type) { setupNewsletter: function(type) {
if(type !== undefined) { if(type !== undefined) {
this.history.pushState(null, `/new/${type}`); this.context.router.push(`/new/${type}`);
} }
}, },
createNewsletter: function(type) { createNewsletter: function(type) {
@ -30,7 +30,7 @@ define(
} }
}).done(function(response) { }).done(function(response) {
if(response.result && response.newsletter.id) { if(response.result && response.newsletter.id) {
this.history.pushState(null, `/template/${response.newsletter.id}`); this.context.router.push(`/template/${response.newsletter.id}`);
} else { } else {
if(response.errors.length > 0) { if(response.errors.length > 0) {
response.errors.map(function(error) { response.errors.map(function(error) {

View File

@ -24,9 +24,9 @@ define(
}; };
var NewsletterNotification = React.createClass({ var NewsletterNotification = React.createClass({
mixins: [ contextTypes: {
Router.History router: React.PropTypes.object.isRequired
], },
getInitialState: function() { getInitialState: function() {
return { return {
options: { options: {
@ -64,7 +64,7 @@ define(
}.bind(this)); }.bind(this));
}, },
showTemplateSelection: function(newsletterId) { showTemplateSelection: function(newsletterId) {
this.history.pushState(null, `/template/${newsletterId}`); this.context.router.push(`/template/${newsletterId}`);
}, },
render: function() { render: function() {
return ( return (

View File

@ -13,11 +13,11 @@ define(
) { ) {
var NewsletterStandard = React.createClass({ var NewsletterStandard = React.createClass({
mixins: [ contextTypes: {
Router.History router: React.PropTypes.object.isRequired
], },
showTemplateSelection: function(newsletterId) { showTemplateSelection: function(newsletterId) {
this.history.pushState(null, `/template/${newsletterId}`); this.context.router.push(`/template/${newsletterId}`);
}, },
componentDidMount: function() { componentDidMount: function() {
// No options for this type, create a newsletter upon mounting // No options for this type, create a newsletter upon mounting

View File

@ -65,6 +65,9 @@ define(
}; };
var WelcomeScheduling = React.createClass({ var WelcomeScheduling = React.createClass({
contextTypes: {
router: React.PropTypes.object.isRequired
},
_getCurrentValue: function() { _getCurrentValue: function() {
return this.props.item[this.props.field.name] || {}; return this.props.item[this.props.field.name] || {};
}, },
@ -131,7 +134,7 @@ define(
}.bind(this)); }.bind(this));
}, },
showTemplateSelection: function(newsletterId) { showTemplateSelection: function(newsletterId) {
this.history.pushState(null, `/template/${newsletterId}`); this.context.router.push(`/template/${newsletterId}`);
}, },
render: function() { render: function() {
var value = this._getCurrentValue(), var value = this._getCurrentValue(),

View File

@ -31,9 +31,9 @@ define(
} }
var NewsletterWelcome = React.createClass({ var NewsletterWelcome = React.createClass({
mixins: [ contextTypes: {
Router.History router: React.PropTypes.object.isRequired
], },
getInitialState: function() { getInitialState: function() {
return { return {
options: { options: {
@ -71,7 +71,7 @@ define(
}.bind(this)); }.bind(this));
}, },
showTemplateSelection: function(newsletterId) { showTemplateSelection: function(newsletterId) {
this.history.pushState(null, `/template/${newsletterId}`); this.context.router.push(`/template/${newsletterId}`);
}, },
render: function() { render: function() {
return ( return (

View File

@ -1,13 +1,11 @@
define( define(
[ [
'react', 'react',
'react-router',
'mailpoet', 'mailpoet',
'form/form.jsx' 'form/form.jsx'
], ],
function( function(
React, React,
Router,
MailPoet, MailPoet,
Form Form
) { ) {
@ -21,7 +19,8 @@ define(
{ {
name: 'description', name: 'description',
label: MailPoet.I18n.t('description'), label: MailPoet.I18n.t('description'),
type: 'textarea' type: 'textarea',
tip: MailPoet.I18n.t('segmentDescriptionTip')
} }
]; ];
@ -35,9 +34,6 @@ define(
}; };
const SegmentForm = React.createClass({ const SegmentForm = React.createClass({
mixins: [
Router.History
],
render: function() { render: function() {
return ( return (
<div> <div>

View File

@ -159,9 +159,6 @@ const item_actions = [
} }
]; ];
const bulk_actions = [
];
const SegmentList = React.createClass({ const SegmentList = React.createClass({
renderItem: function(segment, actions) { renderItem: function(segment, actions) {
var rowClasses = classNames( var rowClasses = classNames(
@ -211,7 +208,6 @@ const SegmentList = React.createClass({
endpoint="segments" endpoint="segments"
onRenderItem={ this.renderItem } onRenderItem={ this.renderItem }
columns={ columns } columns={ columns }
bulk_actions={ bulk_actions }
item_actions={ item_actions } item_actions={ item_actions }
/> />
</div> </div>

View File

@ -1,11 +1,11 @@
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { Router, Route, IndexRoute, Link } from 'react-router' import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
import SegmentList from 'segments/list.jsx' import SegmentList from 'segments/list.jsx'
import SegmentForm from 'segments/form.jsx' import SegmentForm from 'segments/form.jsx'
import createHashHistory from 'history/lib/createHashHistory'
let history = createHashHistory({ queryKey: false }) const history = useRouterHistory(createHashHistory)({ queryKey: false });
const App = React.createClass({ const App = React.createClass({
render() { render() {
@ -13,7 +13,7 @@ const App = React.createClass({
} }
}); });
let container = document.getElementById('segments_container'); const container = document.getElementById('segments_container');
if(container) { if(container) {
ReactDOM.render(( ReactDOM.render((

View File

@ -115,9 +115,6 @@ define(
var Link = Router.Link; var Link = Router.Link;
var SubscriberForm = React.createClass({ var SubscriberForm = React.createClass({
mixins: [
Router.History
],
render: function() { render: function() {
return ( return (
<div> <div>

View File

@ -1,11 +1,11 @@
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { Router, Route, IndexRoute, Link } from 'react-router' import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
import SubscriberList from 'subscribers/list.jsx' import SubscriberList from 'subscribers/list.jsx'
import SubscriberForm from 'subscribers/form.jsx' import SubscriberForm from 'subscribers/form.jsx'
import createHashHistory from 'history/lib/createHashHistory'
const history = createHashHistory({ queryKey: false }) const history = useRouterHistory(createHashHistory)({ queryKey: false });
const App = React.createClass({ const App = React.createClass({
render() { render() {

View File

@ -100,9 +100,9 @@ class Mailer {
} }
function getSender($sender = false) { function getSender($sender = false) {
if(!$sender) { if(empty($sender)) {
$sender = Setting::getValue('sender', null); $sender = Setting::getValue('sender', array());
if(!$sender['address']) throw new \Exception(__('Sender name and email are not configured.')); if(empty($sender['address'])) throw new \Exception(__('Sender name and email are not configured.'));
} }
return array( return array(
'from_name' => $sender['name'], 'from_name' => $sender['name'],

View File

@ -219,6 +219,37 @@ class Newsletter extends Model {
if($newsletter === false) { if($newsletter === false) {
$newsletter = self::create(); $newsletter = self::create();
// set default sender based on settings
if(empty($data['sender'])) {
$sender = Setting::getValue('sender', array());
$data['sender_name'] = (
!empty($sender['name'])
? $sender['name']
: ''
);
$data['sender_address'] = (
!empty($sender['address'])
? $sender['address']
: ''
);
}
// set default reply_to based on settings
if(empty($data['reply_to'])) {
$reply_to = Setting::getValue('reply_to', array());
$data['reply_to_name'] = (
!empty($reply_to['name'])
? $reply_to['name']
: ''
);
$data['reply_to_address'] = (
!empty($reply_to['address'])
? $reply_to['address']
: ''
);
}
$newsletter->hydrate($data); $newsletter->hydrate($data);
} else { } else {
unset($data['id']); unset($data['id']);

View File

@ -24,12 +24,12 @@
"napa": "^1.2.0", "napa": "^1.2.0",
"papaparse": "4.1.1", "papaparse": "4.1.1",
"parsleyjs": "^2.1.2", "parsleyjs": "^2.1.2",
"react": "0.14.3", "react": "latest",
"react-dom": "0.14.3", "react-dom": "latest",
"react-infinity": "1.2.2", "react-infinity": "latest",
"react-prefixr": "0.1.0", "react-prefixr": "latest",
"react-router": "1.0.2", "react-router": "latest",
"react-waypoint": "1.0.4", "react-waypoint": "latest",
"select2": "^4.0.0", "select2": "^4.0.0",
"spectrum-colorpicker": "^1.6.2", "spectrum-colorpicker": "^1.6.2",
"tinymce": "4.1.10", "tinymce": "4.1.10",

View File

@ -37,8 +37,7 @@
'restore': __('Restore'), 'restore': __('Restore'),
'deletePermanently': __('Delete Permanently'), 'deletePermanently': __('Delete Permanently'),
'save': __('Save'), 'save': __('Save'),
'numberOfItems': __('%$1d items'), 'numberOfItems': __('%$1d items'),
'segmentDescriptionTip': __('For your own use and never shown to your subscribers.')
}) %> }) %>
<% endblock %> <% endblock %>