Replace withRouter with react-router-dom hooks

withRouter was removed
[MAILPOET-3911]
This commit is contained in:
Rostislav Wolny
2024-06-27 16:23:19 +02:00
committed by Aschepikov
parent 0f5fbcf044
commit f917b4e885
24 changed files with 219 additions and 224 deletions

View File

@ -1,22 +1,20 @@
import PropTypes from 'prop-types';
import { useEffect } from 'react';
import { withRouter } from 'react-router-dom';
import { useLocation } from 'react-router-dom';
import { withBoundary } from './error-boundary';
function ScrollToTopComponent({ children, location: { pathname } }) {
export function ScrollToTopComponent({ children }) {
const location = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
}, [location.pathname]);
return children || null;
}
ScrollToTopComponent.propTypes = {
location: PropTypes.shape({
pathname: PropTypes.string.isRequired,
}).isRequired,
children: PropTypes.node.isRequired,
};
ScrollToTopComponent.displayName = 'ScrollToTopComponent';
export const ScrollToTop = withRouter(withBoundary(ScrollToTopComponent));
export const ScrollToTop = withBoundary(ScrollToTopComponent);

View File

@ -1,8 +1,8 @@
import classnames from 'classnames';
import { __ } from '@wordpress/i18n';
import { Component, createRef } from 'react';
import { withRouter } from 'react-router-dom';
import jQuery from 'jquery';
import { useNavigate } from 'react-router-dom';
import PropTypes from 'prop-types';
import { MailPoet } from 'mailpoet';
@ -56,7 +56,7 @@ class FormComponent extends Component {
if (
params.id === undefined &&
prevProps.location.pathname !== location.pathname
prevProps.location?.pathname !== location.pathname
) {
setImmediate(() => {
this.setState({
@ -76,7 +76,7 @@ class FormComponent extends Component {
loadItem = (id) => {
const {
history,
navigate,
endpoint = undefined,
onItemLoad = undefined,
} = this.props;
@ -107,7 +107,7 @@ class FormComponent extends Component {
item: {},
},
() => {
history.push('/lists');
navigate('/lists');
},
);
});
@ -117,7 +117,7 @@ class FormComponent extends Component {
e.preventDefault();
const {
history,
navigate,
endpoint = undefined,
fields = [],
isValid = undefined,
@ -169,7 +169,7 @@ class FormComponent extends Component {
if (typeof onSuccess === 'function') {
onSuccess();
} else {
history.push('/');
navigate('/');
}
if (params.id !== undefined) {
@ -330,9 +330,10 @@ FormComponent.propTypes = {
onChange: PropTypes.func,
onSubmit: PropTypes.func,
onSuccess: PropTypes.func,
history: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
navigate: PropTypes.func.isRequired,
};
export const Form = withRouter(FormComponent);
export function Form(props) {
const navigate = useNavigate();
return <FormComponent {...props} navigate={navigate} />;
}

View File

@ -12,7 +12,7 @@ import { ListingSearch } from 'listing/search.jsx';
import { ListingFilters } from 'listing/filters.jsx';
import { ListingItems } from 'listing/listing-items.jsx';
import { MailerError } from 'notices/mailer-error';
import { withRouter } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router-dom';
import { GlobalContext } from 'context';
import { withBoundary } from '../common';
@ -67,7 +67,7 @@ class ListingComponent extends Component {
});
setParams = () => {
const { history, location = undefined } = this.props;
const { navigate, location = undefined } = this.props;
if (location) {
const params = Object.keys(this.state)
.filter(
@ -101,7 +101,7 @@ class ListingComponent extends Component {
const url = this.getUrlWithParams(params);
if (location.pathname !== url) {
history.push(`${url}`);
navigate(`${url}`);
}
}
};
@ -747,14 +747,19 @@ ListingComponent.propTypes = {
renderExtraActions: PropTypes.func,
onBeforeSelectFilter: PropTypes.func,
getListingItemKey: PropTypes.func,
history: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
navigate: PropTypes.func.isRequired,
isItemDeletable: PropTypes.func,
isItemToggleable: PropTypes.func,
className: PropTypes.string,
};
ListingComponent.displayName = 'Listing';
const ListingWithBoundary = withBoundary(ListingComponent);
export const Listing = withRouter(withBoundary(ListingComponent));
export function Listing(props) {
const navigate = useNavigate();
const location = useLocation();
return (
<ListingWithBoundary {...props} navigate={navigate} location={location} />
);
}

View File

@ -9,7 +9,7 @@ import { Button } from 'common/button/button';
import { Heading } from 'common/typography/heading/heading';
import { GlobalContext } from 'context';
import { Grid } from 'common/grid';
import { ListingHeadingStepsRoute } from 'newsletters/listings/heading-steps-route';
import { ListingHeadingSteps } from 'newsletters/listings/heading-steps';
import { EventScheduling } from 'newsletters/automatic-emails/events/event-scheduling.jsx';
import { EventOptions } from 'newsletters/automatic-emails/events/event-options';
import { MailPoet } from 'mailpoet';
@ -261,7 +261,7 @@ class EventsConditions extends Component {
<div>
<Background color="#fff" />
<ListingHeadingStepsRoute
<ListingHeadingSteps
emailType="woocommerce"
automationId="woocommerce_email_creation_heading"
/>

View File

@ -2,7 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
import { __, _x } from '@wordpress/i18n';
import { Hooks } from 'wp-js-hooks';
import { MailPoet } from 'mailpoet';
import { withRouter } from 'react-router-dom';
import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { TopBarWithBeamer } from 'common/top-bar/top-bar';
import { HideScreenOptions } from 'common/hide-screen-options/hide-screen-options';
import { RemoveWrapMargin } from 'common/remove-wrap-margin/remove-wrap-margin';
@ -14,30 +14,21 @@ import { NewsletterType } from './newsletter-type';
import { NewsletterStatsInfo } from './newsletter-stats-info';
import { PremiumBanner } from './premium-banner';
type Props = {
match: {
params: {
id: string;
};
};
history: {
push: (string) => void;
};
// eslint-disable-next-line @typescript-eslint/ban-types -- we need to match `withRouter`
location: object;
};
type State = {
item?: NewsletterType;
loading: boolean;
};
function CampaignStatsPageComponent({ match, history, location }: Props) {
export function CampaignStatsPage() {
const [state, setState] = useState<State>({
item: undefined,
loading: true,
});
const location = useLocation();
const navigate = useNavigate();
const params = useParams();
const loadItem = useCallback(
(id) => {
setState({ loading: true, item: state.item });
@ -68,20 +59,20 @@ function CampaignStatsPageComponent({ match, history, location }: Props) {
setState({
loading: false,
});
history.push('/');
navigate('/');
});
},
[history, state.item],
[navigate, state.item],
);
useEffect(() => {
// Scroll to top in case we're coming
// from the middle of a long newsletter listing
window.scrollTo(0, 0);
if (state.item?.id !== match.params.id) {
loadItem(match.params.id);
if (state.item?.id !== params.id) {
loadItem(params.id);
}
}, [match.params.id, loadItem, state.item]);
}, [params.id, loadItem, state.item]);
const { item, loading } = state;
const newsletter = item;
@ -142,7 +133,7 @@ function CampaignStatsPageComponent({ match, history, location }: Props) {
'mailpoet_newsletters_subscriber_engagement',
<PremiumBanner />,
location,
match.params,
params,
newsletter,
)}
</Tab>
@ -160,7 +151,7 @@ function CampaignStatsPageComponent({ match, history, location }: Props) {
'mailpoet_newsletters_bounces',
<PremiumBanner />,
location,
match.params,
params,
)}
</Tab>
</Tabs>
@ -169,5 +160,4 @@ function CampaignStatsPageComponent({ match, history, location }: Props) {
);
}
CampaignStatsPageComponent.displayName = 'CampaignStatsPage';
export const CampaignStatsPage = withRouter(CampaignStatsPageComponent);
CampaignStatsPage.displayName = 'CampaignStatsPage';

View File

@ -1,11 +1,12 @@
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { useLocation } from 'react-router-dom';
import { mapPathToSteps } from './heading-steps.tsx';
const isHeaderHidden = (location) =>
location.hash.match(/^#\/new/) || location.pathname.match(/^\/new/);
function ListingHeadingDisplayComponent({ children, location }) {
export function ListingHeadingDisplay({ children }) {
const location = useLocation();
const stepNumber = mapPathToSteps(location);
if (stepNumber === null && !isHeaderHidden(location)) {
return children;
@ -13,9 +14,6 @@ function ListingHeadingDisplayComponent({ children, location }) {
return null;
}
ListingHeadingDisplayComponent.propTypes = {
location: PropTypes.string.isRequired,
ListingHeadingDisplay.propTypes = {
children: PropTypes.node.isRequired,
};
export const ListingHeadingDisplay = withRouter(ListingHeadingDisplayComponent);

View File

@ -1,8 +1,7 @@
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { ListingHeadingSteps, Props } from './heading-steps';
import { useLocation } from 'react-router-dom';
import { ListingHeadingSteps } from './heading-steps';
interface PropsWithRouter extends RouteComponentProps, Props {}
export const ListingHeadingStepsRoute = withRouter((props: PropsWithRouter) => (
<ListingHeadingSteps {...props} />
));
export function ListingHeadingStepsRoute(props) {
const location = useLocation();
return <ListingHeadingSteps {...props} location={location} />;
}

View File

@ -1,6 +1,6 @@
import { ReactNode } from 'react';
import { Location } from 'history';
import { Icon, video } from '@wordpress/icons';
import { Location } from 'react-router-dom';
import { __ } from '@wordpress/i18n';
import { HideScreenOptions } from '../../common/hide-screen-options/hide-screen-options';
import { MailPoetLogoResponsive } from '../../common/top-bar/mailpoet-logo-responsive';
@ -129,7 +129,7 @@ export interface Props {
step?: number;
emailType?: string;
automationId?: string;
location: Location;
location?: Location;
onLogoClick?: () => void;
buttons?: ReactNode;
}
@ -137,8 +137,8 @@ export interface Props {
function ListingHeadingSteps({
step,
emailType,
location,
automationId,
location,
buttons,
onLogoClick,
}: Props): JSX.Element {

View File

@ -1,6 +1,6 @@
import classnames from 'classnames';
import { __ } from '@wordpress/i18n';
import { Link, withRouter } from 'react-router-dom';
import { Link, useParams, useLocation } from 'react-router-dom';
import PropTypes from 'prop-types';
import { Listing } from 'listing/listing.jsx';
@ -182,6 +182,9 @@ const renderItem = (newsletter, actions, meta) => {
};
function NewsletterListNotificationHistoryComponent(props) {
const params = useParams();
const location = useLocation();
return (
<>
<Link
@ -193,9 +196,9 @@ function NewsletterListNotificationHistoryComponent(props) {
<Listing
limit={window.mailpoet_listing_per_page}
location={props.location}
location={location}
params={{
...props.match.params,
...params,
parentId: props.parentId,
}}
endpoint="newsletters"
@ -220,17 +223,10 @@ function NewsletterListNotificationHistoryComponent(props) {
NewsletterListNotificationHistoryComponent.propTypes = {
parentId: PropTypes.string.isRequired,
location: PropTypes.shape({
pathname: PropTypes.string,
}).isRequired,
match: PropTypes.shape({
params: PropTypes.shape({
id: PropTypes.node,
}).isRequired,
}).isRequired,
};
NewsletterListNotificationHistoryComponent.displayName =
'NewsletterListNotificationHistory';
export const NewsletterListNotificationHistory = withRouter(
withBoundary(NewsletterListNotificationHistoryComponent),
export const NewsletterListNotificationHistory = withBoundary(
NewsletterListNotificationHistoryComponent,
);

View File

@ -2,7 +2,7 @@ import classnames from 'classnames';
import { Component, Fragment } from 'react';
import { __ } from '@wordpress/i18n';
import { escapeHTML } from '@wordpress/escape-html';
import { Link, withRouter } from 'react-router-dom';
import { Link, useLocation, useParams } from 'react-router-dom';
import PropTypes from 'prop-types';
import ReactStringReplace from 'react-string-replace';
@ -388,7 +388,7 @@ class NewsletterListNotificationComponent extends Component {
<Listing
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.match.params}
params={this.props.params}
endpoint="newsletters"
type="notification"
base_url="notification"
@ -421,11 +421,14 @@ class NewsletterListNotificationComponent extends Component {
NewsletterListNotificationComponent.propTypes = {
location: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
match: PropTypes.shape({
params: PropTypes.object, // eslint-disable-line react/forbid-prop-types
}).isRequired,
params: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};
NewsletterListNotificationComponent.displayName = 'NewsletterListNotification';
export const NewsletterListNotification = withRouter(
withBoundary(NewsletterListNotificationComponent),
);
const WithBoundary = withBoundary(NewsletterListNotificationComponent);
export function NewsletterListNotification(props) {
const location = useLocation();
const params = useParams();
return <WithBoundary {...props} location={location} params={params} />;
}

View File

@ -3,7 +3,7 @@ import { __, _x } from '@wordpress/i18n';
import { escapeHTML } from '@wordpress/escape-html';
import { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { Link, withRouter } from 'react-router-dom';
import { Link, useLocation, useParams } from 'react-router-dom';
import ReactStringReplace from 'react-string-replace';
import { Toggle } from 'common/form/toggle/toggle';
@ -379,7 +379,7 @@ class NewsletterListReEngagementComponent extends Component {
<Listing
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.match.params}
params={this.props.params}
endpoint="newsletters"
type="re_engagement"
base_url="re_engagement"
@ -412,11 +412,14 @@ class NewsletterListReEngagementComponent extends Component {
NewsletterListReEngagementComponent.propTypes = {
location: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
match: PropTypes.shape({
params: PropTypes.object, // eslint-disable-line react/forbid-prop-types
}).isRequired,
params: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};
NewsletterListReEngagementComponent.displayName = 'NewsletterListReEngagement';
export const NewsletterListReEngagement = withRouter(
withBoundary(NewsletterListReEngagementComponent),
);
const WithBoundary = withBoundary(NewsletterListReEngagementComponent);
export function NewsletterListReEngagement(props) {
const location = useLocation();
const params = useParams();
return <WithBoundary {...props} location={location} params={params} />;
}

View File

@ -4,7 +4,7 @@ import { escapeHTML } from '@wordpress/escape-html';
import { Component } from 'react';
import { MailPoet } from 'mailpoet';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { useLocation, useParams } from 'react-router-dom';
import { confirmAlert } from 'common/confirm-alert.jsx';
import { FilterSegmentTag, SegmentTags } from 'common/tag/tags';
@ -294,7 +294,7 @@ class NewsletterListStandardComponent extends Component {
<Listing
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.match.params}
params={this.props.params}
endpoint="newsletters"
type="standard"
base_url="standard"
@ -329,11 +329,14 @@ NewsletterListStandardComponent.contextType = GlobalContext;
NewsletterListStandardComponent.propTypes = {
location: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
match: PropTypes.shape({
params: PropTypes.object, // eslint-disable-line react/forbid-prop-types
}).isRequired,
params: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};
NewsletterListStandardComponent.displayName = 'NewsletterListStandard';
export const NewsletterListStandard = withRouter(
withBoundary(NewsletterListStandardComponent),
);
const WithBoundary = withBoundary(NewsletterListStandardComponent);
export function NewsletterListStandard(props) {
const location = useLocation();
const params = useParams();
return <WithBoundary {...props} location={location} params={params} />;
}

View File

@ -2,10 +2,16 @@ import _ from 'lodash';
import { ChangeEvent, Component, ContextType } from 'react';
import jQuery from 'jquery';
import { __, _x } from '@wordpress/i18n';
import { History, Location } from 'history';
import ReactStringReplace from 'react-string-replace';
import slugify from 'slugify';
import { match as RouterMatch, withRouter } from 'react-router-dom';
import {
useNavigate,
useLocation,
NavigateFunction,
Location,
useParams,
Params,
} from 'react-router-dom';
import { Background } from 'common/background/background';
import { Button, ErrorBoundary } from 'common';
@ -40,11 +46,9 @@ const generateGaTrackingCampaignName = (
};
type NewsletterSendComponentProps = {
match: RouterMatch<{
id: string;
}>;
history: History;
navigate: NavigateFunction;
location: Location;
params: Params;
};
type NewsletterSendComponentState = {
@ -184,7 +188,7 @@ class NewsletterSendComponent extends Component<
componentDidMount() {
// safe to ignore since even on rejection the state is updated
void this.loadItem(this.props.match.params.id).always(() => {
void this.loadItem(this.props.params.id).always(() => {
this.setState({ loading: false });
});
jQuery('#mailpoet_newsletter').parsley({
@ -193,9 +197,9 @@ class NewsletterSendComponent extends Component<
}
componentDidUpdate(prevProps) {
if (this.props.match.params.id !== prevProps.match.params.id) {
if (this.props.params.id !== prevProps.match.params.id) {
// safe to ignore since even on rejection the state is updated
void this.loadItem(this.props.match.params.id).always(() => {
void this.loadItem(this.props.params.id).always(() => {
this.setState({ loading: false });
});
}
@ -295,7 +299,7 @@ class NewsletterSendComponent extends Component<
item: {} as NewsLetter,
},
() => {
this.props.history.push(goToUrl);
this.props.navigate(goToUrl);
},
);
}
@ -326,7 +330,7 @@ class NewsletterSendComponent extends Component<
item: {} as NewsLetter,
},
() => {
this.props.history.push('/new');
this.props.navigate('/new');
},
);
});
@ -443,7 +447,7 @@ class NewsletterSendComponent extends Component<
this.saveTemplate(saveResponse, () => {
if (window.mailpoet_show_congratulate_after_first_newsletter) {
MailPoet.Modal.loading(false);
this.props.history.push(`/send/congratulate/${this.state.item.id}`);
this.props.navigate(`/send/congratulate/${this.state.item.id}`);
return;
}
this.redirectToListing('activated');
@ -493,7 +497,7 @@ class NewsletterSendComponent extends Component<
endpoint: 'newsletters',
action: 'setStatus',
data: {
id: this.props.match.params.id,
id: this.props.params.id,
status: 'active',
},
})
@ -502,7 +506,7 @@ class NewsletterSendComponent extends Component<
this.saveTemplate(saveResponse, () => {
if (window.mailpoet_show_congratulate_after_first_newsletter) {
MailPoet.Modal.loading(false);
this.props.history.push(`/send/congratulate/${this.state.item.id}`);
this.props.navigate(`/send/congratulate/${this.state.item.id}`);
return;
}
this.redirectToListing('activated');
@ -612,7 +616,7 @@ class NewsletterSendComponent extends Component<
if (['automatic', 'welcome'].includes(this.state.item.type)) {
window.location.href = `admin.php?page=mailpoet-automation&notice=${action}`;
} else {
this.props.history.push(`/${this.state.item.type}`);
this.props.navigate(`/${this.state.item.type}`);
}
};
@ -874,7 +878,7 @@ class NewsletterSendComponent extends Component<
wpPostId,
)}`
: `?page=mailpoet-newsletter-editor&id=${Number(
this.props.match.params.id,
this.props.params.id,
)}`
}
onClick={this.handleRedirectToDesign}
@ -905,4 +909,17 @@ class NewsletterSendComponent extends Component<
}
NewsletterSendComponent.contextType = GlobalContext;
export const NewsletterSend = withRouter(NewsletterSendComponent);
export function NewsletterSend(props) {
const location = useLocation();
const navigate = useNavigate();
const params = useParams();
return (
<NewsletterSendComponent
{...props}
location={location}
navigate={navigate}
params={params}
/>
);
}

View File

@ -4,13 +4,13 @@ import {
Dropdown,
MenuItem as WpMenuItem,
} from '@wordpress/components';
import { ComponentType, useState } from 'react';
import { useState } from 'react';
import { __ } from '@wordpress/i18n';
import { chevronDown, Icon } from '@wordpress/icons';
import { MailPoet } from 'mailpoet';
import { Hooks } from 'wp-js-hooks';
import _ from 'underscore';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { Heading } from 'common/typography/heading/heading';
import { EditorSelectModal } from 'newsletters/editor-select-modal';
import { HideScreenOptions } from 'common/hide-screen-options/hide-screen-options';
@ -19,7 +19,6 @@ import { Info } from './types/info';
interface Props {
filter?: () => void;
history: RouteComponentProps['history'];
hideScreenOptions?: boolean;
}
@ -28,11 +27,12 @@ const MenuItem = WpMenuItem as React.FC<
React.ComponentProps<typeof WpMenuItem> & { variant: string }
>;
function NewsletterTypesComponent({
history,
export function NewsletterTypes({
filter = null,
hideScreenOptions = true,
}: Props): JSX.Element {
const navigate = useNavigate();
const [isCreating, setIsCreating] = useState(false);
const [isSelectEditorModalOpen, setIsSelectEditorModalOpen] = useState(false);
@ -42,7 +42,7 @@ function NewsletterTypesComponent({
const setupNewsletter = (type): void => {
if (type !== undefined) {
history.push(`/new/${type}`);
navigate(`/new/${type}`);
MailPoet.trackEvent('Emails > Type selected', {
'Email type': type,
});
@ -105,7 +105,7 @@ function NewsletterTypesComponent({
},
})
.done((response) => {
history.push(`/template/${response.data.id}`);
navigate(`/template/${response.data.id}`);
})
.fail((response) => {
setIsCreating(false);
@ -290,7 +290,3 @@ function NewsletterTypesComponent({
</>
);
}
export const NewsletterTypes = withRouter(
NewsletterTypesComponent as ComponentType<RouteComponentProps>,
);

View File

@ -10,7 +10,7 @@ import { Background } from 'common/background/background';
import { Button } from 'common/button/button';
import { Heading } from 'common/typography/heading/heading';
import { Grid } from 'common/grid';
import { withRouter } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { GlobalContext } from 'context';
const field = {
@ -76,7 +76,7 @@ class NewsletterNotificationComponent extends Component {
};
showTemplateSelection = (newsletterId) => {
this.props.history.push(`/template/${newsletterId}`);
this.props.navigate(`/template/${newsletterId}`);
};
render() {
@ -112,13 +112,12 @@ class NewsletterNotificationComponent extends Component {
NewsletterNotificationComponent.contextType = GlobalContext;
NewsletterNotificationComponent.propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
navigate: PropTypes.func.isRequired,
};
NewsletterNotificationComponent.displayName = 'NewsletterNotification';
export const NewsletterNotification = withRouter(
NewsletterNotificationComponent,
);
export function NewsletterNotification(props) {
const navigate = useNavigate();
return <NewsletterNotificationComponent {...props} navigate={navigate} />;
}

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { ListingHeadingStepsRoute } from 'newsletters/listings/heading-steps-route';
import { MailPoet } from 'mailpoet';
import { withRouter } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { GlobalContext } from 'context';
import { __ } from '@wordpress/i18n';
@ -42,7 +42,7 @@ class NewsletterStandardComponent extends Component {
}
showTemplateSelection = (newsletterId) => {
this.props.history.push(`/template/${newsletterId}`);
this.props.navigate(`/template/${newsletterId}`);
};
render() {
@ -60,11 +60,12 @@ class NewsletterStandardComponent extends Component {
NewsletterStandardComponent.contextType = GlobalContext;
NewsletterStandardComponent.propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
navigate: PropTypes.func.isRequired,
};
NewsletterStandardComponent.displayName = 'NewsletterStandard';
export const NewsletterTypeStandard = withRouter(NewsletterStandardComponent);
export function NewsletterTypeStandard(props) {
const navigate = useNavigate();
return <NewsletterStandardComponent {...props} navigate={navigate} />;
}

View File

@ -6,7 +6,6 @@ import { Selection } from 'form/fields/selection.jsx';
import { FormFieldText } from 'form/fields/text.jsx';
import { timeDelayValues } from 'newsletters/scheduling/common.jsx';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
const availableRoles = window.mailpoet_roles || {};
const availableSegments = _.filter(
@ -55,7 +54,7 @@ const afterTimeTypeField = {
values: timeDelayValues,
};
class WelcomeSchedulingComponent extends Component {
export class WelcomeScheduling extends Component {
getCurrentValue = () => this.props.item[this.props.field.name] || {};
handleValueChange = (name, value) => {
@ -151,15 +150,11 @@ class WelcomeSchedulingComponent extends Component {
}
}
WelcomeSchedulingComponent.propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
WelcomeScheduling.propTypes = {
item: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
field: PropTypes.shape({
name: PropTypes.string,
}).isRequired,
onValueChange: PropTypes.func.isRequired,
};
WelcomeSchedulingComponent.displayName = 'WelcomeScheduling';
export const WelcomeScheduling = withRouter(WelcomeSchedulingComponent);
WelcomeScheduling.displayName = 'WelcomeScheduling';

View File

@ -1,5 +1,11 @@
import { Component, ReactNode } from 'react';
import { Link, withRouter, RouteComponentProps } from 'react-router-dom';
import {
Link,
useLocation,
useParams,
Location,
Params,
} from 'react-router-dom';
import { MailPoet } from 'mailpoet';
import classnames from 'classnames';
import { escapeHTML, escapeAttribute } from '@wordpress/escape-html';
@ -258,7 +264,12 @@ const itemActions = [
},
];
class SegmentListComponent extends Component<RouteComponentProps> {
type SegmentListComponentProps = {
params: Params;
location: Location;
};
class SegmentListComponent extends Component<SegmentListComponentProps> {
renderItem = (segment: Segment, actions: ReactNode) => {
const rowClasses = classnames(
'manage-column',
@ -363,7 +374,7 @@ class SegmentListComponent extends Component<RouteComponentProps> {
<Listing
limit={window.mailpoet_listing_per_page}
location={this.props.location}
params={this.props.match.params}
params={this.props.params}
messages={messages}
search={false}
endpoint="segments"
@ -383,4 +394,10 @@ class SegmentListComponent extends Component<RouteComponentProps> {
}
}
export const SegmentList = withRouter(SegmentListComponent);
export function SegmentList(props) {
const params = useParams();
const location = useLocation();
return (
<SegmentListComponent {...props} params={params} location={location} />
);
}

View File

@ -1,10 +1,11 @@
import PropTypes from 'prop-types';
import { Link, withRouter } from 'react-router-dom';
import { Link, useLocation } from 'react-router-dom';
import { MailPoet } from 'mailpoet';
import { TopBarWithBeamer } from 'common/top-bar/top-bar';
import { plusIcon } from 'common/button/icon/plus';
function SubscribersHeadingComponent({ location }) {
export function SubscribersHeading() {
const location = useLocation();
return (
<TopBarWithBeamer>
<Link
@ -38,9 +39,3 @@ function SubscribersHeadingComponent({ location }) {
</TopBarWithBeamer>
);
}
SubscribersHeadingComponent.propTypes = {
location: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};
export const SubscribersHeading = withRouter(SubscribersHeadingComponent);

View File

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { PreviousNextStepButtons } from './previous-next-step-buttons.jsx';
import { Warnings } from './step-data-manipulation/warnings.jsx';
import { MatchTable } from './step-data-manipulation/match-table.jsx';
@ -24,12 +24,12 @@ function getPreviousStepLink(importData, subscribersLimitForValidation) {
return 'step_input_validation';
}
function StepDataManipulationComponent({
history,
export function StepDataManipulation({
subscribersLimitForValidation,
setStepDataManipulationData,
stepMethodSelectionData = undefined,
}) {
const navigate = useNavigate();
const [selectedSegments, setSelectedSegments] = useState([]);
const [updateExistingSubscribers, setUpdateExistingSubscribers] =
useState(true);
@ -40,9 +40,9 @@ function StepDataManipulationComponent({
const [selectedTags, setSelectedTags] = useState([]);
useEffect(() => {
if (typeof stepMethodSelectionData === 'undefined') {
history.replace('step_method_selection');
navigate('step_method_selection', { replace: true });
}
}, [stepMethodSelectionData, history]);
}, [stepMethodSelectionData, navigate]);
const importSubscribers = () => {
doImport(
@ -54,7 +54,7 @@ function StepDataManipulationComponent({
selectedTags,
(importResults) => {
setStepDataManipulationData(importResults);
history.push('step_results');
navigate('step_results');
},
);
};
@ -91,7 +91,7 @@ function StepDataManipulationComponent({
<PreviousNextStepButtons
canGoNext={selectedSegments.length > 0}
onPreviousAction={() =>
history.push(
navigate(
getPreviousStepLink(
stepMethodSelectionData,
subscribersLimitForValidation,
@ -106,11 +106,7 @@ function StepDataManipulationComponent({
);
}
StepDataManipulationComponent.propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired,
replace: PropTypes.func.isRequired,
}).isRequired,
StepDataManipulation.propTypes = {
stepMethodSelectionData: PropTypes.shape({
duplicate: PropTypes.arrayOf(PropTypes.string),
header: PropTypes.arrayOf(PropTypes.string),
@ -131,5 +127,3 @@ StepDataManipulationComponent.propTypes = {
subscribersLimitForValidation: PropTypes.number.isRequired,
setStepDataManipulationData: PropTypes.func.isRequired,
};
export const StepDataManipulation = withRouter(StepDataManipulationComponent);

View File

@ -1,5 +1,5 @@
import { ComponentType, useCallback, useEffect, useState } from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { useCallback, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { CleanList } from 'subscribers/import-export/import/clean-list';
import { ErrorBoundary } from 'common';
@ -17,38 +17,37 @@ type StepMethodSelectionData = {
};
type Props = {
history: RouteComponentProps['history'];
stepMethodSelectionData?: StepMethodSelectionData;
};
function StepInputValidationComponent({
history,
export function StepInputValidation({
stepMethodSelectionData = undefined,
}: Props): JSX.Element {
const navigate = useNavigate();
const [importSource, setImportSource] = useState(undefined);
const [lastSent, setLastSent] = useState(undefined);
useEffect(() => {
if (stepMethodSelectionData === undefined) {
history.replace('step_method_selection');
navigate('step_method_selection', { replace: true });
}
}, [stepMethodSelectionData, history]);
}, [stepMethodSelectionData, navigate]);
const lastSentSubmit = useCallback(
(when) => {
setLastSent(when);
if (when === 'recently') {
history.push('step_data_manipulation');
navigate('step_data_manipulation');
}
},
[history, setLastSent],
[navigate, setLastSent],
);
return (
<>
{importSource === undefined && (
<ErrorBoundary>
<InitialQuestion onSubmit={setImportSource} history={history} />
<InitialQuestion onSubmit={setImportSource} />
</ErrorBoundary>
)}
@ -69,8 +68,4 @@ function StepInputValidationComponent({
);
}
StepInputValidationComponent.displayName = 'StepInputValidationComponent';
export const StepInputValidation = withRouter(
StepInputValidationComponent as ComponentType<RouteComponentProps>,
);
StepInputValidation.displayName = 'StepInputValidation';

View File

@ -1,10 +1,12 @@
import { useState } from 'react';
import PropTypes from 'prop-types';
import { MailPoet } from 'mailpoet';
import { useNavigate } from 'react-router-dom';
import { Radio } from 'common/form/radio/radio';
import { PreviousNextStepButtons } from '../previous-next-step-buttons.jsx';
function InitialQuestion({ onSubmit, history }) {
function InitialQuestion({ onSubmit }) {
const navigate = useNavigate();
const [importSource, setImportSource] = useState(undefined);
function isFormValid() {
@ -44,7 +46,7 @@ function InitialQuestion({ onSubmit, history }) {
</div>
<PreviousNextStepButtons
canGoNext={isFormValid()}
onPreviousAction={() => history.push('step_method_selection')}
onPreviousAction={() => navigate('step_method_selection')}
onNextAction={() => onSubmit(importSource)}
/>
</div>
@ -52,9 +54,6 @@ function InitialQuestion({ onSubmit, history }) {
}
InitialQuestion.propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
onSubmit: PropTypes.func.isRequired,
};
InitialQuestion.displayName = 'InitialQuestion';

View File

@ -1,5 +1,5 @@
import { useState } from 'react';
import { withRouter } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import PropTypes from 'prop-types';
import { MailPoet } from 'mailpoet';
import { ErrorBoundary } from 'common';
@ -26,24 +26,24 @@ const getNextStepLink = (importData, subscribersLimitForValidation, method) => {
return 'step_input_validation';
};
function StepMethodSelectionComponent({
history,
export function StepMethodSelection({
setStepMethodSelectionData,
subscribersLimitForValidation,
}) {
const navigate = useNavigate();
const [method, setMethod] = useState(undefined);
const [pastedCsvData, setPastedCsvData] = useState('');
const [file, setFile] = useState(undefined);
const finish = (parsedData) => {
setStepMethodSelectionData(parsedData);
history.push(
navigate(
getNextStepLink(parsedData, subscribersLimitForValidation, method),
);
};
const previousStep = () => {
history.push('/step_clean_list');
navigate('/step_clean_list');
};
const processLocal = () => {
@ -108,12 +108,8 @@ function StepMethodSelectionComponent({
);
}
StepMethodSelectionComponent.propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
StepMethodSelection.propTypes = {
setStepMethodSelectionData: PropTypes.func.isRequired,
subscribersLimitForValidation: PropTypes.number.isRequired,
};
StepMethodSelectionComponent.diplayName = 'StepMethodSelection';
export const StepMethodSelection = withRouter(StepMethodSelectionComponent);
StepMethodSelection.diplayName = 'StepMethodSelection';

View File

@ -2,7 +2,7 @@ import { useEffect } from 'react';
import PropTypes from 'prop-types';
import { MailPoet } from 'mailpoet';
import _ from 'underscore';
import { withRouter } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import ReactStringReplace from 'react-string-replace';
import { Button } from 'common/button/button';
@ -102,14 +102,14 @@ NoWelcomeEmail.propTypes = {
NoWelcomeEmail.diplayName = 'NoWelcomeEmail';
function StepResultsComponent({
history,
export function StepResults({
errors = [],
createdSubscribers = undefined,
updatedSubscribers = undefined,
segments = undefined,
addedToSegmentWithWelcomeNotification = undefined,
}) {
const navigate = useNavigate();
useEffect(() => {
if (
typeof segments === 'undefined' &&
@ -117,13 +117,13 @@ function StepResultsComponent({
typeof createdSubscribers === 'undefined' &&
typeof updatedSubscribers === 'undefined'
) {
history.replace('step_method_selection');
navigate('step_method_selection', { replace: true });
}
}, [
segments,
createdSubscribers,
errors.length,
history,
navigate,
updatedSubscribers,
]);
if (errors.length) {
@ -165,7 +165,7 @@ function StepResultsComponent({
<Button
variant="secondary"
type="button"
onClick={() => history.push('step_method_selection')}
onClick={() => navigate('step_method_selection')}
>
{MailPoet.I18n.t('importAgain')}
</Button>
@ -183,11 +183,7 @@ function StepResultsComponent({
);
}
StepResultsComponent.propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired,
replace: PropTypes.func.isRequired,
}).isRequired,
StepResults.propTypes = {
errors: PropTypes.arrayOf(PropTypes.string.isRequired),
segments: PropTypes.arrayOf(PropTypes.string.isRequired),
createdSubscribers: PropTypes.number,
@ -195,5 +191,4 @@ StepResultsComponent.propTypes = {
addedToSegmentWithWelcomeNotification: PropTypes.bool,
};
StepResultsComponent.displayName = 'StepResultsComponent';
export const StepResults = withRouter(StepResultsComponent);
StepResults.displayName = 'StepResults';