Add error boundary to subscriber import/export app
[MAILPOET-4706]
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { withBoundary } from './error_boundary';
|
||||
|
||||
function ScrollToTopComponent({ children, location: { pathname } }) {
|
||||
useEffect(() => {
|
||||
@@ -9,4 +10,5 @@ function ScrollToTopComponent({ children, location: { pathname } }) {
|
||||
return children || null;
|
||||
}
|
||||
|
||||
export const ScrollToTop = withRouter(ScrollToTopComponent);
|
||||
ScrollToTopComponent.displayName = 'ScrollToTopComponent';
|
||||
export const ScrollToTop = withRouter(withBoundary(ScrollToTopComponent));
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { FilterType, List, Logs } from './list';
|
||||
import { ErrorBoundary } from 'common';
|
||||
import { FilterType, List, Logs } from './list';
|
||||
|
||||
interface LogsWindow extends Window {
|
||||
mailpoet_logs: Logs;
|
||||
|
@@ -1,14 +1,15 @@
|
||||
import { useContext } from 'react';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
import { withBoundary } from 'common';
|
||||
import { Notice } from './notice.tsx';
|
||||
|
||||
const Notices = () => {
|
||||
const NoticesComponent = () => {
|
||||
const { notices } = useContext(GlobalContext);
|
||||
return notices.items.map(({ id, ...props }) => (
|
||||
<Notice key={id} {...props} />
|
||||
));
|
||||
};
|
||||
|
||||
Notices.displayName = 'Notices';
|
||||
|
||||
NoticesComponent.displayName = 'Notices';
|
||||
const Notices = withBoundary(NoticesComponent);
|
||||
export { Notices };
|
||||
|
@@ -5,6 +5,7 @@ import { ScrollToTop } from 'common/scroll_to_top.jsx';
|
||||
|
||||
import { GlobalContext, useGlobalContextValue } from 'context/index.jsx';
|
||||
import { Notices } from 'notices/notices.jsx';
|
||||
import { withBoundary } from 'common';
|
||||
import { StepMethodSelection } from './import/step_method_selection.jsx';
|
||||
import { StepInputValidation } from './import/step_input_validation.jsx';
|
||||
import { StepDataManipulation } from './import/step_data_manipulation.jsx';
|
||||
@@ -28,7 +29,7 @@ function ImportSubscribers() {
|
||||
<Switch>
|
||||
<Route
|
||||
path="/step_clean_list"
|
||||
render={(props) => <StepCleanList {...props} />}
|
||||
render={withBoundary(StepCleanList)}
|
||||
/>
|
||||
<Route
|
||||
path="/step_method_selection"
|
||||
|
@@ -5,7 +5,7 @@ type Props = {
|
||||
onProceed?: () => void;
|
||||
};
|
||||
|
||||
export function CleanList({ onProceed }: Props): JSX.Element {
|
||||
function CleanList({ onProceed }: Props): JSX.Element {
|
||||
return (
|
||||
<div className="mailpoet-clean-list-step-container">
|
||||
<p>{MailPoet.I18n.t('cleanListText1')}</p>
|
||||
@@ -26,3 +26,6 @@ export function CleanList({ onProceed }: Props): JSX.Element {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
CleanList.displayName = 'CleanList';
|
||||
export { CleanList };
|
||||
|
@@ -47,5 +47,5 @@ PreviousNextStepButtons.defaultProps = {
|
||||
onPreviousAction: () => {},
|
||||
onNextAction: () => {},
|
||||
};
|
||||
|
||||
PreviousNextStepButtons.displayName = 'PreviousNextStepButtons';
|
||||
export { PreviousNextStepButtons };
|
||||
|
@@ -1,8 +1,11 @@
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { CleanList } from './clean_list';
|
||||
|
||||
export function StepCleanList({ history }: RouteComponentProps): JSX.Element {
|
||||
function StepCleanList({ history }: RouteComponentProps): JSX.Element {
|
||||
return (
|
||||
<CleanList onProceed={(): void => history.push('step_method_selection')} />
|
||||
);
|
||||
}
|
||||
|
||||
StepCleanList.displayName = 'StepCleanList';
|
||||
export { StepCleanList };
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { CleanList } from 'subscribers/importExport/import/clean_list';
|
||||
import { ErrorBoundary } from 'common';
|
||||
import { InitialQuestion } from './step_input_validation/initial_question.jsx';
|
||||
import { WrongSourceBlock } from './step_input_validation/wrong_source_block.jsx';
|
||||
import { LastSentQuestion } from './step_input_validation/last_sent_question.jsx';
|
||||
@@ -30,17 +31,23 @@ function StepInputValidationComponent({ stepMethodSelectionData, history }) {
|
||||
return (
|
||||
<>
|
||||
{importSource === undefined && (
|
||||
<InitialQuestion onSubmit={setImportSource} history={history} />
|
||||
<ErrorBoundary>
|
||||
<InitialQuestion onSubmit={setImportSource} history={history} />
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
|
||||
{importSource === 'address-book' && <WrongSourceBlock />}
|
||||
|
||||
{importSource === 'existing-list' && lastSent === undefined && (
|
||||
<LastSentQuestion onSubmit={lastSentSubmit} />
|
||||
<ErrorBoundary>
|
||||
<LastSentQuestion onSubmit={lastSentSubmit} />
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
|
||||
{importSource === 'existing-list' && lastSent === 'notRecently' && (
|
||||
<CleanList />
|
||||
<ErrorBoundary>
|
||||
<CleanList />
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
@@ -57,5 +57,5 @@ InitialQuestion.propTypes = {
|
||||
}).isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
InitialQuestion.displayName = 'InitialQuestion';
|
||||
export { InitialQuestion };
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { MailPoet } from 'mailpoet';
|
||||
import { Button } from 'common/button/button';
|
||||
@@ -63,5 +63,5 @@ function LastSentQuestion({ onSubmit }) {
|
||||
LastSentQuestion.propTypes = {
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
LastSentQuestion.displayName = 'LastSentQuestion';
|
||||
export { LastSentQuestion };
|
||||
|
@@ -2,6 +2,7 @@ import { useState } from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { MailPoet } from 'mailpoet';
|
||||
import { ErrorBoundary } from 'common';
|
||||
import { SelectImportMethod } from './step_method_selection/select_import_method.jsx';
|
||||
import { MethodPaste } from './step_method_selection/method_paste.jsx';
|
||||
import { MethodUpload } from './step_method_selection/method_upload.jsx';
|
||||
@@ -57,41 +58,51 @@ function StepMethodSelectionComponent({
|
||||
|
||||
return (
|
||||
<div className="mailpoet-settings-grid">
|
||||
<SelectImportMethod activeMethod={method} onMethodChange={setMethod} />
|
||||
<ErrorBoundary>
|
||||
<SelectImportMethod activeMethod={method} onMethodChange={setMethod} />
|
||||
</ErrorBoundary>
|
||||
{method === 'paste-method' && (
|
||||
<MethodPaste
|
||||
onPrevious={previousStep}
|
||||
onValueChange={setPastedCsvData}
|
||||
onFinish={processLocal}
|
||||
canFinish={!!pastedCsvData.trim()}
|
||||
data={pastedCsvData}
|
||||
/>
|
||||
<ErrorBoundary>
|
||||
<MethodPaste
|
||||
onPrevious={previousStep}
|
||||
onValueChange={setPastedCsvData}
|
||||
onFinish={processLocal}
|
||||
canFinish={!!pastedCsvData.trim()}
|
||||
data={pastedCsvData}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
{method === 'file-method' && (
|
||||
<MethodUpload
|
||||
onPrevious={previousStep}
|
||||
onValueChange={setFile}
|
||||
onFinish={processLocal}
|
||||
canFinish={!!file}
|
||||
data={file}
|
||||
/>
|
||||
<ErrorBoundary>
|
||||
<MethodUpload
|
||||
onPrevious={previousStep}
|
||||
onValueChange={setFile}
|
||||
onFinish={processLocal}
|
||||
canFinish={!!file}
|
||||
data={file}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
{method === 'mailchimp-method' && (
|
||||
<MethodMailChimp
|
||||
onPrevious={previousStep}
|
||||
onFinish={(data) => {
|
||||
MailPoet.trackEvent('Subscribers import started', {
|
||||
source: 'MailChimp',
|
||||
});
|
||||
finish(data);
|
||||
}}
|
||||
/>
|
||||
<ErrorBoundary>
|
||||
<MethodMailChimp
|
||||
onPrevious={previousStep}
|
||||
onFinish={(data) => {
|
||||
MailPoet.trackEvent('Subscribers import started', {
|
||||
source: 'MailChimp',
|
||||
});
|
||||
finish(data);
|
||||
}}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
{method === undefined && (
|
||||
<PreviousNextStepButtons
|
||||
canGoNext={false}
|
||||
onPreviousAction={previousStep}
|
||||
/>
|
||||
<ErrorBoundary>
|
||||
<PreviousNextStepButtons
|
||||
canGoNext={false}
|
||||
onPreviousAction={previousStep}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@@ -104,5 +115,5 @@ StepMethodSelectionComponent.propTypes = {
|
||||
setStepMethodSelectionData: PropTypes.func.isRequired,
|
||||
subscribersLimitForValidation: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
StepMethodSelectionComponent.diplayName = 'StepMethodSelection';
|
||||
export const StepMethodSelection = withRouter(StepMethodSelectionComponent);
|
||||
|
@@ -160,4 +160,6 @@ MethodMailChimp.defaultProps = {
|
||||
onPrevious: () => {},
|
||||
};
|
||||
|
||||
MethodMailChimp.displayName = 'MethodMailChimp';
|
||||
|
||||
export { MethodMailChimp };
|
||||
|
@@ -70,5 +70,5 @@ MethodPaste.defaultProps = {
|
||||
onPrevious: () => {},
|
||||
data: '',
|
||||
};
|
||||
|
||||
MethodPaste.displayName = 'MethodPaste';
|
||||
export { MethodPaste };
|
||||
|
@@ -71,5 +71,5 @@ MethodUpload.defaultProps = {
|
||||
onFinish: () => {},
|
||||
onPrevious: () => {},
|
||||
};
|
||||
|
||||
MethodUpload.displayName = 'MethodUpload';
|
||||
export { MethodUpload };
|
||||
|
@@ -78,5 +78,5 @@ SelectImportMethod.propTypes = {
|
||||
SelectImportMethod.defaultProps = {
|
||||
activeMethod: undefined,
|
||||
};
|
||||
|
||||
SelectImportMethod.displayName = 'SelectImportMethod';
|
||||
export { SelectImportMethod };
|
||||
|
@@ -6,6 +6,7 @@ import { withRouter } from 'react-router-dom';
|
||||
import ReactStringReplace from 'react-string-replace';
|
||||
|
||||
import { Button } from 'common/button/button';
|
||||
import { ErrorBoundary } from 'common';
|
||||
|
||||
function ResultMessage({ subscribersCount, segments, initialMessage }) {
|
||||
if (subscribersCount) {
|
||||
@@ -33,6 +34,7 @@ ResultMessage.defaultProps = {
|
||||
subscribersCount: 0,
|
||||
initialMessage: '',
|
||||
};
|
||||
ResultMessage.displayName = 'ResultMessage';
|
||||
|
||||
function NoAction({ createdSubscribers, updatedSubscribers }) {
|
||||
if (!createdSubscribers && !updatedSubscribers) {
|
||||
@@ -50,6 +52,7 @@ NoAction.defaultProps = {
|
||||
createdSubscribers: 0,
|
||||
updatedSubscribers: 0,
|
||||
};
|
||||
NoAction.displayName = 'NoAction';
|
||||
|
||||
function SuppressionListReminder({ createdSubscribers, updatedSubscribers }) {
|
||||
if (createdSubscribers || updatedSubscribers) {
|
||||
@@ -91,6 +94,7 @@ SuppressionListReminder.defaultProps = {
|
||||
createdSubscribers: 0,
|
||||
updatedSubscribers: 0,
|
||||
};
|
||||
SuppressionListReminder.displayName = 'SuppressionListReminder';
|
||||
|
||||
function NoWelcomeEmail({ addedToSegmentWithWelcomeNotification }) {
|
||||
if (addedToSegmentWithWelcomeNotification) {
|
||||
@@ -106,6 +110,7 @@ NoWelcomeEmail.propTypes = {
|
||||
NoWelcomeEmail.defaultProps = {
|
||||
addedToSegmentWithWelcomeNotification: false,
|
||||
};
|
||||
NoWelcomeEmail.diplayName = 'NoWelcomeEmail';
|
||||
|
||||
function StepResultsComponent({
|
||||
errors,
|
||||
@@ -136,31 +141,35 @@ function StepResultsComponent({
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="updated">
|
||||
<ResultMessage
|
||||
subscribersCount={createdSubscribers}
|
||||
segments={segments}
|
||||
initialMessage={MailPoet.I18n.t('subscribersCreated')}
|
||||
/>
|
||||
<ResultMessage
|
||||
subscribersCount={updatedSubscribers}
|
||||
segments={segments}
|
||||
initialMessage={MailPoet.I18n.t('subscribersUpdated')}
|
||||
/>
|
||||
<NoAction
|
||||
<ErrorBoundary>
|
||||
<div className="updated">
|
||||
<ResultMessage
|
||||
subscribersCount={createdSubscribers}
|
||||
segments={segments}
|
||||
initialMessage={MailPoet.I18n.t('subscribersCreated')}
|
||||
/>
|
||||
<ResultMessage
|
||||
subscribersCount={updatedSubscribers}
|
||||
segments={segments}
|
||||
initialMessage={MailPoet.I18n.t('subscribersUpdated')}
|
||||
/>
|
||||
<NoAction
|
||||
createdSubscribers={createdSubscribers}
|
||||
updatedSubscribers={updatedSubscribers}
|
||||
/>
|
||||
<NoWelcomeEmail
|
||||
addedToSegmentWithWelcomeNotification={
|
||||
addedToSegmentWithWelcomeNotification
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
<ErrorBoundary>
|
||||
<SuppressionListReminder
|
||||
createdSubscribers={createdSubscribers}
|
||||
updatedSubscribers={updatedSubscribers}
|
||||
/>
|
||||
<NoWelcomeEmail
|
||||
addedToSegmentWithWelcomeNotification={
|
||||
addedToSegmentWithWelcomeNotification
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<SuppressionListReminder
|
||||
createdSubscribers={createdSubscribers}
|
||||
updatedSubscribers={updatedSubscribers}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
<div className="mailpoet-settings-grid">
|
||||
<div className="mailpoet-settings-save">
|
||||
<Button
|
||||
@@ -203,5 +212,5 @@ StepResultsComponent.defaultProps = {
|
||||
updatedSubscribers: undefined,
|
||||
addedToSegmentWithWelcomeNotification: undefined,
|
||||
};
|
||||
|
||||
StepResultsComponent.displayName = 'StepResultsComponent';
|
||||
export const StepResults = withRouter(StepResultsComponent);
|
||||
|
Reference in New Issue
Block a user