Skip to content

Commit d485b77

Browse files
authored
Merge pull request #2572 from Amsterdam/feature/react-router-featurebranch
[feat-5189]: react router featurebranch
2 parents f49027e + 72f129b commit d485b77

File tree

87 files changed

+1271
-1357
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+1271
-1357
lines changed

package-lock.json

+258-363
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@
4747
"@hookform/resolvers": "^2.9.10",
4848
"@microsoft/applicationinsights-web": "^2.8.9",
4949
"@sentry/browser": "^6.19.7",
50+
"@types/react-router-dom": "^5.3.3",
5051
"@types/scroll-lock": "^2.1.0",
5152
"classnames": "^2.3.2",
5253
"date-fns": "^2.29.3",
53-
"history": "^4.10.1",
54+
"history": "^5.2.0",
5455
"hoist-non-react-statics": "^3.3.2",
5556
"immutable": "^4.0.0-rc.12",
5657
"invariant": "^2.2.4",
@@ -65,11 +66,11 @@
6566
"react-helmet": "^6.1.0",
6667
"react-hook-form": "^7.26.0",
6768
"react-markdown": "^6.0.3",
68-
"react-redux": "^7.2.9",
69+
"react-redux": "^7.2.6",
6970
"react-responsive": "^9.0.2",
70-
"react-router-dom": "^5.3.4",
71+
"react-router-dom": "6.2.1",
7172
"redux": "^4.1.2",
72-
"redux-first-history": "^5.1.1",
73+
"redux-first-history": "5.0.8",
7374
"redux-immutable": "4.0.0",
7475
"redux-saga": "^1.2.2",
7576
"reselect": "^4.1.7",
@@ -108,7 +109,6 @@
108109
"@types/react-dom": "^17.0.18",
109110
"@types/react-helmet": "^6.1.6",
110111
"@types/react-redux": "^7.1.16",
111-
"@types/react-router-dom": "^5.3.3",
112112
"@types/styled-components": "^5.1.26",
113113
"@types/webpack": "^5.28.0",
114114
"@types/webpack-env": "^1.18.0",

src/app.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ApplicationInsights } from '@microsoft/applicationinsights-web'
44
import * as Sentry from '@sentry/browser'
55
import ReactDOM from 'react-dom'
66
import { Provider } from 'react-redux'
7-
import { Router } from 'react-router-dom'
7+
import { HistoryRouter as Router } from 'redux-first-history/rr6'
88

99
import App from 'containers/App'
1010
import { authenticateUser } from 'containers/App/actions'

src/components/FrontPageAlert/FrontPageAlert.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
// SPDX-License-Identifier: MPL-2.0
22
// Copyright (C) 2023 Gemeente Amsterdam
3-
import { useHistory } from 'react-router-dom'
3+
import { useLocation } from 'react-router-dom'
44

55
import configuration from 'shared/services/configuration/configuration'
66

77
import { StyledAlert, StyledMarkdown } from './styled'
88

