From 089938375070577f19f9b4a383b6910ceb14ec27 Mon Sep 17 00:00:00 2001 From: Piotr Rogowski Date: Tue, 25 Jan 2022 21:18:04 +0100 Subject: [PATCH] Update `react-router` (#397) --- package-lock.json | 165 ++++++------------------------ package.json | 2 +- src/App.tsx | 54 +++++----- src/components/CommandPalette.tsx | 25 ++--- src/components/TopBar.tsx | 29 ++---- src/components/Tune/SideBar.tsx | 15 +-- src/pages/Hub.tsx | 6 +- src/pages/Tune.tsx | 47 ++++++--- src/pages/Upload.tsx | 14 +-- src/pages/auth/Login.tsx | 6 +- src/pages/auth/ResetPassword.tsx | 6 +- src/pages/auth/SignUp.tsx | 6 +- 12 files changed, 132 insertions(+), 243 deletions(-) diff --git a/package-lock.json b/package-lock.json index a78467a..3d0eb8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "react-markdown": "^8.0.0", "react-perfect-scrollbar": "^1.5.8", "react-redux": "^7.2.6", - "react-router-dom": "^5.3.0", + "react-router-dom": "^6.2.1", "react-scripts": "^5.0.0", "uplot": "^1.6.18", "uplot-react": "^1.1.1" @@ -10012,16 +10012,11 @@ } }, "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz", + "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==", "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" + "@babel/runtime": "^7.7.6" } }, "node_modules/hoist-non-react-statics": { @@ -10755,11 +10750,6 @@ "node": ">=8" } }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -13758,19 +13748,6 @@ "node": ">=6" } }, - "node_modules/mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "dependencies": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - }, - "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, "node_modules/mini-css-extract-plugin": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz", @@ -14459,14 +14436,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -16868,40 +16837,27 @@ } }, "node_modules/react-router": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", - "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz", + "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "history": "^5.2.0" }, "peerDependencies": { - "react": ">=15" + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", - "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz", + "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.1", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "history": "^5.2.0", + "react-router": "6.2.1" }, "peerDependencies": { - "react": ">=15" + "react": ">=16.8", + "react-dom": ">=16.8" } }, "node_modules/react-scripts": { @@ -17284,11 +17240,6 @@ "node": ">=4" } }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, "node_modules/resolve-url-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", @@ -19299,11 +19250,6 @@ "node": ">= 8" } }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -27657,16 +27603,11 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz", + "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==", "requires": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" + "@babel/runtime": "^7.7.6" } }, "hoist-non-react-statics": { @@ -28155,11 +28096,6 @@ "is-docker": "^2.0.0" } }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -30289,15 +30225,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, - "mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "requires": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - } - }, "mini-css-extract-plugin": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz", @@ -30807,14 +30734,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "requires": { - "isarray": "0.0.1" - } - }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -32415,34 +32334,20 @@ "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" }, "react-router": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", - "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz", + "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==", "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "history": "^5.2.0" } }, "react-router-dom": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", - "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz", + "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==", "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.1", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "history": "^5.2.0", + "react-router": "6.2.1" } }, "react-scripts": { @@ -32741,11 +32646,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, - "resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, "resolve-url-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", @@ -34226,11 +34126,6 @@ } } }, - "value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 8a221cf..9aab6ba 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "react-markdown": "^8.0.0", "react-perfect-scrollbar": "^1.5.8", "react-redux": "^7.2.6", - "react-router-dom": "^5.3.0", + "react-router-dom": "^6.2.1", "react-scripts": "^5.0.0", "uplot": "^1.6.18", "uplot-react": "^1.1.1" diff --git a/src/App.tsx b/src/App.tsx index b47c70d..c29e1e2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,7 @@ import { - Switch, + Routes as ReactRoutes, Route, - useLocation, - matchPath, + useMatch, } from 'react-router-dom'; import { Layout, @@ -16,7 +15,6 @@ import { Suspense, useCallback, useEffect, - useMemo, } from 'react'; import TopBar from './components/TopBar'; import StatusBar from './components/StatusBar'; @@ -64,12 +62,8 @@ const App = ({ ui, navigation }: { ui: UIState, navigation: NavigationState }) = // const [lastDialogPath, setLastDialogPath] = useState(); // const lastDialogPath = storageGetSync('lastDialog'); - const { pathname } = useLocation(); - const matchedTunePath = useMemo(() => matchPath(pathname, { - path: Routes.TUNE_ROOT, - }), [pathname]); - - const tuneId = (matchedTunePath?.params as any)?.tuneId; + const tunePathMatch = useMatch(`${Routes.TUNE_ROOT}/*`); + const tuneId = tunePathMatch?.params.tuneId; useEffect(() => { if (tuneId) { @@ -125,53 +119,53 @@ const App = ({ ui, navigation }: { ui: UIState, navigation: NavigationState }) = <> - - + + - - + } /> + - - + } /> + - - + } /> + - - + } /> + - - + } /> + - - + } /> + - - + } /> + - - + } /> + - - + } /> + generatePath(route, { tu const ActionsProvider = (props: CommandPaletteProps) => { const { config, tune, navigation } = props; const { query } = useKBar(); - const history = useHistory(); + const navigate = useNavigate(); const generateActions = useCallback((types: MenusType) => { const newActions: Action[] = [ @@ -241,7 +241,7 @@ const ActionsProvider = (props: CommandPaletteProps) => { name: 'Info', subtitle: 'Basic information about this tune.', icon: , - perform: () => history.push(buildTuneUrl(navigation.tuneId!, Routes.TUNE_ROOT)), + perform: () => navigate(buildTuneUrl(navigation.tuneId!, Routes.TUNE_ROOT)), }, { id: 'LogsAction', @@ -249,7 +249,7 @@ const ActionsProvider = (props: CommandPaletteProps) => { name: 'Logs', subtitle: 'Log viewer.', icon: , - perform: () => history.push(buildTuneUrl(navigation.tuneId!, Routes.TUNE_LOGS)), + perform: () => navigate(buildTuneUrl(navigation.tuneId!, Routes.TUNE_LOGS)), }, { id: 'DiagnoseAction', @@ -257,7 +257,7 @@ const ActionsProvider = (props: CommandPaletteProps) => { name: 'Diagnose', subtitle: 'Tooth and composite logs viewer.', icon: , - perform: () => history.push(buildTuneUrl(navigation.tuneId!, Routes.TUNE_DIAGNOSE)), + perform: () => navigate(buildTuneUrl(navigation.tuneId!, Routes.TUNE_DIAGNOSE)), }, ]; @@ -281,16 +281,17 @@ const ActionsProvider = (props: CommandPaletteProps) => { section: types[menuName].title, name: subMenu.title, icon: , - perform: () => history.push(buildUrl(navigation.tuneId!, menuName, subMenuName)), + perform: () => navigate(buildUrl(navigation.tuneId!, menuName, subMenuName)), }); }); }); return newActions; - }, [history, navigation.tuneId]); + }, [navigate, navigation.tuneId]); useEffect(() => { if (Object.keys(tune.constants).length) { + // TODO: unregister old actions query.registerActions(generateActions(config.menus)); } }, [config.menus, generateActions, query, tune.constants]); @@ -301,7 +302,7 @@ const ActionsProvider = (props: CommandPaletteProps) => { const CommandPalette = (props: CommandPaletteProps) => { const { children, config, tune, navigation } = props; const { logout } = useAuth(); - const history = useHistory(); + const navigate = useNavigate(); const logoutAction = useCallback(async () => { try { @@ -320,7 +321,7 @@ const CommandPalette = (props: CommandPaletteProps) => { name: 'Hub', subtitle: 'Public tunes and logs.', icon: , - perform: () => history.push(Routes.ROOT), + perform: () => navigate(Routes.ROOT), }, { id: 'ToggleSidebar', @@ -334,7 +335,7 @@ const CommandPalette = (props: CommandPaletteProps) => { name: 'Upload', subtitle: 'Upload tune and logs.', icon: , - perform: () => history.push(Routes.UPLOAD), + perform: () => navigate(Routes.UPLOAD), }, { id: 'LoginAction', @@ -342,7 +343,7 @@ const CommandPalette = (props: CommandPaletteProps) => { name: 'Login', subtitle: 'Login using email, Google or GitHub account.', icon: , - perform: () => history.push(Routes.LOGIN), + perform: () => navigate(Routes.LOGIN), }, { id: 'SignUpAction', @@ -350,7 +351,7 @@ const CommandPalette = (props: CommandPaletteProps) => { name: 'Sign-up', subtitle: 'Create new account.', icon: , - perform: () => history.push(Routes.SIGN_UP), + perform: () => navigate(Routes.SIGN_UP), }, { id: 'LogoutAction', diff --git a/src/components/TopBar.tsx b/src/components/TopBar.tsx index 4a6de46..a99cc43 100644 --- a/src/components/TopBar.tsx +++ b/src/components/TopBar.tsx @@ -1,16 +1,13 @@ import { useCallback, useEffect, - useMemo, } from 'react'; import { - matchPath, useLocation, - useHistory, -} from 'react-router'; -import { + useNavigate, Link, generatePath, + useMatch, } from 'react-router-dom'; import { Layout, @@ -72,18 +69,14 @@ const TopBar = ({ tuneId }: { tuneId: string | null }) => { const { sm, lg } = useBreakpoint(); const { pathname } = useLocation(); const { currentUser, logout } = useAuth(); - const history = useHistory(); + const navigate = useNavigate(); const { query } = useKBar(); const buildTuneUrl = (route: string) => tuneId ? generatePath(route, { tuneId }) : null; - const matchedRootPath = useMemo(() => matchPath(pathname, { - path: Routes.ROOT, - }), [pathname]); - const matchedTuneRootPath = useMemo(() => matchPath(pathname, { - path: Routes.TUNE_ROOT, - }), [pathname]); - const matchedTabPath = useMemo(() => matchPath(pathname, { - path: Routes.TUNE_TAB, - }), [pathname]); + const rootPathMatch = useMatch(Routes.ROOT); + const tuneRootMatch = useMatch(`${Routes.TUNE_ROOT}/*`); + const tuneTuneMatch = useMatch(`${Routes.TUNE_TUNE}/*`); + const tabMatch = useMatch(`${Routes.TUNE_TAB}/*`); + const uploadMatch = useMatch(Routes.UPLOAD); const logoutClick = useCallback(async () => { try { await logout(); @@ -118,10 +111,10 @@ const TopBar = ({ tuneId }: { tuneId: string | null }) => { history.push(e.target.value)} + onChange={(e) => navigate(e.target.value)} > @@ -190,7 +183,7 @@ const TopBar = ({ tuneId }: { tuneId: string | null }) => { diff --git a/src/components/Tune/SideBar.tsx b/src/components/Tune/SideBar.tsx index a0919bb..a91e7d0 100644 --- a/src/components/Tune/SideBar.tsx +++ b/src/components/Tune/SideBar.tsx @@ -7,6 +7,7 @@ import { connect } from 'react-redux'; import { generatePath, Link, + PathMatch, } from 'react-router-dom'; import PerfectScrollbar from 'react-perfect-scrollbar'; import { @@ -52,14 +53,6 @@ export const buildUrl = (tuneId: string, main: string, sub: string) => generateP dialog: sub, }); -export interface DialogMatchedPathType { - url: string; - params: { - category: string; - dialog: string; - }; -} - const mapStateToProps = (state: AppState) => ({ config: state.config, tune: state.tune, @@ -72,7 +65,7 @@ interface SideBarProps { tune: TuneType; ui: UIState; navigation: NavigationState; - matchedPath: DialogMatchedPathType; + matchedPath: PathMatch<'dialog' | 'tuneId' | 'category'>; }; const SideBar = ({ config, tune, ui, navigation, matchedPath }: SideBarProps) => { @@ -148,11 +141,11 @@ const SideBar = ({ config, tune, ui, navigation, matchedPath }: SideBarProps) => {menus} diff --git a/src/pages/Hub.tsx b/src/pages/Hub.tsx index 31b52e3..341f0c9 100644 --- a/src/pages/Hub.tsx +++ b/src/pages/Hub.tsx @@ -18,7 +18,7 @@ import { } from 'react'; import { generatePath, - useHistory, + useNavigate, } from 'react-router'; import useDb from '../hooks/useDb'; import { TuneDbData } from '../types/dbData'; @@ -48,10 +48,10 @@ const loadingCards = ( const Hub = () => { const [tunes, setTunes] = useState([]); const { listTunes } = useDb(); - const history = useHistory(); + const navigate = useNavigate(); const [copied, setCopied] = useState(false); - const goToTune = (tuneId: string) => history.push(generatePath(Routes.TUNE_ROOT, { tuneId })); + const goToTune = (tuneId: string) => navigate(generatePath(Routes.TUNE_ROOT, { tuneId })); const copyToClipboard = async (shareUrl: string) => { if (navigator.clipboard) { diff --git a/src/pages/Tune.tsx b/src/pages/Tune.tsx index 1dc7355..1ee29ba 100644 --- a/src/pages/Tune.tsx +++ b/src/pages/Tune.tsx @@ -1,15 +1,17 @@ +import { Skeleton } from 'antd'; import { - useLocation, - Route, - matchPath, - Redirect, generatePath, + useMatch, + useNavigate, } from 'react-router-dom'; import { connect } from 'react-redux'; -import { useMemo } from 'react'; +import { + useEffect, + useMemo, +} from 'react'; import { Config as ConfigType } from '@speedy-tuner/types'; import Dialog from '../components/Tune/Dialog'; -import SideBar, { DialogMatchedPathType } from '../components/Tune/SideBar'; +import SideBar from '../components/Tune/SideBar'; import { Routes } from '../routes'; import useConfig from '../hooks/useConfig'; import { @@ -24,14 +26,12 @@ const mapStateToProps = (state: AppState) => ({ }); const Tune = ({ navigation, config }: { navigation: NavigationState, config: ConfigType }) => { - const { pathname } = useLocation(); + const dialogMatch = useMatch(Routes.TUNE_DIALOG); + const tuneRootMatch = useMatch(Routes.TUNE_TUNE); // const { storageGetSync } = useBrowserStorage(); // const lastDialogPath = storageGetSync('lastDialog'); const { isConfigReady } = useConfig(config); - const dialogMatchedPath: DialogMatchedPathType = useMemo(() => matchPath(pathname, { - path: Routes.TUNE_DIALOG, - exact: true, - }) || { url: '', params: { category: '', dialog: '' } }, [pathname]); + const navigate = useNavigate(); const firstDialogPath = useMemo(() => { if (!isConfigReady) { @@ -40,6 +40,7 @@ const Tune = ({ navigation, config }: { navigation: NavigationState, config: Con const firstCategory = Object.keys(config.menus)[0]; const firstDialog = Object.keys(config.menus[firstCategory].subMenus)[0]; + return generatePath(Routes.TUNE_DIALOG, { tuneId: navigation.tuneId!, category: firstCategory, @@ -47,15 +48,27 @@ const Tune = ({ navigation, config }: { navigation: NavigationState, config: Con }); }, [config.menus, isConfigReady, navigation.tuneId]); + useEffect(() => { + if (tuneRootMatch && firstDialogPath) { + navigate(firstDialogPath, { replace: true }); + } + }, [firstDialogPath, navigate, tuneRootMatch, isConfigReady]); + + // TODO: unify loading indicators across the app + if (!isConfigReady || !dialogMatch) { + return ( +
+ +
+ ); + } + return ( <> - - {firstDialogPath && } - - + ); diff --git a/src/pages/Upload.tsx b/src/pages/Upload.tsx index 22ea1b3..a8dfdcc 100644 --- a/src/pages/Upload.tsx +++ b/src/pages/Upload.tsx @@ -36,7 +36,7 @@ import { UploadRequestOption } from 'rc-upload/lib/interface'; import { UploadFile } from 'antd/lib/upload/interface'; import { generatePath, - useHistory, + useNavigate, } from 'react-router-dom'; import ReactMarkdown from 'react-markdown'; import pako from 'pako'; @@ -114,7 +114,7 @@ const UploadPage = () => { const [customIniFile, setCustomIniFile] = useState(null); const hasNavigatorShare = navigator.share !== undefined; const { currentUser, refreshToken } = useAuth(); - const history = useHistory(); + const navigate = useNavigate(); const { removeFile, uploadFile, basePathForFile } = useServerStorage(); const { updateData } = useDb(); const requiredRules = [{ required: true, message: 'This field is required!' }]; @@ -122,7 +122,7 @@ const UploadPage = () => { const noop = () => { }; - const goToNewTune = () => history.push(generatePath(Routes.TUNE_ROOT, { + const goToNewTune = () => navigate(generatePath(Routes.TUNE_ROOT, { tuneId: newTuneId!, })); @@ -409,7 +409,7 @@ const UploadPage = () => { const prepareData = useCallback(async () => { if (!currentUser) { restrictedPage(); - history.push(Routes.LOGIN); + navigate(Routes.LOGIN); return; } @@ -418,7 +418,7 @@ const UploadPage = () => { await refreshToken(); if (!currentUser.emailVerified) { emailNotVerified(); - history.push(Routes.LOGIN); + navigate(Routes.LOGIN); return; } @@ -432,11 +432,11 @@ const UploadPage = () => { const tuneId = nanoidCustom(); setNewTuneId(tuneId); console.log('New tuneId:', tuneId); - }, [currentUser, history, refreshToken]); + }, [currentUser, navigate, refreshToken]); useEffect(() => { prepareData(); - }, [currentUser, history, prepareData, refreshToken]); + }, [currentUser, prepareData, refreshToken]); const uploadButton = ( diff --git a/src/pages/auth/Login.tsx b/src/pages/auth/Login.tsx index 283d510..62adcca 100644 --- a/src/pages/auth/Login.tsx +++ b/src/pages/auth/Login.tsx @@ -17,7 +17,7 @@ import { } from '@ant-design/icons'; import { Link, - useHistory, + useNavigate, } from 'react-router-dom'; import { useAuth } from '../../contexts/AuthContext'; import { Routes } from '../../routes'; @@ -37,9 +37,9 @@ const Login = () => { const [isGoogleLoading, setIsGoogleLoading] = useState(false); const [isGithubLoading, setIsGithubLoading] = useState(false); const { login, googleAuth, githubAuth } = useAuth(); - const history = useHistory(); + const navigate = useNavigate(); const isAnythingLoading = isEmailLoading || isGoogleLoading || isGithubLoading; - const redirectAfterLogin = useCallback(() => history.push(Routes.UPLOAD), [history]); + const redirectAfterLogin = useCallback(() => navigate(Routes.UPLOAD), [navigate]); const googleLogin = useCallback(async () => { setIsGoogleLoading(true); diff --git a/src/pages/auth/ResetPassword.tsx b/src/pages/auth/ResetPassword.tsx index dd4b5b9..063a534 100644 --- a/src/pages/auth/ResetPassword.tsx +++ b/src/pages/auth/ResetPassword.tsx @@ -8,7 +8,7 @@ import { import { MailOutlined } from '@ant-design/icons'; import { Link, - useHistory, + useNavigate, } from 'react-router-dom'; import { useAuth } from '../../contexts/AuthContext'; import { Routes } from '../../routes'; @@ -25,14 +25,14 @@ const ResetPassword = () => { const [form] = Form.useForm(); const [isLoading, setIsLoading] = useState(false); const { resetPassword } = useAuth(); - const history = useHistory(); + const navigate = useNavigate(); const onFinish = async ({ email }: { form: any, email: string }) => { setIsLoading(true); try { await resetPassword(email); resetSuccessful(); - history.push(Routes.LOGIN); + navigate(Routes.LOGIN); } catch (error) { form.resetFields(); console.warn(error); diff --git a/src/pages/auth/SignUp.tsx b/src/pages/auth/SignUp.tsx index a7f9ce0..e6bd834 100644 --- a/src/pages/auth/SignUp.tsx +++ b/src/pages/auth/SignUp.tsx @@ -11,7 +11,7 @@ import { } from '@ant-design/icons'; import { Link, - useHistory, + useNavigate, } from 'react-router-dom'; import { useAuth } from '../../contexts/AuthContext'; import { Routes } from '../../routes'; @@ -31,7 +31,7 @@ const SignUp = () => { const [form] = Form.useForm(); const [isLoading, setIsLoading] = useState(false); const { signUp } = useAuth(); - const history = useHistory(); + const navigate = useNavigate(); const onFinish = async ({ email, password }: { email: string, password: string }) => { setIsLoading(true); @@ -39,7 +39,7 @@ const SignUp = () => { await signUp(email, password); signUpSuccessful(); emailNotVerified(); - history.push(Routes.ROOT); + navigate(Routes.ROOT); } catch (error) { form.resetFields(); console.warn(error);