diff --git a/package.json b/package.json index 3ec75404a..7442066f3 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "react-dom": "^17.0.1", "react-hook-form": "7.34.2", "react-i18next": "^13.5.0", - "react-router-dom": "^5.2.0", + "react-router-dom": "^6.28.0", "react-test-renderer": "^16.13.1", "sass": "^1.77.2", "typescript": "4.9.5", diff --git a/src/App.tsx b/src/App.tsx index e40b25520..c57b786c3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,8 +3,8 @@ import React, { useCallback, useMemo, useState } from 'react'; import { BrowserRouter as Router, Route, - Switch, - RouteComponentProps, + Routes, + useParams, } from 'react-router-dom'; import 'hds-core'; import { AppContext } from './App-context'; @@ -22,7 +22,7 @@ import NavigationAndFooterWrapper from './components/navigation-and-footer-wrapp import HaukiHeader from './components/header/HaukiHeader'; import './App.scss'; import { Language } from './common/lib/types'; -import PrivateResourceRoute from './components/router/PrivateResourceRoute'; +import PermissionResolver from './components/router/PermissionResolver'; import ResourcePage from './pages/ResourcePage'; import ResourceBatchUpdatePage from './pages/ResourceBatchUpdatePage'; import AddNormalOpeningHoursPage from './pages/AddNormalOpeningHoursPage'; @@ -54,6 +54,12 @@ const App = (): JSX.Element => { const hasOpenerWindow = document.referrer && document.referrer !== window.location.href; + const { id, childId, datePeriodId } = useParams<{ + id?: string; + childId?: string; + datePeriodId?: string; + }>(); + const closeAppWindow = useCallback((): void => { // A window can only close itself if it has an parent opener. if (hasOpenerWindow) { @@ -121,61 +127,89 @@ const App = (): JSX.Element => { - - - -
-

Etusivu

-
-
-
- - -
-

Kohdetta ei löydy

-

- Kohdetta ei löytynyt. Yritä myöhemmin uudestaan. - Ongelman toistuessa ota yhteys sivuston ylläpitoon. - Teidät on automaattisesti kirjattu ulos. -

-
-
-
- - -
-

Puutteelliset tunnukset

-
-
-
- - -
-

Puuttuvat tunnukset

-
-
-
- - -
- -
-
-
- + +
+

Etusivu

+
+ + } + /> + +
+

Kohdetta ei löydy

+

+ Kohdetta ei löytynyt. Yritä myöhemmin uudestaan. + Ongelman toistuessa ota yhteys sivuston ylläpitoon. + Teidät on automaattisesti kirjattu ulos. +

+
+ + } + /> + +
+

Puutteelliset tunnukset

+
+ + } + /> + +
+

Puuttuvat tunnukset

