(BaseComponent) => {
- @withRouter
- class WrapperClass extends React.Component {
- getQuery = (names) => parseQuery(this.props.location, names);
- getParam = (name) => parseQuery(this.props.location)[name];
- addQuery = (params) => {
- const { location, history } = this.props;
- history.push(addQueryParams(location, params));
- };
- removeQuery = (names = [], replace = false) => {
- const { location, history } = this.props;
+ const WrapperComponent = (props) => {
+ const location = useLocation();
+ const navigate = useNavigate();
+ const getQuery = (names) => parseQuery(location, names);
+ const getParam = (name) => parseQuery(location)[name];
+
+ const addQuery = (params) => {
+ navigate(addQueryParams(location, params));
+ };
+
+ const removeQuery = (names = [], replace = false) => {
const namesArray = Array.isArray(names) ? names : [names];
/* to avoid update stack overflow */
- const actualNames = Object.keys(this.getQuery(namesArray));
+ const actualNames = Object.keys(getQuery(namesArray));
if (actualNames.length > 0) {
- history[replace ? 'replace' : 'push'](removeQueryParams(location, actualNames));
+ const path = removeQueryParams(location, actualNames);
+ navigate(path, { replace });
}
};
- setQuery = (params, replace = false) => {
- const { location, history } = this.props;
- history[replace ? 'replace' : 'push'](setQueryParams(location, params));
- };
- query = {
- all: this.getQuery,
- get: this.getParam,
- add: this.addQuery,
- remove: this.removeQuery,
- set: this.setQuery, // TODO: use namespaces
+
+ const setQuery = (params, replace = false) => {
+ navigate(setQueryParams(location, params), { replace });
};
- getHash = () => this.props.location.hash.substring(1);
- setHash = (hash) => {
- const { location, history } = this.props;
- history.push({ ...location, hash: `#${hash}` });
- };
- removeHash = () => {
- const { location, history } = this.props;
- history.push({ ...location, hash: '' });
- };
- hash = {
- get: this.getHash,
- set: this.setHash,
- remove: this.removeHash,
+ const query = {
+ all: getQuery,
+ get: getParam,
+ add: addQuery,
+ remove: removeQuery,
+ set: setQuery, // TODO: use namespaces
};
- getQueryProps() {
- if (Array.isArray(propNames)) return this.getQuery(propNames);
+ const getHash = () => location.hash.substring(1);
+
+ const setHash = (hash) => {
+ navigate({ ...location, hash: `#${hash}` });
+ };
+
+ const removeHash = () => {
+ navigate({ ...location, hash: '' });
+ };
+
+ const hash = {
+ get: getHash,
+ set: setHash,
+ remove: removeHash,
+ };
+
+ const getQueryProps = () => {
+ if (Array.isArray(propNames)) return getQuery(propNames);
if (propNames !== null && typeof propNames === 'object') {
const values = Object.values(propNames);
- const query = this.getQuery(values);
+ const query = getQuery(values);
const queryProps = {};
- Object.keys(propNames).map((key) => {
+ Object.keys(propNames).forEach((key) => {
queryProps[key] = query[propNames[key]];
});
return queryProps;
}
return {};
- }
+ };
- render() {
- const queryProps = this.getQueryProps();
- return
;
- }
- }
- return WrapperClass;
+ const queryProps = getQueryProps();
+ return
;
+ };
+
+ return WrapperComponent;
};
-export default withLocationHandlers;
+
+export default withLocationHandlers;
\ No newline at end of file
diff --git a/frontend/app/components/hocs/withSiteIdRouter.js b/frontend/app/components/hocs/withSiteIdRouter.js
deleted file mode 100644
index 756a5d280..000000000
--- a/frontend/app/components/hocs/withSiteIdRouter.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import { withRouter } from 'react-router-dom';
-import { withSiteId } from 'App/routes';
-import { observer } from 'mobx-react-lite'
-import { useStore } from "App/mstore";
-
-export default BaseComponent => withRouter(observer((props) => {
- const { history, ...other } = props
- const { projectsStore } = useStore();
- const siteId = projectsStore.siteId
-
- const push = (location) => {
- if (typeof location === 'string') {
- history.push(withSiteId(location, siteId));
- } else if (typeof location === 'object') {
- history.push({ ...location, pathname: withSiteId(location.pathname, siteId) });
- }
- }
-
- return
-}))
\ No newline at end of file
diff --git a/frontend/app/components/hocs/withSiteIdUpdater.js b/frontend/app/components/hocs/withSiteIdUpdater.js
index 8bc3f533e..ee52b51f1 100644
--- a/frontend/app/components/hocs/withSiteIdUpdater.js
+++ b/frontend/app/components/hocs/withSiteIdUpdater.js
@@ -1,13 +1,15 @@
import React, { useEffect, useRef } from 'react';
import { useStore } from "App/mstore";
import { observer } from 'mobx-react-lite'
+import { useParams, useNavigate } from 'react-router';
const withSiteIdUpdater = (BaseComponent) => {
const WrapperComponent = (props) => {
+ const { siteId: urlSiteId } = useParams();
+ const navigate = useNavigate();
const { projectsStore } = useStore();
const siteId = projectsStore.siteId;
const setSiteId = projectsStore.setSiteId;
- const urlSiteId = props.match.params.siteId
const prevSiteIdRef = useRef(siteId);
useEffect(() => {
@@ -17,15 +19,15 @@ const withSiteIdUpdater = (BaseComponent) => {
}, []);
useEffect(() => {
- const { location: { pathname }, history } = props;
+ const pathname = location.pathname;
const shouldUrlUpdate = urlSiteId && parseInt(urlSiteId, 10) !== parseInt(siteId, 10);
if (shouldUrlUpdate) {
const path = ['', siteId].concat(pathname.split('/').slice(2)).join('/');
- history.push(path);
+ navigate(path);
}
prevSiteIdRef.current = siteId;
- }, [urlSiteId, siteId, props.location.pathname, props.history]);
+ }, [urlSiteId, siteId, location.pathname]);
const key = siteId;
diff --git a/frontend/app/components/shared/Breadcrumb/BackButton.tsx b/frontend/app/components/shared/Breadcrumb/BackButton.tsx
index ef046d5a0..43c9d25d2 100644
--- a/frontend/app/components/shared/Breadcrumb/BackButton.tsx
+++ b/frontend/app/components/shared/Breadcrumb/BackButton.tsx
@@ -1,14 +1,14 @@
import React from 'react';
import { Button } from 'antd';
-import { useHistory } from 'react-router-dom';
+import { useNavigate } from 'react-router';
import { LeftOutlined, ArrowLeftOutlined } from '@ant-design/icons';
function BackButton({ compact }: { compact?: boolean }) {
- const history = useHistory();
+ const navigate = useNavigate()
const siteId = location.pathname.split('/')[1];
const handleBackClick = () => {
- history.push(`/${siteId}/dashboard`);
+ navigate(`/${siteId}/dashboard`);
};
if (compact) {
return (
diff --git a/frontend/app/components/shared/GettingStarted/StepList.tsx b/frontend/app/components/shared/GettingStarted/StepList.tsx
index 178cb4aa1..431a51e98 100644
--- a/frontend/app/components/shared/GettingStarted/StepList.tsx
+++ b/frontend/app/components/shared/GettingStarted/StepList.tsx
@@ -1,13 +1,13 @@
import React from 'react';
+import { useNavigate } from "react-router";
import { Icon } from 'UI';
import cn from 'classnames';
import { Step } from 'App/mstore/types/gettingStarted';
import { useStore } from 'App/mstore';
import { onboarding as onboardingRoute, withSiteId } from 'App/routes';
-import { RouteComponentProps, withRouter } from 'react-router';
import { useModal } from 'App/components/Modal';
-interface StepListProps extends RouteComponentProps {
+interface StepListProps {
title: string;
steps: Step[];
status: 'pending' | 'completed';
@@ -61,6 +61,7 @@ const StepItem = React.memo(
);
const StepList = React.memo((props: StepListProps) => {
+ const navigate = useNavigate()
const { title, steps } = props;
const { hideModal } = useModal();
@@ -79,10 +80,9 @@ const StepList = React.memo((props: StepListProps) => {
}
const onClick = (step: any) => {
- const { history } = props;
const siteId = projectsStore.getSiteId().siteId!;
hideModal();
- history.push(withSiteId(onboardingRoute(step.url), siteId));
+ navigate(withSiteId(onboardingRoute(step.url), siteId));
};
return (
@@ -97,4 +97,4 @@ const StepList = React.memo((props: StepListProps) => {
);
});
-export default withRouter(StepList);
+export default StepList;
diff --git a/frontend/app/components/shared/IntegrateSlackButton/IntegrateSlackButton.js b/frontend/app/components/shared/IntegrateSlackButton/IntegrateSlackButton.js
index bc1900336..d87b78ed4 100644
--- a/frontend/app/components/shared/IntegrateSlackButton/IntegrateSlackButton.js
+++ b/frontend/app/components/shared/IntegrateSlackButton/IntegrateSlackButton.js
@@ -2,12 +2,12 @@ import React from 'react'
import { Icon } from 'UI'
import { Button } from 'antd'
import { CLIENT_TABS, client as clientRoute } from 'App/routes';
-import { withRouter } from 'react-router-dom';
-
-function IntegrateSlackTeamsButton({ history }) {
+import { useNavigate } from "react-router";
+function IntegrateSlackTeamsButton() {
+ const navigate = useNavigate();
const gotoPreferencesIntegrations = () => {
- history.push(clientRoute(CLIENT_TABS.INTEGRATIONS));
+ navigate(clientRoute(CLIENT_TABS.INTEGRATIONS));
}
return (
@@ -26,4 +26,4 @@ function IntegrateSlackTeamsButton({ history }) {
)
}
-export default withRouter(IntegrateSlackTeamsButton)
+export default IntegrateSlackTeamsButton
diff --git a/frontend/app/components/shared/NoSessionsMessage/NoSessionsMessage.js b/frontend/app/components/shared/NoSessionsMessage/NoSessionsMessage.js
index c8b1a626d..ebdbe6587 100644
--- a/frontend/app/components/shared/NoSessionsMessage/NoSessionsMessage.js
+++ b/frontend/app/components/shared/NoSessionsMessage/NoSessionsMessage.js
@@ -3,17 +3,16 @@ import { Alert, Space, Button } from 'antd';
import { observer } from 'mobx-react-lite'
import { useStore } from "App/mstore";
import { onboarding as onboardingRoute } from 'App/routes';
-import { withRouter } from 'react-router-dom';
import * as routes from '../../../routes';
import { SquareArrowOutUpRight } from 'lucide-react';
-import { useHistory } from 'react-router';
+import { useNavigate } from 'react-router';
const withSiteId = routes.withSiteId;
const NoSessionsMessage = () => {
const { projectsStore } = useStore();
const siteId = projectsStore.siteId;
- const history = useHistory();
+ const navigate = useNavigate();
const activeSite = projectsStore.active;
const showNoSessions = !!activeSite && !activeSite.recorded;
const onboardingPath = withSiteId(onboardingRoute('installing'), siteId);
@@ -41,7 +40,7 @@ const NoSessionsMessage = () => {
@@ -55,4 +54,4 @@ const NoSessionsMessage = () => {
);
};
-export default withRouter(observer(NoSessionsMessage));
+export default observer(NoSessionsMessage)
diff --git a/frontend/app/components/shared/ProjectDropdown/ProjectDropdown.tsx b/frontend/app/components/shared/ProjectDropdown/ProjectDropdown.tsx
index 72d9446cb..3514315e8 100644
--- a/frontend/app/components/shared/ProjectDropdown/ProjectDropdown.tsx
+++ b/frontend/app/components/shared/ProjectDropdown/ProjectDropdown.tsx
@@ -5,11 +5,10 @@ import {
import { Button, Dropdown, MenuProps, Space, Typography } from 'antd';
import cn from 'classnames';
import React from 'react';
-import { withRouter } from 'react-router-dom';
+import { useLocation } from 'react-router'
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { hasSiteId, siteChangeAvailable } from 'App/routes';
-import NewSiteForm from 'Components/Client/Sites/NewSiteForm';
import { Icon } from 'UI';
import { useModal } from 'Components/ModalContext';
import ProjectForm from 'Components/Client/Projects/ProjectForm';
@@ -17,15 +16,15 @@ import Project from '@/mstore/types/project';
const { Text } = Typography;
-function ProjectDropdown(props: { location: any }) {
+function ProjectDropdown() {
const mstore = useStore();
+ const location = useLocation();
const { projectsStore, searchStore, searchStoreLive, userStore } = mstore;
const account = userStore.account;
const sites = projectsStore.list;
const siteId = projectsStore.siteId;
const setSiteId = projectsStore.setSiteId;
const initProject = projectsStore.initProject;
- const { location } = props;
const isAdmin = account.admin || account.superAdmin;
const activeSite = sites.find((s) => s.id === siteId);
const showCurrent =
@@ -139,6 +138,4 @@ function ProjectDropdown(props: { location: any }) {
);
}
-export default withRouter(
- observer(ProjectDropdown)
-);
+export default observer(ProjectDropdown)
\ No newline at end of file
diff --git a/frontend/app/components/shared/SessionItem/PlayLink/PlayLink.tsx b/frontend/app/components/shared/SessionItem/PlayLink/PlayLink.tsx
index f9d322606..f71913d10 100644
--- a/frontend/app/components/shared/SessionItem/PlayLink/PlayLink.tsx
+++ b/frontend/app/components/shared/SessionItem/PlayLink/PlayLink.tsx
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
-import { useHistory } from 'react-router';
+import { useNavigate } from 'react-router';
import {
liveSession as liveSessionRoute,
@@ -31,7 +31,7 @@ interface Props {
function PlayLink(props: Props) {
const { projectsStore } = useStore();
const { isAssist, viewed, sessionId, onClick = null, queryParams } = props;
- const history = useHistory();
+ const navigate = useNavigate()
const defaultIconName = getIconName(viewed);
const [iconName, setIconName] = useState
(defaultIconName);
@@ -58,7 +58,7 @@ function PlayLink(props: Props) {
} else {
e.preventDefault();
props.beforeOpen();
- history.push(replayLink);
+ navigate(replayLink);
}
}
};
diff --git a/frontend/app/components/shared/SessionItem/SessionItem.tsx b/frontend/app/components/shared/SessionItem/SessionItem.tsx
index 52e772cad..374a1cd10 100644
--- a/frontend/app/components/shared/SessionItem/SessionItem.tsx
+++ b/frontend/app/components/shared/SessionItem/SessionItem.tsx
@@ -2,7 +2,6 @@ import cn from 'classnames';
import { Duration } from 'luxon';
import { observer } from 'mobx-react-lite';
import React, { useState, useCallback, useMemo } from 'react';
-import { RouteComponentProps, useHistory, withRouter } from 'react-router-dom';
import { durationFormatted, formatTimeOrDate } from 'App/date';
import { useStore } from 'App/mstore';
@@ -14,7 +13,7 @@ import {
} from 'App/routes';
import { capitalize } from 'App/utils';
import { Avatar, CountryFlag, Icon, Label, TextEllipsis } from 'UI';
-
+import { useLocation } from "react-router";
import Counter from './Counter';
import ErrorBars from './ErrorBars';
import PlayLink from './PlayLink';
@@ -78,8 +77,8 @@ const PREFETCH_STATE = {
fetched: 2
};
-function SessionItem(props: RouteComponentProps & Props) {
- const { location } = useHistory();
+function SessionItem(props: Props) {
+ const location = useLocation();
const { settingsStore, sessionStore } = useStore();
const { timezone, shownTimezone } = settingsStore.sessionSettings;
const [prefetchState, setPrefetched] = useState(PREFETCH_STATE.none);
@@ -449,4 +448,4 @@ function SessionItem(props: RouteComponentProps & Props) {
);
}
-export default withRouter(observer(SessionItem));
+export default observer(SessionItem);
diff --git a/frontend/app/components/shared/SessionsTabOverview/components/SessionList/SessionList.tsx b/frontend/app/components/shared/SessionsTabOverview/components/SessionList/SessionList.tsx
index 2d05133b2..1d45cd28b 100644
--- a/frontend/app/components/shared/SessionsTabOverview/components/SessionList/SessionList.tsx
+++ b/frontend/app/components/shared/SessionsTabOverview/components/SessionList/SessionList.tsx
@@ -3,7 +3,7 @@ import { FilterKey } from 'Types/filter/filterType';
import SessionItem from 'Shared/SessionItem';
import { NoContent, Loader, Pagination, Icon } from 'UI';
import { Button } from 'antd'
-import { useLocation, withRouter } from 'react-router-dom';
+import { useLocation } from 'react-router';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
import { numberWithCommas } from 'App/utils';
import SessionDateRange from './SessionDateRange';
@@ -237,4 +237,4 @@ function SessionList() {
);
}
-export default withRouter(observer(SessionList));
+export default observer(SessionList);
diff --git a/frontend/app/components/ui/NavPrompt/index.tsx b/frontend/app/components/ui/NavPrompt/index.tsx
new file mode 100644
index 000000000..90bbbc1dc
--- /dev/null
+++ b/frontend/app/components/ui/NavPrompt/index.tsx
@@ -0,0 +1,46 @@
+import { useCallback, useEffect } from 'react';
+import { useBlocker } from 'react-router';
+
+function NavigationPrompt({ when, message }: any) {
+ const blocker = useCallback(
+ (tx) => {
+ if (!when) return false;
+
+ if (typeof message === 'function') {
+ const result = message(tx.nextLocation);
+ if (result === true) return false;
+ }
+
+ return true;
+ },
+ [when, message]
+ );
+
+ const { state, proceed, reset, location: nextLocation } = useBlocker(blocker);
+
+ useEffect(() => {
+ if (state === 'blocked') {
+ let promptMessage = 'Are you sure you want to leave this page?';
+ if (typeof message === 'function') {
+ const result = message(nextLocation);
+ if (typeof result === 'string') {
+ promptMessage = result;
+ }
+ } else if (typeof message === 'string') {
+ promptMessage = message;
+ }
+
+ const confirmed = window.confirm(promptMessage);
+
+ if (confirmed) {
+ proceed();
+ } else {
+ reset();
+ }
+ }
+ }, [state, proceed, reset, nextLocation, message]);
+
+ return null;
+}
+
+export default NavigationPrompt;
diff --git a/frontend/app/components/ui/NoSessionPermission/NoSessionPermission.tsx b/frontend/app/components/ui/NoSessionPermission/NoSessionPermission.tsx
index 0447a51ef..5ff5d0cd9 100644
--- a/frontend/app/components/ui/NoSessionPermission/NoSessionPermission.tsx
+++ b/frontend/app/components/ui/NoSessionPermission/NoSessionPermission.tsx
@@ -1,6 +1,6 @@
import { observer } from 'mobx-react-lite';
import React from 'react';
-import { RouteComponentProps, withRouter } from 'react-router-dom';
+import { useNavigate, useLocation } from "react-router";
import { useStore } from 'App/mstore';
import {
@@ -16,8 +16,7 @@ import stl from './NoSessionPermission.module.css';
const SESSIONS_ROUTE = sessionsRoute();
const ASSIST_ROUTE = assistRoute();
-interface Props extends RouteComponentProps {
- history: any;
+interface Props {
isLive?: boolean;
}
function NoSessionPermission(props: Props) {
@@ -26,19 +25,20 @@ function NoSessionPermission(props: Props) {
const sessionPath = sessionStore.sessionPath;
const isAssist = window.location.pathname.includes('/assist/');
const siteId = projectsStore.siteId!;
- const { history } = props;
+ const navigate = useNavigate();
+ const location = useLocation();
const backHandler = () => {
if (
- sessionPath.pathname === history.location.pathname ||
+ sessionPath.pathname === location.pathname ||
sessionPath.pathname.includes('/session/') ||
isAssist
) {
- history.push(
+ navigate(
withSiteId(isAssist ? ASSIST_ROUTE : SESSIONS_ROUTE, siteId)
);
} else {
- history.push(
+ navigate(
sessionPath
? sessionPath.pathname + sessionPath.search
: withSiteId(SESSIONS_ROUTE, siteId)
@@ -50,7 +50,7 @@ function NoSessionPermission(props: Props) {
Not allowed
- {session.isLive ? (
+ {session.live ? (
This session is still live, and you don’t have the necessary
permissions to access this feature. Please check with your admin.
@@ -68,6 +68,4 @@ function NoSessionPermission(props: Props) {
);
}
-export default withRouter(
- observer(NoSessionPermission)
-);
+export default observer(NoSessionPermission)
diff --git a/frontend/app/components/ui/index.js b/frontend/app/components/ui/index.js
index 90b7226a5..58bd6c9dd 100644
--- a/frontend/app/components/ui/index.js
+++ b/frontend/app/components/ui/index.js
@@ -47,4 +47,5 @@ export { default as Message } from './Message';
export { default as Popover } from './Popover';
export { default as Switch } from './Switch';
export { default as Divider } from './Divider';
-export { default as CodeBlock } from './CodeBlock'
\ No newline at end of file
+export { default as CodeBlock } from './CodeBlock'
+export { default as NavPrompt } from './NavPrompt';
\ No newline at end of file
diff --git a/frontend/app/hooks/useSessionSearchQueryHandler.ts b/frontend/app/hooks/useSessionSearchQueryHandler.ts
index ac31e4913..4b60d3023 100644
--- a/frontend/app/hooks/useSessionSearchQueryHandler.ts
+++ b/frontend/app/hooks/useSessionSearchQueryHandler.ts
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
-import { useHistory } from 'react-router';
+import { useNavigate } from 'react-router';
import { JsonUrlConverter } from 'App/utils/search';
import { useStore } from '@/mstore';
import Search from '@/mstore/types/search';
@@ -15,7 +15,7 @@ interface Props {
const useSessionSearchQueryHandler = ({ onBeforeLoad, appliedFilter, loading, onLoaded = () => null }: Props) => {
const { searchStore } = useStore();
const [beforeHookLoaded, setBeforeHookLoaded] = useState(!onBeforeLoad);
- const history = useHistory();
+ const navigate = useNavigate()
// Apply filter from the query string when the component mounts
useEffect(() => {
@@ -27,7 +27,7 @@ const useSessionSearchQueryHandler = ({ onBeforeLoad, appliedFilter, loading, on
setBeforeHookLoaded(true);
}
- const converter = JsonUrlConverter.urlParamsToJson(history.location.search);
+ const converter = JsonUrlConverter.urlParamsToJson(location.search);
const json = getFilterFromJson(converter.toJSON());
const filter = new Search(json);
@@ -57,27 +57,27 @@ const useSessionSearchQueryHandler = ({ onBeforeLoad, appliedFilter, loading, on
};
void applyFilterFromQuery();
- }, [loading, searchStore, history.location.search, onBeforeLoad]);
+ }, [loading, searchStore, location.search, onBeforeLoad]);
// Update the URL whenever the appliedFilter changes
useEffect(() => {
const updateUrlWithFilter = () => {
if (!loading && beforeHookLoaded) {
const query = JsonUrlConverter.jsonToUrlParams(appliedFilter);
- history.replace({ search: query });
+ navigate({ search: query }, { replace: true });
}
};
updateUrlWithFilter();
- }, [appliedFilter, loading, beforeHookLoaded, history]);
+ }, [appliedFilter, loading, beforeHookLoaded]);
// Ensure the URL syncs on remount if already parsed
useEffect(() => {
if (searchStore.urlParsed) {
const query = JsonUrlConverter.jsonToUrlParams(appliedFilter);
- history.replace({ search: query });
+ navigate({ search: query }, { replace: true });
}
- }, [appliedFilter, searchStore.urlParsed, history]);
+ }, [appliedFilter, searchStore.urlParsed]);
return null;
};
diff --git a/frontend/app/layout/SideMenu.tsx b/frontend/app/layout/SideMenu.tsx
index 85e8f0aa2..6482b0d2d 100644
--- a/frontend/app/layout/SideMenu.tsx
+++ b/frontend/app/layout/SideMenu.tsx
@@ -1,9 +1,8 @@
import { Divider, Menu, Tag, Typography, Popover, Button } from 'antd';
import cn from 'classnames';
import React from 'react';
-import { RouteComponentProps, withRouter } from 'react-router-dom';
import { observer } from 'mobx-react-lite';
-
+import { useLocation, useNavigate } from 'react-router';
import SupportModal from 'App/layout/SupportModal';
import * as routes from 'App/routes';
import {
@@ -30,15 +29,15 @@ import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
const { Text } = Typography;
-interface Props extends RouteComponentProps {
- siteId?: string;
+interface Props {
isCollapsed?: boolean;
}
function SideMenu(props: Props) {
+ const location = useLocation();
+ const navigate = useNavigate();
const {
- location,
- isCollapsed
+ isCollapsed,
} = props;
const isPreferencesActive = location.pathname.includes('/client/');
@@ -118,7 +117,7 @@ function SideMenu(props: Props) {
const menuRoutes: any = {
[MENU.EXIT]: () =>
- props.history.push(withSiteId(routes.sessions(), siteId)),
+ navigate(withSiteId(routes.sessions(), siteId)),
[MENU.SESSIONS]: () => withSiteId(routes.sessions(), siteId),
[MENU.BOOKMARKS]: () => withSiteId(routes.bookmarks(), siteId),
[MENU.VAULT]: () => withSiteId(routes.bookmarks(), siteId),
@@ -169,7 +168,7 @@ function SideMenu(props: Props) {
};
const pushTo = (path: string) => {
- props.history.push(path);
+ navigate(path);
};
const RenderDivider = (props: { index: number }) => {
@@ -324,8 +323,7 @@ function SideMenu(props: Props) {
);
}
-export default withRouter(observer(SideMenu));
-
+export default observer(SideMenu);
const SpotMenuItem = ({ isCollapsed }: any) => {
const [isModalVisible, setIsModalVisible] = React.useState(false);
diff --git a/frontend/app/layout/SpotToOpenReplayPrompt.tsx b/frontend/app/layout/SpotToOpenReplayPrompt.tsx
index db49e49a1..f123f0034 100644
--- a/frontend/app/layout/SpotToOpenReplayPrompt.tsx
+++ b/frontend/app/layout/SpotToOpenReplayPrompt.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { Modal, Button, List, Divider } from 'antd';
import { CircleDot, Play, TrendingUp, Radio, Sparkles, Plug, ArrowRight } from 'lucide-react';
-import { useHistory } from 'react-router-dom';
+import { useNavigate } from 'react-router';
import { onboarding } from 'App/routes';
import { useStore } from 'App/mstore';
@@ -15,7 +15,7 @@ const SpotToOpenReplayPrompt = ({ isVisible, onCancel }: {
onCancel: () => void;
}) => {
const { userStore } = useStore();
- const history = useHistory();
+ const navigate = useNavigate()
const features = [
{ icon: , text: 'Spot', noBorder: true },
{ isDivider: true },
@@ -28,7 +28,7 @@ const SpotToOpenReplayPrompt = ({ isVisible, onCancel }: {
const onUpgrade = () => {
userStore.upgradeScope().then(() => {
- history.push(onboarding());
+ navigate(onboarding());
onCancel();
})
}
diff --git a/frontend/package.json b/frontend/package.json
index e4bff1d30..de984c9f7 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -62,8 +62,8 @@
"react-draggable": "^4.4.5",
"react-google-recaptcha": "^2.1.0",
"react-intersection-observer": "^9.13.1",
- "react-router": "^5.3.3",
- "react-router-dom": "^5.3.3",
+ "react-router": "^6.30.0",
+ "react-router-dom": "^6.30.0",
"react-select": "^5.3.2",
"react-svg-map": "^2.2.0",
"react-toastify": "^9.1.1",
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 3cd24d927..784ccdd6e 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -1581,7 +1581,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.6, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.4, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.24.8, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
+"@babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.6, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.4, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.24.8, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.26.9
resolution: "@babel/runtime@npm:7.26.9"
dependencies:
@@ -2930,6 +2930,13 @@ __metadata:
languageName: node
linkType: hard
+"@remix-run/router@npm:1.23.0":
+ version: 1.23.0
+ resolution: "@remix-run/router@npm:1.23.0"
+ checksum: 10c1/c87d2227dc07ec5575cb3349dc388c0abd77a7f04bbdde531b183880c19c9550c3adbeb67a1a2ad677fbf13dd6192e2c42f479d5d99e4f01c7b53f250cec6c00
+ languageName: node
+ linkType: hard
+
"@sentry/browser@npm:^5.21.1":
version: 5.30.0
resolution: "@sentry/browser@npm:5.30.0"
@@ -8528,20 +8535,6 @@ __metadata:
languageName: node
linkType: hard
-"history@npm:^4.9.0":
- version: 4.10.1
- resolution: "history@npm:4.10.1"
- dependencies:
- "@babel/runtime": "npm:^7.1.2"
- loose-envify: "npm:^1.2.0"
- resolve-pathname: "npm:^3.0.0"
- tiny-invariant: "npm:^1.0.2"
- tiny-warning: "npm:^1.0.0"
- value-equal: "npm:^1.0.1"
- checksum: 10c1/52b1a0cc62f6bff70d29325ce3e16078f070e8d51405866ce617c266dbf66a8b3898b5dbd9272514844760e8c3d1e657240d64175ab6b133b8bb100161218b5b
- languageName: node
- linkType: hard
-
"hls.js@npm:^1.5.13":
version: 1.5.20
resolution: "hls.js@npm:1.5.20"
@@ -8549,7 +8542,7 @@ __metadata:
languageName: node
linkType: hard
-"hoist-non-react-statics@npm:^3.1.0, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
+"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
version: 3.3.2
resolution: "hoist-non-react-statics@npm:3.3.2"
dependencies:
@@ -9387,13 +9380,6 @@ __metadata:
languageName: node
linkType: hard
-"isarray@npm:0.0.1":
- version: 0.0.1
- resolution: "isarray@npm:0.0.1"
- checksum: 10c1/abd2b120df9b6e06385e1d2d109dc4eabac0b950e1a02448cde7416691462d809c32d2acdd28d6c2e2ede3527e6251debc9a56f7c7c8515da4ead1993f6ba514
- languageName: node
- linkType: hard
-
"isarray@npm:^2.0.5":
version: 2.0.5
resolution: "isarray@npm:2.0.5"
@@ -10563,7 +10549,7 @@ __metadata:
languageName: node
linkType: hard
-"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0":
+"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
dependencies:
@@ -11663,8 +11649,8 @@ __metadata:
react-draggable: "npm:^4.4.5"
react-google-recaptcha: "npm:^2.1.0"
react-intersection-observer: "npm:^9.13.1"
- react-router: "npm:^5.3.3"
- react-router-dom: "npm:^5.3.3"
+ react-router: "npm:^6.30.0"
+ react-router-dom: "npm:^6.30.0"
react-select: "npm:^5.3.2"
react-svg-map: "npm:^2.2.0"
react-toastify: "npm:^9.1.1"
@@ -11969,15 +11955,6 @@ __metadata:
languageName: node
linkType: hard
-"path-to-regexp@npm:^1.7.0":
- version: 1.9.0
- resolution: "path-to-regexp@npm:1.9.0"
- dependencies:
- isarray: "npm:0.0.1"
- checksum: 10c1/79d0f8f5221b7d1a2c3de08775f7ea158ef7bd978e9ed3c6b0813a89ffcc59edb9eee435913ce73e2aad99384b7101d40d81dfe312cf2f54da53990305108695
- languageName: node
- linkType: hard
-
"path-type@npm:^4.0.0":
version: 4.0.0
resolution: "path-type@npm:4.0.0"
@@ -13676,7 +13653,7 @@ __metadata:
languageName: node
linkType: hard
-"react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0":
+"react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.7.0":
version: 16.13.1
resolution: "react-is@npm:16.13.1"
checksum: 10c1/b1d8be84f510ec19f3dc7cebd9790076f708943e333e03a26dfadc225bd36b3ac6bbdc94a19e1cd72f43d366de47e21fa04396aba0e86ae0e50610fb4c7a47c8
@@ -13697,39 +13674,27 @@ __metadata:
languageName: node
linkType: hard
-"react-router-dom@npm:^5.3.3":
- version: 5.3.4
- resolution: "react-router-dom@npm:5.3.4"
+"react-router-dom@npm:^6.30.0":
+ version: 6.30.0
+ resolution: "react-router-dom@npm:6.30.0"
dependencies:
- "@babel/runtime": "npm:^7.12.13"
- history: "npm:^4.9.0"
- loose-envify: "npm:^1.3.1"
- prop-types: "npm:^15.6.2"
- react-router: "npm:5.3.4"
- tiny-invariant: "npm:^1.0.2"
- tiny-warning: "npm:^1.0.0"
+ "@remix-run/router": "npm:1.23.0"
+ react-router: "npm:6.30.0"
peerDependencies:
- react: ">=15"
- checksum: 10c1/1a00acf223dc8ffb7eb6c189dcc858858c4df37b51dd92b5d38aca456b9813596094e19fdcdcc8044daad054c5392de051643988c217e3a296d1df803e5106f4
+ react: ">=16.8"
+ react-dom: ">=16.8"
+ checksum: 10c1/00e36b130dcd6fdf7c2867b35ad547b28dfcdbc5b342699baaea785dbfbabd6d3e1d9213c3eb1ffb64e4b418b3a1053882b7ab568a68624f301c2ed88f6d38e5
languageName: node
linkType: hard
-"react-router@npm:5.3.4, react-router@npm:^5.3.3":
- version: 5.3.4
- resolution: "react-router@npm:5.3.4"
+"react-router@npm:6.30.0, react-router@npm:^6.30.0":
+ version: 6.30.0
+ resolution: "react-router@npm:6.30.0"
dependencies:
- "@babel/runtime": "npm:^7.12.13"
- history: "npm:^4.9.0"
- hoist-non-react-statics: "npm:^3.1.0"
- loose-envify: "npm:^1.3.1"
- path-to-regexp: "npm:^1.7.0"
- prop-types: "npm:^15.6.2"
- react-is: "npm:^16.6.0"
- tiny-invariant: "npm:^1.0.2"
- tiny-warning: "npm:^1.0.0"
+ "@remix-run/router": "npm:1.23.0"
peerDependencies:
- react: ">=15"
- checksum: 10c1/b920516e84fc10980a108b1ad368c4ebd3b5541c4de1bb071053c91ccc6410d1a7326aed6da6101d6728ca825ec661e73b87518078502e3a4879f5be924af2d6
+ react: ">=16.8"
+ checksum: 10c1/6d8b9dfcfa38b930f49a511d635f02dd66dfed6c120df08c41ebfc661c6c4aa388b59ac63e01ffba55a3f334e199ce2f9f76f1fd50d14fca52e213373c18368f
languageName: node
linkType: hard
@@ -14111,13 +14076,6 @@ __metadata:
languageName: node
linkType: hard
-"resolve-pathname@npm:^3.0.0":
- version: 3.0.0
- resolution: "resolve-pathname@npm:3.0.0"
- checksum: 10c1/7951bb47cbfc98a2cc0e4b62a099ce4191f01e42557b048cf8bf857092e0719a4d021f9765d770ec8967630656f0a78c4b656908183d09dd680649d20d56851b
- languageName: node
- linkType: hard
-
"resolve-pkg-maps@npm:^1.0.0":
version: 1.0.0
resolution: "resolve-pkg-maps@npm:1.0.0"
@@ -15607,20 +15565,13 @@ __metadata:
languageName: node
linkType: hard
-"tiny-invariant@npm:^1.0.2, tiny-invariant@npm:^1.3.1":
+"tiny-invariant@npm:^1.3.1":
version: 1.3.3
resolution: "tiny-invariant@npm:1.3.3"
checksum: 10c1/e9baa182794cfa0499134b3e7a886ab8be2e2cd15e070eedb81e2ae8ff379b8ddba146cb25093242c6768d127a93e7f2ce774c7be9a8035c1b34d02c9a5b0a8c
languageName: node
linkType: hard
-"tiny-warning@npm:^1.0.0":
- version: 1.0.3
- resolution: "tiny-warning@npm:1.0.3"
- checksum: 10c1/b559861279695929d2ed06390b7a455186cb796a5fd3fb8efa45de786b45976dcb46d038f1bd9aaa744abe3c3cbc08e6650ce34fabf419bc50e3150106e78751
- languageName: node
- linkType: hard
-
"tinyglobby@npm:^0.2.7":
version: 0.2.12
resolution: "tinyglobby@npm:0.2.12"
@@ -16259,13 +16210,6 @@ __metadata:
languageName: node
linkType: hard
-"value-equal@npm:^1.0.1":
- version: 1.0.1
- resolution: "value-equal@npm:1.0.1"
- checksum: 10c1/90eacdf332d054e39b44e190d72c4975cf3daee09084e16146eb5ae8590683b11a097d552efe9a6bbb3ea56489a06e5ea02c20acba83c1a84e20912a864d7981
- languageName: node
- linkType: hard
-
"vary@npm:~1.1.2":
version: 1.1.2
resolution: "vary@npm:1.1.2"