99
export const FrontPageAlert = () => {
10-
const history = useHistory()
10+
const location = useLocation()
1111
const alertText = configuration.frontPageAlert.text
1212

13-
if (!(history.location.pathname === '/incident/beschrijf') || !alertText)
14-
return null
13+
if (!(location.pathname === '/incident/beschrijf') || !alertText) return null
1514

1615
return (
1716
<StyledAlert level="error" outline>

src/components/Notification/index.tsx

+9-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// SPDX-License-Identifier: MPL-2.0
2-
// Copyright (C) 2019 - 2022 Gemeente Amsterdam
2+
// Copyright (C) 2019 - 2023 Gemeente Amsterdam
33
import type { FunctionComponent } from 'react'
44
import { useEffect, useState, useCallback, useRef } from 'react'
55

66
import { Close } from '@amsterdam/asc-assets'
77
import { Column, Row } from '@amsterdam/asc-ui'
8-
import { useHistory } from 'react-router-dom'
8+
import { useLocation } from 'react-router-dom'
99

1010
import {
1111
ONCLOSE_TIMEOUT,
@@ -51,30 +51,29 @@ const Notification: FunctionComponent<NotificationProps> = ({
5151
const [shouldHide, setShouldHide] = useState(false)
5252
const isFrontOffice = useIsFrontOffice()
5353
const tall = isFrontOffice && !getIsAuthenticated()
54-
const history = useHistory()
54+
const location = useLocation()
5555

5656
// persisting timeout IDs across renders
5757
const onCloseTimeoutRef = useRef<number>()
5858
const slideUpTimeoutRef = useRef<number>()
5959

6060
/**
61-
* Subscribe to history changes
6261
* Will reset the notification whenever a navigation action occurs and only when the type of the
6362
* notifcation is TYPE_LOCAL
6463
*/
64+
const didMount = useRef(false)
65+
6566
useEffect(() => {
6667
if (type !== TYPE_LOCAL || typeof onClose !== 'function') {
6768
return undefined
6869
}
6970

70-
const unlisten = history.listen(() => {
71+
if (didMount.current) {
7172
onClose()
72-
})
73-
74-
return () => {
75-
unlisten()
7673
}
77-
}, [history, type, title, onClose])
74+
75+
didMount.current = true
76+
}, [onClose, type, location])
7877

7978
useEffect(() => {
8079
if (
@@ -99,7 +98,6 @@ const Notification: FunctionComponent<NotificationProps> = ({
9998

10099
const onCloseTimeoutId = window.setTimeout(() => {
101100
window.clearTimeout(onCloseTimeoutRef.current)
102-
103101
onClose()
104102
}, ONCLOSE_TIMEOUT + SLIDEUP_TIMEOUT)
105103

src/components/OverviewMap/DetailPanel/DetailPanel.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MPL-2.0
2-
// Copyright (C) 2020 - 2021 Gemeente Amsterdam
2+
// Copyright (C) 2020 - 2023 Gemeente Amsterdam
33
import type { FunctionComponent } from 'react'
44

55
import { Close } from '@amsterdam/asc-assets'
@@ -85,7 +85,7 @@ const DetailPanel: FunctionComponent<DetailPanelProps> = ({
8585
<AscLink
8686
as={Link}
8787
variant="inline"
88-
to={`${INCIDENT_URL}/${incident.id}`}
88+
to={`../${INCIDENT_URL}/${incident.id}`}
8989
>
9090
Melding {incident.id}
9191
</AscLink>

src/components/ProtectedRoute/ProtectedRoute.tsx

+7-16
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import { useMemo } from 'react'
44
import type { FunctionComponent } from 'react'
55

66
import { useSelector } from 'react-redux'
7-
import type { RouteComponentProps, RouteProps } from 'react-router-dom'
8-
import { Route } from 'react-router-dom'
7+
import type { RouteProps } from 'react-router-dom'
98

109
import NotFoundPage from 'components/pages/NotFoundPage'
1110
import {
@@ -16,10 +15,10 @@ import {
1615
export const NO_PAGE_ACCESS_MESSAGE = 'U heeft geen toegang tot deze pagina'
1716
export const NO_PAGE_FOUND_MESSAGE = 'We hebben de pagina niet gevonden'
1817

19-
interface ProtectedRouteProps extends RouteProps {
18+
type ProtectedRouteProps = RouteProps & {
2019
role?: string
2120
roleGroup?: string
22-
component: (props: RouteComponentProps<any>) => JSX.Element | null
21+
component: (props: any) => JSX.Element | null
2322
}
2423

2524
const ProtectedRoute: FunctionComponent<ProtectedRouteProps> = ({
@@ -34,20 +33,12 @@ const ProtectedRoute: FunctionComponent<ProtectedRouteProps> = ({
3433
() => (role && userCan(role)) || (roleGroup && userCanAccess(roleGroup)),
3534
[role, roleGroup, userCan, userCanAccess]
3635
)
37-
3836
if (!Component) return <NotFoundPage message={NO_PAGE_FOUND_MESSAGE} />
3937

40-
return (
41-
<Route
42-
{...rest}
43-
render={(props) =>
44-
hasAccess ? (
45-
<Component {...props} />
46-
) : (
47-
<NotFoundPage message={NO_PAGE_ACCESS_MESSAGE} />
48-
)
49-
}
50-
/>
38+
return hasAccess ? (
39+
<Component {...rest} />
40+
) : (
41+
<NotFoundPage message={NO_PAGE_ACCESS_MESSAGE} />
5142
)
5243
}
5344

src/components/ProtectedRoute/__tests__/ProtectedRoute.test.tsx

+4-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// SPDX-License-Identifier: MPL-2.0
22
// Copyright (C) 2021-2022 Gemeente Amsterdam
33
import { render, act, screen } from '@testing-library/react'
4-
import type { RouteComponentProps } from 'react-router-dom'
54

65
import * as appSelectors from 'containers/App/selectors' // { makeSelectUserCanAccess, makeSelectUserCan }
76
import { withAppContext, history } from 'test/utils'
@@ -20,11 +19,11 @@ describe('ProtectedRoute component', () => {
2019

2120
it('should render not found message when component does not exist', () => {
2221
const MockComponentUndefined = undefined as unknown as (
23-
props: RouteComponentProps<any>
22+
props: any
2423
) => JSX.Element
2524
render(
2625
withAppContext(
27-
<ProtectedRoute exact path="/test" component={MockComponentUndefined} />
26+
<ProtectedRoute path="/test" component={MockComponentUndefined} />
2827
)
2928
)
3029

@@ -39,9 +38,7 @@ describe('ProtectedRoute component', () => {
3938

4039
it("should NOT render the component when doesn't have access", () => {
4140
render(
42-
withAppContext(
43-
<ProtectedRoute exact path="/test" component={TestComponent} />
44-
)
41+
withAppContext(<ProtectedRoute path="/test" component={TestComponent} />)
4542
)
4643

4744
act(() => {
@@ -59,12 +56,7 @@ describe('ProtectedRoute component', () => {
5956
.mockImplementation(() => () => true)
6057
render(
6158
withAppContext(
62-
<ProtectedRoute
63-
exact
64-
path="/test"
65-
component={TestComponent}
66-
role="role"
67-
/>
59+
<ProtectedRoute path="/test" component={TestComponent} role="role" />
6860
)
6961
)
7062

@@ -84,7 +76,6 @@ describe('ProtectedRoute component', () => {
8476
render(
8577
withAppContext(
8678
<ProtectedRoute
87-
exact
8879
path="/test"
8980
component={TestComponent}
9081
roleGroup="roleGroup"

src/components/Summary/Summary.test.tsx

+8-19
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// SPDX-License-Identifier: MPL-2.0
22
// Copyright (C) 2020 - 2022 Gemeente Amsterdam
3-
import { render, screen } from '@testing-library/react'
3+
import { render, screen, waitFor } from '@testing-library/react'
44
import userEvent from '@testing-library/user-event'
55
import * as reactRedux from 'react-redux'
6-
import * as reactRouterDom from 'react-router-dom'
76

87
import configuration from 'shared/services/configuration/configuration'
98
import { formatAddress } from 'shared/services/format-address'
@@ -12,6 +11,7 @@ import { AssetSelectProvider } from 'signals/incident/components/form/MapSelecto
1211
import type { SummaryProps } from 'signals/incident/components/form/MapSelectors/Asset/types'
1312
import type { Item } from 'signals/incident/components/form/MapSelectors/types'
1413
import { showMap } from 'signals/incident/containers/IncidentContainer/actions'
14+
import { history } from 'test/utils'
1515
import { withAppContext } from 'test/utils'
1616
import type { Address } from 'types/address'
1717

@@ -58,22 +58,12 @@ export const summaryProps: SummaryProps = {
5858
coordinates: { lat: 0, lng: 0 },
5959
}
6060

61-
let mockLocation = {
62-
pathname: '/incident/vulaan',
63-
referrer: '/',
64-
search: '',
65-
state: {},
66-
hash: '',
67-
}
68-
6961
export const withContext = (
7062
Component: JSX.Element,
7163
context = assetSelectContextValue
7264
) =>
7365
withAppContext(
74-
<reactRouterDom.MemoryRouter initialEntries={[mockLocation]}>
75-
<AssetSelectProvider value={context}>{Component}</AssetSelectProvider>
76-
</reactRouterDom.MemoryRouter>
66+
<AssetSelectProvider value={context}>{Component}</AssetSelectProvider>
7767
)
7868

7969
const dispatch = jest.fn()
@@ -204,14 +194,13 @@ describe('signals/incident/components/form/AssetSelect/Summary', () => {
204194
expect(screen.getByTestId('map-edit-button')).toBeInTheDocument()
205195
})
206196

207-
it("does not render the mapEditButton at 'incident/summary'", () => {
208-
mockLocation = {
209-
...mockLocation,
210-
pathname: '/incident/summary',
211-
}
197+
it("does not render the mapEditButton at 'incident/summary'", async () => {
198+
history.push('/incident/summary')
212199

213200
render(withContext(<Summary {...summaryProps} />))
214201

215-
expect(screen.queryByTestId('map-edit-button')).not.toBeInTheDocument()
202+
await waitFor(() => {
203+
expect(screen.queryByTestId('map-edit-button')).not.toBeInTheDocument()
204+
})
216205
})
217206
})

src/configureStore.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export default function configureStore(initialState: Record<string, any>) {
7272
/* istanbul ignore next */
7373
if (module.hot) {
7474
module.hot.accept('./reducers', () => {
75-
store.replaceReducer(createReducer({ ...store.injectedReducers }))
75+
store.replaceReducer(createReducer(store.injectedReducers))
7676
})
7777
}
7878

src/containers/App/index.test.tsx

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// SPDX-License-Identifier: MPL-2.0
2-
// Copyright (C) 2019 - 2022 Gemeente Amsterdam
2+
// Copyright (C) 2019 - 2023 Gemeente Amsterdam
33
import { render, screen, act } from '@testing-library/react'
4-
import type { UnregisterCallback, History } from 'history'
54
import * as reactRedux from 'react-redux'
65

76
import { fetchCategories as fetchCategoriesAction } from 'models/categories/actions'
@@ -30,10 +29,7 @@ jest.mock('shared/services/auth/auth', () => ({
3029
jest.useFakeTimers()
3130

3231
describe('<App />', () => {
33-
let listenSpy: jest.SpyInstance<
34-
UnregisterCallback,
35-
[listener: History.LocationListener<unknown>]
36-
>
32+
let listenSpy: jest.SpyInstance
3733
let spyScrollTo: jest.Mock
3834
let props: JSX.IntrinsicAttributes & { resetIncidentAction: jest.Mock }
3935

@@ -60,13 +56,13 @@ describe('<App />', () => {
6056
it('should scroll to top on history change', () => {
6157
render(withAppContext(<App />))
6258

63-
expect(spyScrollTo).not.toHaveBeenCalled()
59+
expect(spyScrollTo).toHaveBeenCalledWith(0, 0)
6460

6561
act(() => {
6662
history.push('/somewhere/else')
6763
})
6864

69-
expect(spyScrollTo).toHaveBeenCalledWith(0, 0)
65+
expect(spyScrollTo).toHaveBeenCalledTimes(2)
7066
})
7167

7268
it('should reset incident on page unload', () => {

0 commit comments

Comments
 (0)