+
+ + } + /> + +
+ +
+ + } + /> + ) => { - const { id, childId } = match.params; - - return ( - id && ( + path="/resource/:id" + element={ + id && ( + + +
+ + + +
+
+
+ ) + } + /> +
@@ -187,23 +221,16 @@ const App = (): JSX.Element => {
- ) - ); - }} + + ) + } /> - ) => { - const { id } = match.params; - - return ( - id && ( + path="/resource/:id/batch" + element={ + id && ( +
@@ -214,147 +241,135 @@ const App = (): JSX.Element => {
- ) - ); - }} +
+ ) + } /> - + +
+ +
+ + ) + } + /> + ) => { - const { id } = match.params; - - return ( - id && ( - <> - -
- -
- - ) - ); - }} + path="/resource/:id/period/new" + element={ + id && ( + + +
+ +
+
+ ) + } + /> + + +
+ +
+ + ) + } /> - ) => { - const { id, datePeriodId } = match.params; - - return ( - id && - datePeriodId && ( - <> - -
- -
- - ) - ); - }} + path="/resource/:id/period/:datePeriodId" + element={ + id && + datePeriodId && ( + + +
+ +
+
+ ) + } /> - + +
+ +
+ + ) + } + /> + ) => { - const { id } = match.params; - - return ( - id && ( - <> - -
- -
- - ) - ); - }} + path="/resource/:id/holidays" + element={ + id && ( + + +
+ +
+
+ ) + } /> - ) => { - const { id } = match.params; - - return ( - id && ( - <> - -
- -
- - ) - ); - }} + + +
+ +
+ + ) + } /> - ) => { - const { id, datePeriodId } = match.params; - - return ( - id && - datePeriodId && ( - <> - -
- -
- - ) - ); - }} + path="/resource/:parentId/child/:id/exception/:datePeriodId" + element={ + id && + datePeriodId && ( + + +
+ +
+
+ ) + } /> -
+
diff --git a/src/components/header/HaukiHeader.test.tsx b/src/components/header/HaukiHeader.test.tsx index a2068b644..521500be5 100644 --- a/src/components/header/HaukiHeader.test.tsx +++ b/src/components/header/HaukiHeader.test.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { render, waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { BrowserRouter as Router } from 'react-router-dom'; -import { Mock } from 'vitest'; import api from '../../common/utils/api/api'; import { AppContext } from '../../App-context'; import { AuthContext } from '../../auth/auth-context'; @@ -33,9 +32,7 @@ vi.mock('react-router-dom', async (importOriginal) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment /* @ts-ignore */ ...mod, - useHistory: (): { push: Mock } => ({ - push: vi.fn(), - }), + useNavigate: vi.fn(), }; }); diff --git a/src/components/header/HaukiHeader.tsx b/src/components/header/HaukiHeader.tsx index def00ea4e..47b380be0 100644 --- a/src/components/header/HaukiHeader.tsx +++ b/src/components/header/HaukiHeader.tsx @@ -1,6 +1,6 @@ /* eslint-disable jsx-a11y/anchor-is-valid */ import React from 'react'; -import { useHistory, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { IconCrossCircleFill, IconUser, @@ -25,7 +25,7 @@ const HaukiHeader = (): JSX.Element => { const authProps: Partial = useAuth(); const { i18n, t } = useTranslation(); const { authTokens, clearAuth } = authProps; - const history = useHistory(); + const navigate = useNavigate(); const isAuthenticated = !!authTokens; const { id } = useParams<{ id: string }>(); @@ -41,7 +41,7 @@ const HaukiHeader = (): JSX.Element => { if (clearAuth) { clearAuth(); } - history.push('/'); + navigate('/'); } else { showSignOutErrorNotification(t('Header.SignOutRejected')); } @@ -84,7 +84,7 @@ const HaukiHeader = (): JSX.Element => { const urlSearchParams = new URLSearchParams(window.location.search); urlSearchParams.set('lang', newLanguage); - history.push({ + navigate({ pathname: window.location.pathname, search: urlSearchParams.toString(), }); diff --git a/src/components/opening-periods-section/OpeningPeriodsSection.tsx b/src/components/opening-periods-section/OpeningPeriodsSection.tsx index af9266ab0..f96a1df9f 100644 --- a/src/components/opening-periods-section/OpeningPeriodsSection.tsx +++ b/src/components/opening-periods-section/OpeningPeriodsSection.tsx @@ -1,7 +1,7 @@ import { Checkbox, LoadingSpinner } from 'hds-react'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { DatePeriod } from '../../common/lib/types'; import { PrimaryButton, SecondaryButton } from '../button/Button'; import './OpeningPeriodsSection.scss'; @@ -35,7 +35,7 @@ const OpeningPeriodsSection = ({ title, theme, }: Props): JSX.Element => { - const history = useHistory(); + const navigate = useNavigate(); const { selectedDatePeriods, removeDatePeriods, @@ -117,7 +117,7 @@ const OpeningPeriodsSection = ({ dataTest={addNewOpeningPeriodButtonDataTest} light onClick={(): void => { - history.push(newUrl); + navigate(newUrl); }} size="small"> {addDatePeriodButtonText} diff --git a/src/components/router/PrivateResourceRoute.test.tsx b/src/components/router/PermissionResolver.test.tsx similarity index 72% rename from src/components/router/PrivateResourceRoute.test.tsx rename to src/components/router/PermissionResolver.test.tsx index 2fad5be43..aab152549 100644 --- a/src/components/router/PrivateResourceRoute.test.tsx +++ b/src/components/router/PermissionResolver.test.tsx @@ -1,13 +1,9 @@ import React from 'react'; -import { - BrowserRouter as Router, - Route, - RouteComponentProps, -} from 'react-router-dom'; +import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import { render, screen, waitFor } from '@testing-library/react'; import api from '../../common/utils/api/api'; import * as AuthContext from '../../auth/auth-context'; -import PrivateResourceRoute from './PrivateResourceRoute'; +import PermissionResolver from './PermissionResolver'; import { AuthTokens } from '../../auth/auth-context'; const testTokens: AuthTokens = { @@ -21,7 +17,7 @@ const testTokens: AuthTokens = { hsa_has_organization_rights: 'true', }; -const renderRoutesWithPrivateRoute = () => { +const renderRoutesWithPermissionResolver = () => { window.history.pushState( {}, 'Test page', @@ -30,23 +26,24 @@ const renderRoutesWithPrivateRoute = () => { return render( - -

Test not found

-
- -

Test unauthenticated

-
- -

Test unauthorized

-
- ) => ( -

{match.params.id}

- )} - /> + + Test not found} /> + Test unauthenticated} + /> + + Test unauthorized} /> + +

{testTokens.hsa_resource}

+ + } + /> +
); }; @@ -71,7 +68,7 @@ const mockPermissionsApi = (hasPermission: boolean): void => { ); }; -describe(``, () => { +describe(``, () => { afterEach(() => { vi.clearAllMocks(); }); @@ -80,7 +77,7 @@ describe(``, () => { mockContext(); mockPermissionsApi(true); - const { getByText } = renderRoutesWithPrivateRoute(); + const { getByText } = renderRoutesWithPermissionResolver(); expect(getByText('Sivua alustetaan..')).toBeInTheDocument(); }); @@ -89,7 +86,7 @@ describe(``, () => { mockContext(); mockPermissionsApi(true); - renderRoutesWithPrivateRoute(); + renderRoutesWithPermissionResolver(); await waitFor(async () => expect( @@ -102,7 +99,7 @@ describe(``, () => { mockContext(); mockPermissionsApi(false); - renderRoutesWithPrivateRoute(); + renderRoutesWithPermissionResolver(); await waitFor(async () => expect(await screen.findByText('Test unauthorized')).toBeInTheDocument() @@ -113,7 +110,7 @@ describe(``, () => { mockContext({ tokens: undefined }); mockPermissionsApi(false); - renderRoutesWithPrivateRoute(); + renderRoutesWithPermissionResolver(); await waitFor(async () => expect( @@ -135,7 +132,7 @@ describe(``, () => { Promise.reject(resourceNotFoundError) ); - renderRoutesWithPrivateRoute(); + renderRoutesWithPermissionResolver(); await waitFor(async () => expect(await screen.findByText('Test not found')).toBeInTheDocument() diff --git a/src/components/router/PermissionResolver.tsx b/src/components/router/PermissionResolver.tsx new file mode 100644 index 000000000..7519bc1f0 --- /dev/null +++ b/src/components/router/PermissionResolver.tsx @@ -0,0 +1,62 @@ +import React, { ReactNode, useEffect, useState } from 'react'; +import { Navigate, useLocation, useNavigate } from 'react-router-dom'; +import { AuthContextProps, useAuth } from '../../auth/auth-context'; +import api from '../../common/utils/api/api'; +import Main from '../main/Main'; + +const PermissionResolver = ({ + id, + children, +}: { + id?: string; + children?: ReactNode; +}): JSX.Element => { + const { authTokens, clearAuth }: Partial = useAuth(); + const { pathname, search } = useLocation(); + const navigate = useNavigate(); + const isAuthenticated = !!authTokens; + const [isLoading, setIsLoading] = useState(true); + const [isAuthorized, setIsAuthorized] = useState(false); + + useEffect(() => { + if (!id || !isAuthenticated) { + setIsLoading(false); + } else { + api + .testResourcePostPermission(id) + .then((hasPermission: boolean) => { + setIsAuthorized(hasPermission); + setIsLoading(false); + }) + .catch((e) => { + if (clearAuth) { + clearAuth(); + } + if (e.response?.status === 404) { + return navigate(`/not_found?original_request=${pathname}${search}`); + } + return setIsLoading(false); + }); + } + }, [clearAuth, navigate, id, isAuthenticated, pathname, search]); + + if (isLoading) { + return ( +
+

Sivua alustetaan..

+
+ ); + } + + if (!isAuthenticated) { + return ; + } + + if (!isAuthorized) { + return ; + } + + return <>{children}; +}; + +export default PermissionResolver; diff --git a/src/components/router/PrivateResourceRoute.tsx b/src/components/router/PrivateResourceRoute.tsx deleted file mode 100644 index 6d37b1893..000000000 --- a/src/components/router/PrivateResourceRoute.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React, { ReactNode, useEffect, useState } from 'react'; -import { - Route, - Redirect, - RouteProps, - RouteComponentProps, - useLocation, - useHistory, -} from 'react-router-dom'; -import { AuthContextProps, useAuth } from '../../auth/auth-context'; -import api from '../../common/utils/api/api'; -import Main from '../main/Main'; - -const PermissionResolver = ({ - id, - children, -}: { - id?: string; - children?: ReactNode; -}): JSX.Element => { - const { authTokens, clearAuth }: Partial = useAuth(); - const { pathname, search } = useLocation(); - const history = useHistory(); - const isAuthenticated = !!authTokens; - const [isLoading, setLoading] = useState(true); - const [isAuthorized, setIsAuthorized] = useState(false); - - useEffect(() => { - if (!id || !isAuthenticated) { - setLoading(false); - } else { - api - .testResourcePostPermission(id) - .then((hasPermission: boolean) => { - setIsAuthorized(hasPermission); - setLoading(false); - }) - .catch((e) => { - if (clearAuth) { - clearAuth(); - } - if (e.response?.status === 404) { - return history.push( - `/not_found?original_request=${pathname}${search}` - ); - } - return setLoading(false); - }); - } - }, [clearAuth, history, id, isAuthenticated, pathname, search]); - - if (isLoading) { - return ( -
-

Sivua alustetaan..

-
- ); - } - - if (!isAuthenticated) { - return ; - } - - if (!isAuthorized) { - return ; - } - - return <>{children}; -}; - -type ComputedMatch = { - params: { - id?: string; - }; -}; - -interface PrivateRouteProps extends RouteProps { - computedMatch?: ComputedMatch; - id: string; -} - -const PrivateResourceRoute = (routeProps: PrivateRouteProps): JSX.Element => { - const { render, ...rest } = routeProps; - - return ( - ) => { - if (!render) { - // eslint-disable-next-line no-console - console.error( - 'Missing required render prop from PrivateResourceRoute-attributes' - ); - return ; - } - - return ( - - {render(props)} - - ); - }} - /> - ); -}; - -export default PrivateResourceRoute; diff --git a/src/hooks/useGoToResourceBatchUpdatePage.ts b/src/hooks/useGoToResourceBatchUpdatePage.ts index 3b25a4808..9bffa20ad 100644 --- a/src/hooks/useGoToResourceBatchUpdatePage.ts +++ b/src/hooks/useGoToResourceBatchUpdatePage.ts @@ -1,11 +1,9 @@ import { useCallback } from 'react'; -import { useHistory, useRouteMatch } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; const useGotToResourceBatchUpdataPage = (): (() => void) => { - const history = useHistory(); - const { - params: { parentId, id: resourceId }, - } = useRouteMatch<{ + const navigate = useNavigate(); + const { parentId, id: resourceId } = useParams<{ parentId?: string; id?: string; }>(); @@ -19,8 +17,8 @@ const useGotToResourceBatchUpdataPage = (): (() => void) => { ? `${parentId}/child/${resourceId}` : resourceId; - history.push(`/resource/${resourcePath}/batch`); - }, [history, parentId, resourceId]); + navigate(`/resource/${resourcePath}/batch`); + }, [navigate, parentId, resourceId]); }; export default useGotToResourceBatchUpdataPage; diff --git a/src/hooks/useReturnToResourcePage.ts b/src/hooks/useReturnToResourcePage.ts index 8403219d2..b1d6caaae 100644 --- a/src/hooks/useReturnToResourcePage.ts +++ b/src/hooks/useReturnToResourcePage.ts @@ -1,11 +1,9 @@ import { useCallback } from 'react'; -import { useHistory, useRouteMatch } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; const useReturnToResourcePage = (): (() => void) => { - const history = useHistory(); - const { - params: { parentId, id: resourceId }, - } = useRouteMatch<{ + const navigate = useNavigate(); + const { parentId, id: resourceId } = useParams<{ parentId?: string; id?: string; }>(); @@ -19,8 +17,8 @@ const useReturnToResourcePage = (): (() => void) => { ? `${parentId}/child/${resourceId}` : resourceId; - history.push(`/resource/${resourcePath}`); - }, [history, parentId, resourceId]); + navigate(`/resource/${resourcePath}`); + }, [navigate, parentId, resourceId]); }; export default useReturnToResourcePage; diff --git a/src/pages/ResourceBatchUpdatePage.tsx b/src/pages/ResourceBatchUpdatePage.tsx index a394576d0..734179374 100644 --- a/src/pages/ResourceBatchUpdatePage.tsx +++ b/src/pages/ResourceBatchUpdatePage.tsx @@ -1,6 +1,6 @@ /* eslint-disable no-underscore-dangle */ import React, { useEffect, useState } from 'react'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { Notification, Table, @@ -67,7 +67,7 @@ const ResourceBatchUpdatePage = ({ } = useAppContext(); const authProps: Partial = useAuth(); const { authTokens, clearAuth } = authProps; - const history = useHistory(); + const navigate = useNavigate(); const isAuthenticated = !!authTokens; const { isModalOpen, openModal } = useModal(); const [resource, setResource] = useState(undefined); @@ -120,7 +120,7 @@ const ResourceBatchUpdatePage = ({ if (clearAuth) { clearAuth(); } - history.push('/'); + navigate('/'); } else { showErrorNotification(t('ResourcePage.Notifications.SignOutFailed')); } diff --git a/yarn.lock b/yarn.lock index 0b6af4963..9e2da317c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -257,7 +257,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.9.2": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e" integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw== @@ -990,6 +990,11 @@ resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.22.1.tgz#4e5de032fcb0b7bca50f6a9f8e133fd882821930" integrity sha512-PCpa+Vo6BKnRMuOEzy5zAZ3/H5tnQg1e80khMhK2xys0j6ZqzkgQC+fHMNZ7VDFNLqqNMj/o0eVeSBDh2POjkw== +"@remix-run/router@1.21.0": + version "1.21.0" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.21.0.tgz#c65ae4262bdcfe415dbd4f64ec87676e4a56e2b5" + integrity sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA== + "@rollup/pluginutils@^4.2.1": version "4.2.1" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d" @@ -3725,19 +3730,7 @@ hds-react@^3.8.0: uuid "^9.0.0" yup "^1.0.2" -history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - 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" - -hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -4110,11 +4103,6 @@ is-weakset@^2.0.1: call-bind "^1.0.2" get-intrinsic "^1.1.1" -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" @@ -4448,7 +4436,7 @@ lodash@^4.17.15, lodash@^4.17.21: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -4949,13 +4937,6 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -5184,7 +5165,7 @@ react-i18next@^13.5.0: "@babel/runtime" "^7.22.5" html-parse-stringify "^3.0.1" -react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.6: +react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.6: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -5217,33 +5198,20 @@ react-refresh@^0.14.2: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== -react-router-dom@^5.2.0: - version "5.3.4" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.4.tgz#2ed62ffd88cae6db134445f4a0c0ae8b91d2e5e6" - integrity sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ== +react-router-dom@^6.28.0: + version "6.28.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.28.0.tgz#f73ebb3490e59ac9f299377062ad1d10a9f579e6" + integrity sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg== dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.3.4" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react-router@5.3.4: - version "5.3.4" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.4.tgz#8ca252d70fcc37841e31473c7a151cf777887bb5" - integrity sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - 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" + "@remix-run/router" "1.21.0" + react-router "6.28.0" + +react-router@6.28.0: + version "6.28.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.28.0.tgz#29247c86d7ba901d7e5a13aa79a96723c3e59d0d" + integrity sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg== + dependencies: + "@remix-run/router" "1.21.0" react-test-renderer@^16.13.1: version "16.14.0" @@ -5390,11 +5358,6 @@ resolve-global@1.0.0, resolve-global@^1.0.0: dependencies: global-dirs "^0.1.1" -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - resolve@^1.10.0, resolve@^1.12.0, resolve@^1.22.4, resolve@^1.22.8: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" @@ -5960,16 +5923,6 @@ tiny-case@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== -tiny-invariant@^1.0.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" - integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== - -tiny-warning@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - tinybench@^2.5.1: version "2.8.0" resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.8.0.tgz#30e19ae3a27508ee18273ffed9ac7018949acd7b" @@ -6209,11 +6162,6 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - vite-node@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.0.tgz#2c7e61129bfecc759478fa592754fd9704aaba7f"