From 5b077b3911a5b06ed0fb2e94c4e5d457eba42f4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tautvidas=20Sipavi=C4=8Dius?= Date: Thu, 1 Nov 2018 01:49:35 +0200 Subject: [PATCH] Fix newsletter related broken eslint rules --- assets/js/src/help/help.jsx | 5 + assets/js/src/newsletters/breadcrumb.jsx | 12 +- .../src/newsletters/listings/notification.jsx | 10 +- .../listings/notification_history.jsx | 9 +- .../js/src/newsletters/listings/standard.jsx | 9 +- assets/js/src/newsletters/listings/tabs.jsx | 5 + .../js/src/newsletters/listings/welcome.jsx | 10 +- assets/js/src/newsletters/newsletters.jsx | 5 + assets/js/src/newsletters/send.jsx | 27 +- assets/js/src/newsletters/send/date_text.jsx | 173 ++++++++++ assets/js/src/newsletters/send/date_time.jsx | 89 +++++ assets/js/src/newsletters/send/standard.jsx | 304 +++--------------- .../js/src/newsletters/send/time_select.jsx | 45 +++ assets/js/src/newsletters/types.jsx | 46 +-- .../types/notification/scheduling.jsx | 52 +-- assets/js/src/newsletters/types/standard.jsx | 8 +- .../newsletters/types/welcome/scheduling.jsx | 52 +-- 17 files changed, 479 insertions(+), 382 deletions(-) create mode 100644 assets/js/src/newsletters/send/date_text.jsx create mode 100644 assets/js/src/newsletters/send/date_time.jsx create mode 100644 assets/js/src/newsletters/send/time_select.jsx diff --git a/assets/js/src/help/help.jsx b/assets/js/src/help/help.jsx index 95699a68b3..eacabcab65 100644 --- a/assets/js/src/help/help.jsx +++ b/assets/js/src/help/help.jsx @@ -2,6 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Router, Route, IndexRedirect, useRouterHistory } from 'react-router'; import { createHashHistory } from 'history'; +import PropTypes from 'prop-types'; import SystemStatus from 'help/system_status.jsx'; import SystemInfo from 'help/system_info.jsx'; @@ -15,6 +16,10 @@ class App extends React.Component { } } +App.propTypes = { + children: PropTypes.element.isRequired, +}; + const container = document.getElementById('help_container'); if (container) { diff --git a/assets/js/src/newsletters/breadcrumb.jsx b/assets/js/src/newsletters/breadcrumb.jsx index 88719c3e90..00b7bd6a2a 100644 --- a/assets/js/src/newsletters/breadcrumb.jsx +++ b/assets/js/src/newsletters/breadcrumb.jsx @@ -1,6 +1,7 @@ import React from 'react'; import classNames from 'classnames'; import { Link } from 'react-router'; +import PropTypes from 'prop-types'; import MailPoet from 'mailpoet'; class Breadcrumb extends React.Component { @@ -64,5 +65,14 @@ class Breadcrumb extends React.Component { } } -module.exports = Breadcrumb; +Breadcrumb.propTypes = { + steps: PropTypes.arrayOf(PropTypes.object), + step: PropTypes.string, +}; +Breadcrumb.defaultProps = { + steps: undefined, + step: null, +}; + +module.exports = Breadcrumb; diff --git a/assets/js/src/newsletters/listings/notification.jsx b/assets/js/src/newsletters/listings/notification.jsx index 4cb2d7730c..3b7bc6fd10 100644 --- a/assets/js/src/newsletters/listings/notification.jsx +++ b/assets/js/src/newsletters/listings/notification.jsx @@ -1,6 +1,7 @@ import React from 'react'; import createReactClass from 'create-react-class'; import { Link } from 'react-router'; +import PropTypes from 'prop-types'; import Listing from 'listing/listing.jsx'; import ListingTabs from 'newsletters/listings/tabs.jsx'; @@ -158,8 +159,15 @@ const newsletterActions = [ }, ]; -const NewsletterListNotification = createReactClass({ +const NewsletterListNotification = createReactClass({ // eslint-disable-line react/prefer-es6-class + displayName: 'NewsletterListNotification', + + propTypes: { + location: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + params: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + }, + mixins: [MailerMixin, CronMixin], updateStatus: function updateStatus(e) { diff --git a/assets/js/src/newsletters/listings/notification_history.jsx b/assets/js/src/newsletters/listings/notification_history.jsx index e436e8956d..3761b9ea8c 100644 --- a/assets/js/src/newsletters/listings/notification_history.jsx +++ b/assets/js/src/newsletters/listings/notification_history.jsx @@ -4,6 +4,7 @@ import { Link } from 'react-router'; import classNames from 'classnames'; import MailPoet from 'mailpoet'; import Hooks from 'wp-js-hooks'; +import PropTypes from 'prop-types'; import Listing from 'listing/listing.jsx'; import ListingTabs from 'newsletters/listings/tabs.jsx'; @@ -58,8 +59,14 @@ let newsletterActions = [ Hooks.addFilter('mailpoet_newsletters_listings_notification_history_actions', StatisticsMixin.addStatsCTAAction); newsletterActions = Hooks.applyFilters('mailpoet_newsletters_listings_notification_history_actions', newsletterActions); -const NewsletterListNotificationHistory = createReactClass({ +const NewsletterListNotificationHistory = createReactClass({ // eslint-disable-line react/prefer-es6-class, max-len displayName: 'NewsletterListNotificationHistory', + + propTypes: { + location: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + params: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + }, + mixins: [QueueMixin, StatisticsMixin, MailerMixin, CronMixin], renderItem: function renderItem(newsletter, actions, meta) { diff --git a/assets/js/src/newsletters/listings/standard.jsx b/assets/js/src/newsletters/listings/standard.jsx index 7d636d5d96..db6769e5de 100644 --- a/assets/js/src/newsletters/listings/standard.jsx +++ b/assets/js/src/newsletters/listings/standard.jsx @@ -4,6 +4,7 @@ import { confirmAlert } from 'react-confirm-alert'; import classNames from 'classnames'; import MailPoet from 'mailpoet'; import Hooks from 'wp-js-hooks'; +import PropTypes from 'prop-types'; import Listing from 'listing/listing.jsx'; import ListingTabs from 'newsletters/listings/tabs.jsx'; @@ -173,8 +174,14 @@ let newsletterActions = [ Hooks.addFilter('mailpoet_newsletters_listings_standard_actions', StatisticsMixin.addStatsCTAAction); newsletterActions = Hooks.applyFilters('mailpoet_newsletters_listings_standard_actions', newsletterActions); -const NewsletterListStandard = createReactClass({ +const NewsletterListStandard = createReactClass({ // eslint-disable-line react/prefer-es6-class displayName: 'NewsletterListStandard', + + propTypes: { + location: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + params: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + }, + mixins: [QueueMixin, StatisticsMixin, MailerMixin, CronMixin], renderItem: function renderItem(newsletter, actions, meta) { diff --git a/assets/js/src/newsletters/listings/tabs.jsx b/assets/js/src/newsletters/listings/tabs.jsx index 7ae72d92e3..4a727e92e2 100644 --- a/assets/js/src/newsletters/listings/tabs.jsx +++ b/assets/js/src/newsletters/listings/tabs.jsx @@ -3,6 +3,7 @@ import { Link } from 'react-router'; import classNames from 'classnames'; import MailPoet from 'mailpoet'; import Hooks from 'wp-js-hooks'; +import PropTypes from 'prop-types'; class ListingTabs extends React.Component { state = { @@ -53,4 +54,8 @@ class ListingTabs extends React.Component { } } +ListingTabs.propTypes = { + tab: PropTypes.string.isRequired, +}; + module.exports = ListingTabs; diff --git a/assets/js/src/newsletters/listings/welcome.jsx b/assets/js/src/newsletters/listings/welcome.jsx index 9c6aba41fa..4bef6725ca 100644 --- a/assets/js/src/newsletters/listings/welcome.jsx +++ b/assets/js/src/newsletters/listings/welcome.jsx @@ -1,6 +1,6 @@ import React from 'react'; - import createReactClass from 'create-react-class'; +import PropTypes from 'prop-types'; import Listing from 'listing/listing.jsx'; import ListingTabs from 'newsletters/listings/tabs.jsx'; @@ -155,8 +155,14 @@ let newsletterActions = [ Hooks.addFilter('mailpoet_newsletters_listings_welcome_notification_actions', StatisticsMixin.addStatsCTAAction); newsletterActions = Hooks.applyFilters('mailpoet_newsletters_listings_welcome_notification_actions', newsletterActions); -const NewsletterListWelcome = createReactClass({ +const NewsletterListWelcome = createReactClass({ // eslint-disable-line react/prefer-es6-class displayName: 'NewsletterListWelcome', + + propTypes: { + location: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + params: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + }, + mixins: [StatisticsMixin, MailerMixin, CronMixin], updateStatus: function updateStatus(e) { diff --git a/assets/js/src/newsletters/newsletters.jsx b/assets/js/src/newsletters/newsletters.jsx index 3fbf99f35b..32fad98194 100644 --- a/assets/js/src/newsletters/newsletters.jsx +++ b/assets/js/src/newsletters/newsletters.jsx @@ -4,6 +4,7 @@ import { Router, Route, IndexRedirect, useRouterHistory } from 'react-router'; import { createHashHistory } from 'history'; import Hooks from 'wp-js-hooks'; import _ from 'underscore'; +import PropTypes from 'prop-types'; import NewsletterTypes from 'newsletters/types.jsx'; import NewsletterTemplates from 'newsletters/templates.jsx'; @@ -25,6 +26,10 @@ class App extends React.Component { } } +App.propTypes = { + children: PropTypes.element.isRequired, +}; + const container = document.getElementById('newsletters_container'); const getAutomaticEmailsRoutes = () => { diff --git a/assets/js/src/newsletters/send.jsx b/assets/js/src/newsletters/send.jsx index c89aa1dbd9..ee368f4c79 100644 --- a/assets/js/src/newsletters/send.jsx +++ b/assets/js/src/newsletters/send.jsx @@ -11,10 +11,17 @@ import HelpTooltip from 'help-tooltip.jsx'; import jQuery from 'jquery'; import { fromUrl } from 'common/thumbnail.jsx'; import Hooks from 'wp-js-hooks'; +import PropTypes from 'prop-types'; -const NewsletterSend = createReactClass({ +const NewsletterSend = createReactClass({ // eslint-disable-line react/prefer-es6-class displayName: 'NewsletterSend', + propTypes: { + params: PropTypes.shape({ + id: PropTypes.string, + }).isRequired, + }, + contextTypes: { router: React.PropTypes.object.isRequired, }, @@ -27,6 +34,15 @@ const NewsletterSend = createReactClass({ }; }, + componentDidMount: function componentDidMount() { + this.loadItem(this.props.params.id); + jQuery('#mailpoet_newsletter').parsley(); + }, + + componentWillReceiveProps: function componentWillReceiveProps(props) { + this.loadItem(props.params.id); + }, + getFieldsByNewsletter: function getFieldsByNewsletter(newsletter) { const type = this.getSubtype(newsletter); return type.getFields(newsletter); @@ -49,15 +65,6 @@ const NewsletterSend = createReactClass({ return jQuery('#mailpoet_newsletter').parsley().isValid(); }, - componentDidMount: function componentDidMount() { - this.loadItem(this.props.params.id); - jQuery('#mailpoet_newsletter').parsley(); - }, - - componentWillReceiveProps: function componentWillReceiveProps(props) { - this.loadItem(props.params.id); - }, - loadItem: function loadItem(id) { this.setState({ loading: true }); diff --git a/assets/js/src/newsletters/send/date_text.jsx b/assets/js/src/newsletters/send/date_text.jsx new file mode 100644 index 0000000000..b30da4aacc --- /dev/null +++ b/assets/js/src/newsletters/send/date_text.jsx @@ -0,0 +1,173 @@ +import React from 'react'; +import jQuery from 'jquery'; +import _ from 'underscore'; +import MailPoet from 'mailpoet'; +import PropTypes from 'prop-types'; + +const datepickerTranslations = { + closeText: MailPoet.I18n.t('close'), + currentText: MailPoet.I18n.t('today'), + nextText: MailPoet.I18n.t('next'), + prevText: MailPoet.I18n.t('previous'), + monthNames: [ + MailPoet.I18n.t('january'), + MailPoet.I18n.t('february'), + MailPoet.I18n.t('march'), + MailPoet.I18n.t('april'), + MailPoet.I18n.t('may'), + MailPoet.I18n.t('june'), + MailPoet.I18n.t('july'), + MailPoet.I18n.t('august'), + MailPoet.I18n.t('september'), + MailPoet.I18n.t('october'), + MailPoet.I18n.t('november'), + MailPoet.I18n.t('december'), + ], + monthNamesShort: [ + MailPoet.I18n.t('januaryShort'), + MailPoet.I18n.t('februaryShort'), + MailPoet.I18n.t('marchShort'), + MailPoet.I18n.t('aprilShort'), + MailPoet.I18n.t('mayShort'), + MailPoet.I18n.t('juneShort'), + MailPoet.I18n.t('julyShort'), + MailPoet.I18n.t('augustShort'), + MailPoet.I18n.t('septemberShort'), + MailPoet.I18n.t('octoberShort'), + MailPoet.I18n.t('novemberShort'), + MailPoet.I18n.t('decemberShort'), + ], + dayNames: [ + MailPoet.I18n.t('sunday'), + MailPoet.I18n.t('monday'), + MailPoet.I18n.t('tuesday'), + MailPoet.I18n.t('wednesday'), + MailPoet.I18n.t('thursday'), + MailPoet.I18n.t('friday'), + MailPoet.I18n.t('saturday'), + ], + dayNamesShort: [ + MailPoet.I18n.t('sundayShort'), + MailPoet.I18n.t('mondayShort'), + MailPoet.I18n.t('tuesdayShort'), + MailPoet.I18n.t('wednesdayShort'), + MailPoet.I18n.t('thursdayShort'), + MailPoet.I18n.t('fridayShort'), + MailPoet.I18n.t('saturdayShort'), + ], + dayNamesMin: [ + MailPoet.I18n.t('sundayMin'), + MailPoet.I18n.t('mondayMin'), + MailPoet.I18n.t('tuesdayMin'), + MailPoet.I18n.t('wednesdayMin'), + MailPoet.I18n.t('thursdayMin'), + MailPoet.I18n.t('fridayMin'), + MailPoet.I18n.t('saturdayMin'), + ], +}; + +class DateText extends React.Component { + componentDidMount() { + const $element = jQuery(this.dateInput); + const that = this; + if ($element.datepicker) { + // Override jQuery UI datepicker Date parsing and formatting + jQuery.datepicker.parseDate = function parseDate(format, value) { + // Transform string format to Date object + return MailPoet.Date.toDate(value, { + parseFormat: this.props.dateDisplayFormat, + format, + }); + }; + jQuery.datepicker.formatDate = function formatDate(format, value) { + // Transform Date object to string format + const newValue = MailPoet.Date.format(value, { + format, + }); + return newValue; + }; + + $element.datepicker(_.extend({ + dateFormat: this.props.displayFormat, + isRTL: false, + onSelect: function onSelect(value) { + that.onChange({ + target: { + name: that.getFieldName(), + value, + }, + }); + }, + }, datepickerTranslations)); + + this.datepickerInitialized = true; + } + } + + componentWillUnmount() { + if (this.datepickerInitialized) { + jQuery(this.dateInput).datepicker('destroy'); + } + } + + onChange = (event) => { + const changeEvent = event; + // Swap display format to storage format + const displayDate = changeEvent.target.value; + const storageDate = this.getStorageDate(displayDate); + + changeEvent.target.value = storageDate; + this.props.onChange(changeEvent); + }; + + getFieldName = () => this.props.name || 'date'; + + getDisplayDate = (date) => { + const formatting = { + parseFormat: this.props.storageFormat, + format: this.props.displayFormat, + }; + return MailPoet.Date.format(date, formatting); + }; + + getStorageDate = (date) => { + const formatting = { + parseFormat: this.props.displayFormat, + format: this.props.storageFormat, + }; + return MailPoet.Date.format(date, formatting); + }; + + render() { + return ( + { this.dateInput = c; }} + {...this.props.validation} + /> + ); + } +} + +DateText.propTypes = { + displayFormat: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, + name: PropTypes.string, + storageFormat: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + disabled: PropTypes.bool.isRequired, + validation: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + dateDisplayFormat: PropTypes.string.isRequired, +}; + +DateText.defaultProps = { + name: 'date', +}; + +module.exports = DateText; diff --git a/assets/js/src/newsletters/send/date_time.jsx b/assets/js/src/newsletters/send/date_time.jsx new file mode 100644 index 0000000000..ef0c54157e --- /dev/null +++ b/assets/js/src/newsletters/send/date_time.jsx @@ -0,0 +1,89 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import DateText from 'newsletters/send/date_text.jsx'; +import TimeSelect from 'newsletters/send/time_select.jsx'; + +class DateTime extends React.Component { + state = this.buildStateFromProps(this.props); + + componentWillReceiveProps(nextProps) { + this.setState(this.buildStateFromProps(nextProps)); + } + + getDateTime = () => [this.state.date, this.state.time].join(this.DATE_TIME_SEPARATOR); + + DATE_TIME_SEPARATOR = ' '; + + buildStateFromProps = (props) => { + const value = props.value || this.props.defaultDateTime; + const [date, time] = value.split(this.DATE_TIME_SEPARATOR); + return { + date, + time, + }; + }; + + handleChange = (event) => { + const newState = {}; + newState[event.target.name] = event.target.value; + + this.setState(newState, this.propagateChange); + }; + + propagateChange = () => { + if (this.props.onChange) { + this.props.onChange({ + target: { + name: this.props.name || '', + value: this.getDateTime(), + }, + }); + } + }; + + render() { + return ( + + + + + ); + } +} + +DateTime.propTypes = { + defaultDateTime: PropTypes.string.isRequired, + dateDisplayFormat: PropTypes.string.isRequired, + dateStorageFormat: PropTypes.string.isRequired, + onChange: PropTypes.func, + name: PropTypes.string, + disabled: PropTypes.bool, + dateValidation: PropTypes.objectOf(PropTypes.string).isRequired, + timeValidation: PropTypes.any, // eslint-disable-line react/forbid-prop-types + timeOfDayItems: PropTypes.objectOf(PropTypes.string).isRequired, +}; + +DateTime.defaultProps = { + onChange: undefined, + name: '', + disabled: false, + timeValidation: undefined, +}; + +module.exports = DateTime; diff --git a/assets/js/src/newsletters/send/standard.jsx b/assets/js/src/newsletters/send/standard.jsx index 49519b453a..5d5289eeea 100644 --- a/assets/js/src/newsletters/send/standard.jsx +++ b/assets/js/src/newsletters/send/standard.jsx @@ -1,8 +1,10 @@ import React from 'react'; -import jQuery from 'jquery'; import _ from 'underscore'; import MailPoet from 'mailpoet'; import Hooks from 'wp-js-hooks'; +import PropTypes from 'prop-types'; + +import DateTime from 'newsletters/send/date_time.jsx'; const currentTime = window.mailpoet_current_time || '00:00'; const defaultDateTime = `${window.mailpoet_current_date} 00:00:00`; @@ -10,259 +12,32 @@ const timeOfDayItems = window.mailpoet_schedule_time_of_day; const dateDisplayFormat = window.mailpoet_date_display_format; const dateStorageFormat = window.mailpoet_date_storage_format; -const datepickerTranslations = { - closeText: MailPoet.I18n.t('close'), - currentText: MailPoet.I18n.t('today'), - nextText: MailPoet.I18n.t('next'), - prevText: MailPoet.I18n.t('previous'), - monthNames: [ - MailPoet.I18n.t('january'), - MailPoet.I18n.t('february'), - MailPoet.I18n.t('march'), - MailPoet.I18n.t('april'), - MailPoet.I18n.t('may'), - MailPoet.I18n.t('june'), - MailPoet.I18n.t('july'), - MailPoet.I18n.t('august'), - MailPoet.I18n.t('september'), - MailPoet.I18n.t('october'), - MailPoet.I18n.t('november'), - MailPoet.I18n.t('december'), - ], - monthNamesShort: [ - MailPoet.I18n.t('januaryShort'), - MailPoet.I18n.t('februaryShort'), - MailPoet.I18n.t('marchShort'), - MailPoet.I18n.t('aprilShort'), - MailPoet.I18n.t('mayShort'), - MailPoet.I18n.t('juneShort'), - MailPoet.I18n.t('julyShort'), - MailPoet.I18n.t('augustShort'), - MailPoet.I18n.t('septemberShort'), - MailPoet.I18n.t('octoberShort'), - MailPoet.I18n.t('novemberShort'), - MailPoet.I18n.t('decemberShort'), - ], - dayNames: [ - MailPoet.I18n.t('sunday'), - MailPoet.I18n.t('monday'), - MailPoet.I18n.t('tuesday'), - MailPoet.I18n.t('wednesday'), - MailPoet.I18n.t('thursday'), - MailPoet.I18n.t('friday'), - MailPoet.I18n.t('saturday'), - ], - dayNamesShort: [ - MailPoet.I18n.t('sundayShort'), - MailPoet.I18n.t('mondayShort'), - MailPoet.I18n.t('tuesdayShort'), - MailPoet.I18n.t('wednesdayShort'), - MailPoet.I18n.t('thursdayShort'), - MailPoet.I18n.t('fridayShort'), - MailPoet.I18n.t('saturdayShort'), - ], - dayNamesMin: [ - MailPoet.I18n.t('sundayMin'), - MailPoet.I18n.t('mondayMin'), - MailPoet.I18n.t('tuesdayMin'), - MailPoet.I18n.t('wednesdayMin'), - MailPoet.I18n.t('thursdayMin'), - MailPoet.I18n.t('fridayMin'), - MailPoet.I18n.t('saturdayMin'), - ], -}; - -class DateText extends React.Component { - onChange = (event) => { - const changeEvent = event; - // Swap display format to storage format - const displayDate = changeEvent.target.value; - const storageDate = this.getStorageDate(displayDate); - - changeEvent.target.value = storageDate; - this.props.onChange(changeEvent); - }; - - componentDidMount() { - const $element = jQuery(this.dateInput); - const that = this; - if ($element.datepicker) { - // Override jQuery UI datepicker Date parsing and formatting - jQuery.datepicker.parseDate = function parseDate(format, value) { - // Transform string format to Date object - return MailPoet.Date.toDate(value, { - parseFormat: dateDisplayFormat, - format, - }); - }; - jQuery.datepicker.formatDate = function formatDate(format, value) { - // Transform Date object to string format - const newValue = MailPoet.Date.format(value, { - format, - }); - return newValue; - }; - - $element.datepicker(_.extend({ - dateFormat: this.props.displayFormat, - isRTL: false, - onSelect: function onSelect(value) { - that.onChange({ - target: { - name: that.getFieldName(), - value, - }, - }); - }, - }, datepickerTranslations)); - - this.datepickerInitialized = true; - } - } - - componentWillUnmount() { - if (this.datepickerInitialized) { - jQuery(this.dateInput).datepicker('destroy'); - } - } - - getFieldName = () => { - return this.props.name || 'date'; - }; - - getDisplayDate = (date) => { - return MailPoet.Date.format(date, { - parseFormat: this.props.storageFormat, - format: this.props.displayFormat, - }); - }; - - getStorageDate = (date) => { - return MailPoet.Date.format(date, { - parseFormat: this.props.displayFormat, - format: this.props.storageFormat, - }); - }; - - render() { - return ( - { this.dateInput = c; }} - {...this.props.validation} - /> - ); - } -} - -class TimeSelect extends React.Component { - render() { - const options = Object.keys(timeOfDayItems).map( - value => ( - - ) - ); - - return ( - - ); - } -} - -class DateTime extends React.Component { - DATE_TIME_SEPARATOR = ' '; - - componentWillReceiveProps(nextProps) { - this.setState(this.buildStateFromProps(nextProps)); - } - - buildStateFromProps = (props) => { - const value = props.value || defaultDateTime; - const [date, time] = value.split(this.DATE_TIME_SEPARATOR); - return { - date, - time, - }; - }; - - handleChange = (event) => { - const newState = {}; - newState[event.target.name] = event.target.value; - - this.setState(newState, this.propagateChange); - }; - - propagateChange = () => { - if (this.props.onChange) { - this.props.onChange({ - target: { - name: this.props.name || '', - value: this.getDateTime(), - }, - }); - } - }; - - getDateTime = () => { - return [this.state.date, this.state.time].join(this.DATE_TIME_SEPARATOR); - }; - - state = this.buildStateFromProps(this.props); - - render() { - return ( - - - - - ); - } -} - class StandardScheduling extends React.Component { getCurrentValue = () => { + const schedulingOptions = { + isScheduled: '0', + scheduledAt: defaultDateTime, + }; return _.defaults( this.props.item[this.props.field.name] || {}, - { - isScheduled: '0', - scheduledAt: defaultDateTime, - } + schedulingOptions ); }; + getDateValidation = () => ({ + 'data-parsley-required': true, + 'data-parsley-required-message': MailPoet.I18n.t('noScheduledDateError'), + 'data-parsley-errors-container': '#mailpoet_scheduling', + }); + + isScheduled = () => this.getCurrentValue().isScheduled === '1'; + + handleCheckboxChange = (event) => { + const changeEvent = event; + changeEvent.target.value = this.isScheduledInput.checked ? '1' : '0'; + return this.handleValueChange(changeEvent); + }; + handleValueChange = (event) => { const oldValue = this.getCurrentValue(); const newValue = {}; @@ -276,24 +51,6 @@ class StandardScheduling extends React.Component { }); }; - handleCheckboxChange = (event) => { - const changeEvent = event; - changeEvent.target.value = this.isScheduledInput.checked ? '1' : '0'; - return this.handleValueChange(changeEvent); - }; - - isScheduled = () => { - return this.getCurrentValue().isScheduled === '1'; - }; - - getDateValidation = () => { - return { - 'data-parsley-required': true, - 'data-parsley-required-message': MailPoet.I18n.t('noScheduledDateError'), - 'data-parsley-errors-container': '#mailpoet_scheduling', - }; - }; - render() { let schedulingOptions; @@ -306,6 +63,10 @@ class StandardScheduling extends React.Component { onChange={this.handleValueChange} disabled={this.props.field.disabled} dateValidation={this.getDateValidation()} + defaultDateTime={defaultDateTime} + timeOfDayItems={timeOfDayItems} + dateDisplayFormat={dateDisplayFormat} + dateStorageFormat={dateStorageFormat} />   @@ -332,6 +93,19 @@ class StandardScheduling extends React.Component { } } +StandardScheduling.propTypes = { + item: PropTypes.object, // eslint-disable-line react/forbid-prop-types + field: PropTypes.shape({ + name: PropTypes.string.isRequired, + disabled: PropTypes.bool, + }).isRequired, + onValueChange: PropTypes.func.isRequired, +}; + +StandardScheduling.defaultProps = { + item: {}, +}; + let fields = [ { name: 'subject', diff --git a/assets/js/src/newsletters/send/time_select.jsx b/assets/js/src/newsletters/send/time_select.jsx new file mode 100644 index 0000000000..0617895c1d --- /dev/null +++ b/assets/js/src/newsletters/send/time_select.jsx @@ -0,0 +1,45 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +class TimeSelect extends React.Component { // eslint-disable-line react/prefer-stateless-function + render() { + const options = Object.keys(this.props.timeOfDayItems).map( + value => ( + + ) + ); + + return ( + + ); + } +} + +TimeSelect.propTypes = { + timeOfDayItems: PropTypes.objectOf(PropTypes.string).isRequired, + name: PropTypes.string, + value: PropTypes.string.isRequired, + disabled: PropTypes.bool, + onChange: PropTypes.func.isRequired, + validation: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types +}; + +TimeSelect.defaultProps = { + name: 'time', + disabled: false, +}; + +module.exports = TimeSelect; diff --git a/assets/js/src/newsletters/types.jsx b/assets/js/src/newsletters/types.jsx index 6ccd3660c8..1d846c694a 100644 --- a/assets/js/src/newsletters/types.jsx +++ b/assets/js/src/newsletters/types.jsx @@ -20,6 +20,29 @@ class NewsletterTypes extends React.Component { } }; + getAutomaticEmails = () => { + if (!window.mailpoet_automatic_emails) return []; + + return _.map(window.mailpoet_automatic_emails, (automaticEmail) => { + const email = automaticEmail; + const onClick = _.partial(this.setupNewsletter, automaticEmail.slug); + email.action = (() => ( +
+ + { MailPoet.I18n.t('setUp') } + +
+ ))(); + + return email; + }); + }; + createNewsletter = (type) => { MailPoet.trackEvent('Emails > Type selected', { 'MailPoet Free version': window.mailpoet_version, @@ -45,29 +68,6 @@ class NewsletterTypes extends React.Component { }); }; - getAutomaticEmails = () => { - if (!window.mailpoet_automatic_emails) return []; - - return _.map(window.mailpoet_automatic_emails, (automaticEmail) => { - const email = automaticEmail; - const onClick = _.partial(this.setupNewsletter, automaticEmail.slug); - email.action = (() => ( -
- - { MailPoet.I18n.t('setUp') } - -
- ))(); - - return email; - }); - }; - render() { const createStandardNewsletter = _.partial(this.createNewsletter, 'standard'); const createNotificationNewsletter = _.partial(this.setupNewsletter, 'notification'); diff --git a/assets/js/src/newsletters/types/notification/scheduling.jsx b/assets/js/src/newsletters/types/notification/scheduling.jsx index f6dd7d0d91..5671a3a5c1 100644 --- a/assets/js/src/newsletters/types/notification/scheduling.jsx +++ b/assets/js/src/newsletters/types/notification/scheduling.jsx @@ -1,5 +1,6 @@ import _ from 'underscore'; import React from 'react'; +import PropTypes from 'prop-types'; import Select from 'form/fields/select.jsx'; import { intervalValues, @@ -35,9 +36,7 @@ const nthWeekDayField = { }; class NotificationScheduling extends React.Component { - getCurrentValue = () => { - return (this.props.item[this.props.field.name] || {}); - }; + getCurrentValue = () => this.props.item[this.props.field.name] || {}; handleValueChange = (name, value) => { const oldValue = this.getCurrentValue(); @@ -53,40 +52,11 @@ class NotificationScheduling extends React.Component { }); }; - handleIntervalChange = (event) => { - return this.handleValueChange( - 'intervalType', - event.target.value - ); - }; - - handleTimeOfDayChange = (event) => { - return this.handleValueChange( - 'timeOfDay', - event.target.value - ); - }; - - handleWeekDayChange = (event) => { - return this.handleValueChange( - 'weekDay', - event.target.value - ); - }; - - handleMonthDayChange = (event) => { - return this.handleValueChange( - 'monthDay', - event.target.value - ); - }; - - handleNthWeekDayChange = (event) => { - return this.handleValueChange( - 'nthWeekDay', - event.target.value - ); - }; + handleIntervalChange = event => this.handleValueChange('intervalType', event.target.value); + handleTimeOfDayChange = event => this.handleValueChange('timeOfDay', event.target.value); + handleWeekDayChange = event => this.handleValueChange('weekDay', event.target.value); + handleMonthDayChange = event => this.handleValueChange('monthDay', event.target.value); + handleNthWeekDayChange = event => this.handleValueChange('nthWeekDay', event.target.value); render() { const value = this.getCurrentValue(); @@ -153,4 +123,12 @@ class NotificationScheduling extends React.Component { } } +NotificationScheduling.propTypes = { + item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + field: PropTypes.shape({ + name: PropTypes.string, + }).isRequired, + onValueChange: PropTypes.func.isRequired, +}; + module.exports = NotificationScheduling; diff --git a/assets/js/src/newsletters/types/standard.jsx b/assets/js/src/newsletters/types/standard.jsx index 3559d5f600..4ab453ff37 100644 --- a/assets/js/src/newsletters/types/standard.jsx +++ b/assets/js/src/newsletters/types/standard.jsx @@ -7,10 +7,6 @@ class NewsletterStandard extends React.Component { router: React.PropTypes.object.isRequired, }; - showTemplateSelection = (newsletterId) => { - this.context.router.push(`/template/${newsletterId}`); - }; - componentDidMount() { // No options for this type, create a newsletter upon mounting MailPoet.Ajax.post({ @@ -32,6 +28,10 @@ class NewsletterStandard extends React.Component { }); } + showTemplateSelection = (newsletterId) => { + this.context.router.push(`/template/${newsletterId}`); + }; + render() { return (
diff --git a/assets/js/src/newsletters/types/welcome/scheduling.jsx b/assets/js/src/newsletters/types/welcome/scheduling.jsx index cf37361dd6..6d3b2dfd04 100644 --- a/assets/js/src/newsletters/types/welcome/scheduling.jsx +++ b/assets/js/src/newsletters/types/welcome/scheduling.jsx @@ -4,6 +4,7 @@ import MailPoet from 'mailpoet'; import Select from 'form/fields/select.jsx'; import Text from 'form/fields/text.jsx'; import { timeDelayValues } from 'newsletters/scheduling/common.jsx'; +import PropTypes from 'prop-types'; const availableRoles = window.mailpoet_roles || {}; const availableSegments = _.filter( @@ -52,9 +53,7 @@ class WelcomeScheduling extends React.Component { router: React.PropTypes.object.isRequired, }; - getCurrentValue = () => { - return (this.props.item[this.props.field.name] || {}); - }; + getCurrentValue = () => this.props.item[this.props.field.name] || {}; handleValueChange = (name, value) => { const oldValue = this.getCurrentValue(); @@ -70,40 +69,11 @@ class WelcomeScheduling extends React.Component { }); }; - handleEventChange = (event) => { - return this.handleValueChange( - 'event', - event.target.value - ); - }; - - handleSegmentChange = (event) => { - return this.handleValueChange( - 'segment', - event.target.value - ); - }; - - handleRoleChange = (event) => { - return this.handleValueChange( - 'role', - event.target.value - ); - }; - - handleAfterTimeNumberChange = (event) => { - return this.handleValueChange( - 'afterTimeNumber', - event.target.value - ); - }; - - handleAfterTimeTypeChange = (event) => { - return this.handleValueChange( - 'afterTimeType', - event.target.value - ); - }; + handleEventChange = event => this.handleValueChange('event', event.target.value); + handleSegmentChange = event => this.handleValueChange('segment', event.target.value); + handleRoleChange = event => this.handleValueChange('role', event.target.value); + handleAfterTimeNumberChange = event => this.handleValueChange('afterTimeNumber', event.target.value); + handleAfterTimeTypeChange = event => this.handleValueChange('afterTimeType', event.target.value); handleNext = () => { MailPoet.Ajax.post({ @@ -184,4 +154,12 @@ class WelcomeScheduling extends React.Component { } } +WelcomeScheduling.propTypes = { + item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + field: PropTypes.shape({ + name: PropTypes.string, + }).isRequired, + onValueChange: PropTypes.func.isRequired, +}; + module.exports = WelcomeScheduling;