From f917b4e8854f83e2aaeaf24c0a074494e13f8cfd Mon Sep 17 00:00:00 2001 From: Rostislav Wolny Date: Thu, 27 Jun 2024 16:23:19 +0200 Subject: [PATCH] Replace withRouter with react-router-dom hooks withRouter was removed [MAILPOET-3911] --- .../assets/js/src/common/scroll-to-top.jsx | 12 ++--- mailpoet/assets/js/src/form/form.jsx | 21 ++++---- mailpoet/assets/js/src/listing/listing.jsx | 19 ++++--- .../automatic-emails/events-conditions.jsx | 4 +- .../src/newsletters/campaign-stats/page.tsx | 38 +++++--------- .../newsletters/listings/heading-display.jsx | 10 ++-- .../listings/heading-steps-route.tsx | 13 +++-- .../newsletters/listings/heading-steps.tsx | 6 +-- .../listings/notification-history.jsx | 22 ++++---- .../src/newsletters/listings/notification.jsx | 19 ++++--- .../newsletters/listings/re-engagement.jsx | 19 ++++--- .../js/src/newsletters/listings/standard.jsx | 19 ++++--- mailpoet/assets/js/src/newsletters/send.tsx | 51 ++++++++++++------- mailpoet/assets/js/src/newsletters/types.tsx | 18 +++---- .../types/notification/notification.jsx | 15 +++--- .../js/src/newsletters/types/standard.jsx | 13 ++--- .../newsletters/types/welcome/scheduling.jsx | 11 ++-- .../assets/js/src/segments/static/list.tsx | 25 +++++++-- .../assets/js/src/subscribers/heading.jsx | 13 ++--- .../import/step-data-manipulation.jsx | 22 +++----- .../import/step-input-validation.tsx | 25 ++++----- .../initial-question.jsx | 9 ++-- .../import/step-method-selection.jsx | 18 +++---- .../import-export/import/step-results.jsx | 21 +++----- 24 files changed, 219 insertions(+), 224 deletions(-) diff --git a/mailpoet/assets/js/src/common/scroll-to-top.jsx b/mailpoet/assets/js/src/common/scroll-to-top.jsx index 8d6fd6ae81..a146e4c3ca 100644 --- a/mailpoet/assets/js/src/common/scroll-to-top.jsx +++ b/mailpoet/assets/js/src/common/scroll-to-top.jsx @@ -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); diff --git a/mailpoet/assets/js/src/form/form.jsx b/mailpoet/assets/js/src/form/form.jsx index 0e15a719ad..416ed5f2a6 100644 --- a/mailpoet/assets/js/src/form/form.jsx +++ b/mailpoet/assets/js/src/form/form.jsx @@ -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 ; +} diff --git a/mailpoet/assets/js/src/listing/listing.jsx b/mailpoet/assets/js/src/listing/listing.jsx index 3e219bdf47..12d22588b3 100644 --- a/mailpoet/assets/js/src/listing/listing.jsx +++ b/mailpoet/assets/js/src/listing/listing.jsx @@ -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 ( + + ); +} diff --git a/mailpoet/assets/js/src/newsletters/automatic-emails/events-conditions.jsx b/mailpoet/assets/js/src/newsletters/automatic-emails/events-conditions.jsx index 836b72b3ef..2ca549ddc4 100644 --- a/mailpoet/assets/js/src/newsletters/automatic-emails/events-conditions.jsx +++ b/mailpoet/assets/js/src/newsletters/automatic-emails/events-conditions.jsx @@ -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 {
- diff --git a/mailpoet/assets/js/src/newsletters/campaign-stats/page.tsx b/mailpoet/assets/js/src/newsletters/campaign-stats/page.tsx index 31b9fc2e9c..e12066978c 100644 --- a/mailpoet/assets/js/src/newsletters/campaign-stats/page.tsx +++ b/mailpoet/assets/js/src/newsletters/campaign-stats/page.tsx @@ -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({ 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', , location, - match.params, + params, newsletter, )} @@ -160,7 +151,7 @@ function CampaignStatsPageComponent({ match, history, location }: Props) { 'mailpoet_newsletters_bounces', , location, - match.params, + params, )} @@ -169,5 +160,4 @@ function CampaignStatsPageComponent({ match, history, location }: Props) { ); } -CampaignStatsPageComponent.displayName = 'CampaignStatsPage'; -export const CampaignStatsPage = withRouter(CampaignStatsPageComponent); +CampaignStatsPage.displayName = 'CampaignStatsPage'; diff --git a/mailpoet/assets/js/src/newsletters/listings/heading-display.jsx b/mailpoet/assets/js/src/newsletters/listings/heading-display.jsx index 16e10b6f16..3f6982fbdb 100644 --- a/mailpoet/assets/js/src/newsletters/listings/heading-display.jsx +++ b/mailpoet/assets/js/src/newsletters/listings/heading-display.jsx @@ -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); diff --git a/mailpoet/assets/js/src/newsletters/listings/heading-steps-route.tsx b/mailpoet/assets/js/src/newsletters/listings/heading-steps-route.tsx index d534315ba6..a9d29dad70 100644 --- a/mailpoet/assets/js/src/newsletters/listings/heading-steps-route.tsx +++ b/mailpoet/assets/js/src/newsletters/listings/heading-steps-route.tsx @@ -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) => ( - -)); +export function ListingHeadingStepsRoute(props) { + const location = useLocation(); + return ; +} diff --git a/mailpoet/assets/js/src/newsletters/listings/heading-steps.tsx b/mailpoet/assets/js/src/newsletters/listings/heading-steps.tsx index 003a572ffe..1ebc88b801 100644 --- a/mailpoet/assets/js/src/newsletters/listings/heading-steps.tsx +++ b/mailpoet/assets/js/src/newsletters/listings/heading-steps.tsx @@ -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 { diff --git a/mailpoet/assets/js/src/newsletters/listings/notification-history.jsx b/mailpoet/assets/js/src/newsletters/listings/notification-history.jsx index 8e703a1ca7..ed77e0e20e 100644 --- a/mailpoet/assets/js/src/newsletters/listings/notification-history.jsx +++ b/mailpoet/assets/js/src/newsletters/listings/notification-history.jsx @@ -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 ( <> ; +} diff --git a/mailpoet/assets/js/src/newsletters/listings/re-engagement.jsx b/mailpoet/assets/js/src/newsletters/listings/re-engagement.jsx index 935c0029ef..6c5d20693d 100644 --- a/mailpoet/assets/js/src/newsletters/listings/re-engagement.jsx +++ b/mailpoet/assets/js/src/newsletters/listings/re-engagement.jsx @@ -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 { ; +} diff --git a/mailpoet/assets/js/src/newsletters/listings/standard.jsx b/mailpoet/assets/js/src/newsletters/listings/standard.jsx index 45286e7578..7c08d7f68c 100644 --- a/mailpoet/assets/js/src/newsletters/listings/standard.jsx +++ b/mailpoet/assets/js/src/newsletters/listings/standard.jsx @@ -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 { ; +} diff --git a/mailpoet/assets/js/src/newsletters/send.tsx b/mailpoet/assets/js/src/newsletters/send.tsx index bfbea42289..07dbb5cd45 100644 --- a/mailpoet/assets/js/src/newsletters/send.tsx +++ b/mailpoet/assets/js/src/newsletters/send.tsx @@ -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¬ice=${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 ( + + ); +} diff --git a/mailpoet/assets/js/src/newsletters/types.tsx b/mailpoet/assets/js/src/newsletters/types.tsx index 86f5cfcec6..3ec823605a 100644 --- a/mailpoet/assets/js/src/newsletters/types.tsx +++ b/mailpoet/assets/js/src/newsletters/types.tsx @@ -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 & { 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, -); diff --git a/mailpoet/assets/js/src/newsletters/types/notification/notification.jsx b/mailpoet/assets/js/src/newsletters/types/notification/notification.jsx index 30d739af42..bc21431ba8 100644 --- a/mailpoet/assets/js/src/newsletters/types/notification/notification.jsx +++ b/mailpoet/assets/js/src/newsletters/types/notification/notification.jsx @@ -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 ; +} diff --git a/mailpoet/assets/js/src/newsletters/types/standard.jsx b/mailpoet/assets/js/src/newsletters/types/standard.jsx index 572a46512a..8cb51b2279 100644 --- a/mailpoet/assets/js/src/newsletters/types/standard.jsx +++ b/mailpoet/assets/js/src/newsletters/types/standard.jsx @@ -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 ; +} diff --git a/mailpoet/assets/js/src/newsletters/types/welcome/scheduling.jsx b/mailpoet/assets/js/src/newsletters/types/welcome/scheduling.jsx index 19a63ef749..665e20fe64 100644 --- a/mailpoet/assets/js/src/newsletters/types/welcome/scheduling.jsx +++ b/mailpoet/assets/js/src/newsletters/types/welcome/scheduling.jsx @@ -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'; diff --git a/mailpoet/assets/js/src/segments/static/list.tsx b/mailpoet/assets/js/src/segments/static/list.tsx index 355838ed2f..9d82c61613 100644 --- a/mailpoet/assets/js/src/segments/static/list.tsx +++ b/mailpoet/assets/js/src/segments/static/list.tsx @@ -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 { +type SegmentListComponentProps = { + params: Params; + location: Location; +}; + +class SegmentListComponent extends Component { renderItem = (segment: Segment, actions: ReactNode) => { const rowClasses = classnames( 'manage-column', @@ -363,7 +374,7 @@ class SegmentListComponent extends Component { { } } -export const SegmentList = withRouter(SegmentListComponent); +export function SegmentList(props) { + const params = useParams(); + const location = useLocation(); + return ( + + ); +} diff --git a/mailpoet/assets/js/src/subscribers/heading.jsx b/mailpoet/assets/js/src/subscribers/heading.jsx index 98ff0d5677..722501ae5c 100644 --- a/mailpoet/assets/js/src/subscribers/heading.jsx +++ b/mailpoet/assets/js/src/subscribers/heading.jsx @@ -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 ( ); } - -SubscribersHeadingComponent.propTypes = { - location: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types -}; - -export const SubscribersHeading = withRouter(SubscribersHeadingComponent); diff --git a/mailpoet/assets/js/src/subscribers/import-export/import/step-data-manipulation.jsx b/mailpoet/assets/js/src/subscribers/import-export/import/step-data-manipulation.jsx index acef9c32b9..9434fcbc86 100644 --- a/mailpoet/assets/js/src/subscribers/import-export/import/step-data-manipulation.jsx +++ b/mailpoet/assets/js/src/subscribers/import-export/import/step-data-manipulation.jsx @@ -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({ 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); diff --git a/mailpoet/assets/js/src/subscribers/import-export/import/step-input-validation.tsx b/mailpoet/assets/js/src/subscribers/import-export/import/step-input-validation.tsx index 38851bbb46..b937e218d7 100644 --- a/mailpoet/assets/js/src/subscribers/import-export/import/step-input-validation.tsx +++ b/mailpoet/assets/js/src/subscribers/import-export/import/step-input-validation.tsx @@ -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 && ( - + )} @@ -69,8 +68,4 @@ function StepInputValidationComponent({ ); } -StepInputValidationComponent.displayName = 'StepInputValidationComponent'; - -export const StepInputValidation = withRouter( - StepInputValidationComponent as ComponentType, -); +StepInputValidation.displayName = 'StepInputValidation'; diff --git a/mailpoet/assets/js/src/subscribers/import-export/import/step-input-validation/initial-question.jsx b/mailpoet/assets/js/src/subscribers/import-export/import/step-input-validation/initial-question.jsx index ecc52f8602..df97fba18f 100644 --- a/mailpoet/assets/js/src/subscribers/import-export/import/step-input-validation/initial-question.jsx +++ b/mailpoet/assets/js/src/subscribers/import-export/import/step-input-validation/initial-question.jsx @@ -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 }) {
history.push('step_method_selection')} + onPreviousAction={() => navigate('step_method_selection')} onNextAction={() => onSubmit(importSource)} /> @@ -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'; diff --git a/mailpoet/assets/js/src/subscribers/import-export/import/step-method-selection.jsx b/mailpoet/assets/js/src/subscribers/import-export/import/step-method-selection.jsx index e0e48ab78c..fbb717d8cf 100644 --- a/mailpoet/assets/js/src/subscribers/import-export/import/step-method-selection.jsx +++ b/mailpoet/assets/js/src/subscribers/import-export/import/step-method-selection.jsx @@ -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'; diff --git a/mailpoet/assets/js/src/subscribers/import-export/import/step-results.jsx b/mailpoet/assets/js/src/subscribers/import-export/import/step-results.jsx index b6a676d63d..58cc1a9ff4 100644 --- a/mailpoet/assets/js/src/subscribers/import-export/import/step-results.jsx +++ b/mailpoet/assets/js/src/subscribers/import-export/import/step-results.jsx @@ -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({ @@ -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';