Add warnings to manipulation step
[MAILPOET-1809]
This commit is contained in:
@@ -11,97 +11,19 @@ import StepInputValidation from './import/step_input_validation.jsx';
|
||||
import StepMethodSelection from './import/step_method_selection.jsx';
|
||||
import StepResults from './import/step_results.jsx';
|
||||
|
||||
const SUBSCRIBERS_LIMIT_FOR_VALIDATION = 500;
|
||||
|
||||
function getDataManipulationPreviousStepLink(importData) {
|
||||
if (importData === undefined) {
|
||||
return 'step_method_selection';
|
||||
}
|
||||
if (importData.subscribersCount === undefined) {
|
||||
return 'step_method_selection';
|
||||
}
|
||||
if (importData.subscribersCount < SUBSCRIBERS_LIMIT_FOR_VALIDATION) {
|
||||
return 'step_method_selection';
|
||||
}
|
||||
return 'step_input_validation';
|
||||
}
|
||||
|
||||
jQuery(document).ready(() => {
|
||||
if (!jQuery('#mailpoet_subscribers_import').length) {
|
||||
return;
|
||||
}
|
||||
jQuery('input[name="select_method"]').attr('checked', false);
|
||||
// configure router
|
||||
const router = new (Backbone.Router.extend({
|
||||
routes: {
|
||||
'': 'home',
|
||||
step_method_selection: 'step_method_selection',
|
||||
step_input_validation: 'step_input_validation',
|
||||
step_data_manipulation: 'step_data_manipulation',
|
||||
step_results: 'step_results',
|
||||
},
|
||||
home() {
|
||||
this.navigate('step_method_selection', { trigger: true });
|
||||
},
|
||||
}))();
|
||||
|
||||
function showCurrentStep() {
|
||||
MailPoet.Notice.hide();
|
||||
MailPoet.Modal.loading(false);
|
||||
jQuery('#mailpoet_subscribers_import > div[id^="step"]').hide();
|
||||
jQuery(window.location.hash).show();
|
||||
}
|
||||
|
||||
router.on('route:step_method_selection', () => {
|
||||
showCurrentStep();
|
||||
|
||||
const container = document.getElementById('step_method_selection');
|
||||
|
||||
if (container) {
|
||||
ReactDOM.render(
|
||||
<StepMethodSelection
|
||||
navigate={router.navigate}
|
||||
/>,
|
||||
container
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
router.on('route:step_input_validation', () => {
|
||||
if (typeof (window.importData.step_method_selection) === 'undefined') {
|
||||
router.navigate('step_method_selection', { trigger: true });
|
||||
return;
|
||||
}
|
||||
showCurrentStep();
|
||||
const container = document.getElementById('step_input_validation');
|
||||
|
||||
if (container) {
|
||||
ReactDOM.render(
|
||||
<StepInputValidation
|
||||
navigate={router.navigate}
|
||||
importData={window.importData.step_method_selection}
|
||||
/>,
|
||||
container
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
router.on('route:step_data_manipulation', () => {
|
||||
let fillerPosition;
|
||||
let importResults;
|
||||
let duplicates;
|
||||
if (typeof (window.importData.step_method_selection) === 'undefined') {
|
||||
router.navigate('step_method_selection', { trigger: true });
|
||||
return;
|
||||
}
|
||||
|
||||
// define reusable variables
|
||||
const nextStepButton = jQuery('#next_step');
|
||||
const previousStepButton = jQuery('#return_to_previous');
|
||||
|
||||
// create a copy of subscribers object for further manipulation
|
||||
const subscribers = jQuery.extend(true, {}, window.importData.step_method_selection);
|
||||
const subscribersDataTemplate = Handlebars.compile(jQuery('#subscribers_data_template').html());
|
||||
const subscribersDataTemplatePartial = Handlebars.compile(jQuery('#subscribers_data_template_partial').html());
|
||||
const subscribersDataParseResultsTemplate = Handlebars.compile(jQuery('#subscribers_data_parse_results_template').html());
|
||||
const segmentSelectElement = jQuery('#mailpoet_segments_select');
|
||||
const maxRowsToShow = 10;
|
||||
const filler = '. . .';
|
||||
@@ -110,8 +32,6 @@ jQuery(document).ready(() => {
|
||||
const fillerArray = Array(...new Array(subscribers.subscribers[0].length))
|
||||
.map(String.prototype.valueOf, filler);
|
||||
|
||||
showCurrentStep();
|
||||
|
||||
function toggleNextStepButton(condition) {
|
||||
const disabled = 'button-disabled';
|
||||
if (condition === 'on') {
|
||||
@@ -125,61 +45,6 @@ jQuery(document).ready(() => {
|
||||
jQuery('#subscribers_data_parse_results:visible').html('');
|
||||
jQuery('#subscribers_data_import_results:visible').hide();
|
||||
|
||||
// show parse statistics if any duplicate/invalid records were found
|
||||
if (subscribers.invalid.length || subscribers.duplicate.length || subscribers.role.length) {
|
||||
// count repeating e-mails inside duplicate array and present them in
|
||||
// 'email (xN)' format
|
||||
duplicates = {};
|
||||
subscribers.duplicate.forEach((subscriberEmail) => {
|
||||
duplicates[subscriberEmail] = (duplicates[subscriberEmail] || 0) + 1;
|
||||
});
|
||||
subscribers.duplicate = [];
|
||||
Object.keys(duplicates).forEach((email) => {
|
||||
if (duplicates[email] > 1) {
|
||||
subscribers.duplicate.push(`${email} (x${duplicates[email]})`);
|
||||
} else {
|
||||
subscribers.duplicate.push(email);
|
||||
}
|
||||
});
|
||||
|
||||
importResults = {
|
||||
notice: MailPoet.I18n.t('importNoticeSkipped').replace(
|
||||
'%1$s',
|
||||
`<strong>${subscribers.invalid.length + subscribers.duplicate.length + subscribers.role.length}</strong>`
|
||||
),
|
||||
invalid: (subscribers.invalid.length)
|
||||
? MailPoet.I18n.t('importNoticeInvalid')
|
||||
.replace('%1$s', `<strong>${subscribers.invalid.length.toLocaleString()}</strong>`)
|
||||
.replace('%2$s', subscribers.invalid.join(', '))
|
||||
: null,
|
||||
duplicate: (subscribers.duplicate.length)
|
||||
? MailPoet.I18n.t('importNoticeDuplicate')
|
||||
.replace('%1$s', `<strong>${subscribers.duplicate.length}</strong>`)
|
||||
.replace('%2$s', subscribers.duplicate.join(', '))
|
||||
: null,
|
||||
role: (subscribers.role.length)
|
||||
? MailPoet.I18n.t('importNoticeRoleBased')
|
||||
.replace('%1$s', `<strong>${subscribers.role.length.toLocaleString()}</strong>`)
|
||||
.replace('%2$s', subscribers.role.join(', '))
|
||||
.replace(
|
||||
/\[link](.+)\[\/link]/,
|
||||
'<a href="https://kb.mailpoet.com/article/270-role-based-email-addresses-are-not-allowed" target="_blank" rel="noopener noreferrer">$1</a>'
|
||||
)
|
||||
: null,
|
||||
};
|
||||
jQuery('#subscribers_data_parse_results').html(
|
||||
subscribersDataParseResultsTemplate(importResults)
|
||||
);
|
||||
}
|
||||
|
||||
jQuery('.mailpoet_subscribers_data_parse_results_details_show')
|
||||
.click(function detailsClick() {
|
||||
const details = jQuery('.mailpoet_subscribers_data_parse_results_details');
|
||||
details.toggle();
|
||||
jQuery(this).text((details.is(':visible'))
|
||||
? MailPoet.I18n.t('hideDetails')
|
||||
: MailPoet.I18n.t('showDetails'));
|
||||
});
|
||||
|
||||
// show available segments
|
||||
if (window.mailpoetSegments.length) {
|
||||
@@ -610,12 +475,6 @@ jQuery(document).ready(() => {
|
||||
filterSubscribers();
|
||||
});
|
||||
|
||||
previousStepButton.off().on('click', () => {
|
||||
router.navigate(
|
||||
getDataManipulationPreviousStepLink(window.importData.step_method_selection),
|
||||
{ trigger: true }
|
||||
);
|
||||
});
|
||||
|
||||
nextStepButton.off().on('click', (event) => {
|
||||
const columns = {};
|
||||
|
@@ -2,6 +2,7 @@ import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import PreviousNextStepButtons from './previous_next_step_buttons.jsx';
|
||||
import Warnings from './step_data_manipulation/warnings.jsx';
|
||||
|
||||
function getPreviousStepLink(importData, subscribersLimitForValidation) {
|
||||
if (importData === undefined) {
|
||||
@@ -32,6 +33,9 @@ function StepDataManipulation({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Warnings
|
||||
stepMethodSelectionData={stepMethodSelectionData}
|
||||
/>
|
||||
<PreviousNextStepButtons
|
||||
canGoNext={false}
|
||||
onPreviousAction={() => (
|
||||
|
@@ -0,0 +1,117 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
import ReactStringReplace from 'react-string-replace';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const getSingleWarning = (warningTranslation, subscribers) => {
|
||||
let warning = '';
|
||||
if (subscribers.length) {
|
||||
warning = ReactStringReplace(
|
||||
warningTranslation.replace('%2$s', subscribers.join(', ')),
|
||||
'%1$s',
|
||||
() => <strong key={warningTranslation}>{subscribers.length.toLocaleString()}</strong>
|
||||
);
|
||||
warning = <p>{warning}</p>;
|
||||
}
|
||||
return warning;
|
||||
};
|
||||
|
||||
const Warnings = ({
|
||||
stepMethodSelectionData,
|
||||
}) => {
|
||||
const { invalid, duplicate, role } = stepMethodSelectionData;
|
||||
|
||||
const [detailsShown, setDetailsShown] = useState(false);
|
||||
|
||||
const detailClasses = classNames(
|
||||
'mailpoet_subscribers_data_parse_results_details',
|
||||
{ mailpoet_hidden: !detailsShown },
|
||||
);
|
||||
|
||||
const invalidWarning = getSingleWarning(MailPoet.I18n.t('importNoticeInvalid'), invalid);
|
||||
|
||||
const duplicateWarning = getSingleWarning(MailPoet.I18n.t('importNoticeDuplicate'), duplicate);
|
||||
|
||||
let roleBasedWarning = '';
|
||||
if (role.length) {
|
||||
roleBasedWarning = ReactStringReplace(
|
||||
MailPoet.I18n.t('importNoticeRoleBased'),
|
||||
/(%1\$s|\[link\].*\[\/link\]|%2\$s)/,
|
||||
(match) => {
|
||||
if (match === '%1$s') return <strong key="role-length">{role.length.toLocaleString()}</strong>;
|
||||
if (match === '%2$s') return role.join(', ');
|
||||
return (
|
||||
<a
|
||||
href="https://kb.mailpoet.com/article/270-role-based-email-addresses-are-not-allowed"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key={match}
|
||||
>
|
||||
{match.replace('[link]', '').replace('[/link]', '')}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
);
|
||||
roleBasedWarning = <p>{roleBasedWarning}</p>;
|
||||
}
|
||||
|
||||
if (
|
||||
invalid.length
|
||||
|| duplicate.length
|
||||
|| role.length
|
||||
) {
|
||||
const allWarningsCount = invalid.length + duplicate.length + role.length;
|
||||
return (
|
||||
<div className="error">
|
||||
<p>
|
||||
{ReactStringReplace(MailPoet.I18n.t('importNoticeSkipped'), '%1$s', () => (
|
||||
<strong key="lengths">{allWarningsCount.toLocaleString()}</strong>
|
||||
))}
|
||||
{' '}
|
||||
<a
|
||||
className="mailpoet_subscribers_data_parse_results_details_show"
|
||||
data-automation-id="show-more-details"
|
||||
onClick={() => setDetailsShown(!detailsShown)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onKeyDown={(event) => {
|
||||
if ((['keydown', 'keypress'].includes(event.type) && ['Enter', ' '].includes(event.key))
|
||||
) {
|
||||
event.preventDefault();
|
||||
setDetailsShown(!detailsShown);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{MailPoet.I18n.t('showMoreDetails')}
|
||||
</a>
|
||||
</p>
|
||||
<div className={detailClasses}>
|
||||
<hr />
|
||||
{invalidWarning}
|
||||
{duplicateWarning}
|
||||
{roleBasedWarning}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Warnings.propTypes = {
|
||||
stepMethodSelectionData: PropTypes.shape({
|
||||
duplicate: PropTypes.arrayOf(PropTypes.string),
|
||||
invalid: PropTypes.arrayOf(PropTypes.string),
|
||||
role: PropTypes.arrayOf(PropTypes.string),
|
||||
}),
|
||||
};
|
||||
|
||||
Warnings.defaultProps = {
|
||||
stepMethodSelectionData: {
|
||||
invalid: [],
|
||||
duplicate: [],
|
||||
role: [],
|
||||
},
|
||||
};
|
||||
|
||||
export default Warnings;
|
||||
|
Reference in New Issue
Block a user