Skip to content

Commit 65d55f4

Browse files
fix: Collection Details Page not going back correctly (#3168)
1 parent 2a7e16b commit 65d55f4

16 files changed

+149
-11
lines changed

src/components/CollectionDetailPage/CollectionDetailPage.container.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { getCollection, isOnSaleLoading, getLoading as getLoadingCollection, get
77
import { DELETE_COLLECTION_REQUEST, SET_COLLECTION_MINTERS_REQUEST } from 'modules/collection/actions'
88
import { openModal } from 'decentraland-dapps/dist/modules/modal/actions'
99
import { getCollectionItems } from 'modules/item/selectors'
10+
import { getLastLocation } from 'modules/ui/location/selector'
1011
import { fetchCollectionForumPostReplyRequest, FETCH_COLLECTION_FORUM_POST_REPLY_REQUEST } from 'modules/forum/actions'
1112
import { MapStateProps, MapDispatchProps, MapDispatch } from './CollectionDetailPage.types'
1213
import CollectionDetailPage from './CollectionDetailPage'
@@ -24,7 +25,8 @@ const mapState = (state: RootState): MapStateProps => {
2425
status: statusByCollectionId[collectionId],
2526
isLoading:
2627
isLoadingType(getLoadingCollection(state), DELETE_COLLECTION_REQUEST) ||
27-
isLoadingType(getLoadingCollection(state), FETCH_COLLECTION_FORUM_POST_REPLY_REQUEST)
28+
isLoadingType(getLoadingCollection(state), FETCH_COLLECTION_FORUM_POST_REPLY_REQUEST),
29+
lastLocation: getLastLocation(state)
2830
}
2931
}
3032

src/components/CollectionDetailPage/CollectionDetailPage.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default function CollectionDetailPage({
3737
wallet,
3838
items,
3939
isOnSaleLoading,
40+
lastLocation,
4041
status,
4142
onOpenModal,
4243
isLoading,
@@ -50,6 +51,7 @@ export default function CollectionDetailPage({
5051

5152
const [tab, setTab] = useState<ItemType>(initialTab || ItemType.WEARABLE)
5253
const history = useHistory()
54+
const isComingFromTheCollectionsPage = lastLocation === locations.collections()
5355

5456
const fetchCollectionForumPostReply = useCallback(() => {
5557
// Only fetch the forum post replies if the collection has a forum link and there's no other fetch process in progress
@@ -85,8 +87,12 @@ export default function CollectionDetailPage({
8587
}, [collection, wallet, onOpenModal])
8688

8789
const handleGoBack = useCallback(() => {
88-
history.push(locations.collections())
89-
}, [history])
90+
if (isComingFromTheCollectionsPage) {
91+
history.goBack()
92+
} else {
93+
history.push(locations.collections())
94+
}
95+
}, [history, isComingFromTheCollectionsPage])
9096

9197
const handleNavigateToEditor = useCallback(() => {
9298
if (collection) {

src/components/CollectionDetailPage/CollectionDetailPage.types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type Props = {
1212
isLoading: boolean
1313
items: Item[]
1414
status: SyncStatus
15+
lastLocation?: string
1516
onOpenModal: typeof openModal
1617
onFetchCollectionForumPostReply: typeof fetchCollectionForumPostReplyRequest
1718
}
@@ -20,6 +21,6 @@ export type State = {
2021
tab: ItemType
2122
}
2223

23-
export type MapStateProps = Pick<Props, 'wallet' | 'collection' | 'isOnSaleLoading' | 'isLoading' | 'items' | 'status'>
24+
export type MapStateProps = Pick<Props, 'wallet' | 'collection' | 'isOnSaleLoading' | 'isLoading' | 'items' | 'status' | 'lastLocation'>
2425
export type MapDispatchProps = Pick<Props, 'onOpenModal' | 'onFetchCollectionForumPostReply'>
2526
export type MapDispatch = Dispatch<OpenModalAction | FetchCollectionForumPostReplyRequestAction>

src/components/ThirdPartyCollectionDetailPage/ThirdPartyCollectionDetailPage.container.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { getCollectionThirdParty, isFetchingAvailableSlots } from 'modules/third
1414
import { fetchThirdPartyAvailableSlotsRequest } from 'modules/thirdParty/actions'
1515
import { isThirdPartyCollection } from 'modules/collection/utils'
1616
import { getIsLinkedWearablesV2Enabled } from 'modules/features/selectors'
17+
import { getLastLocation } from 'modules/ui/location/selector'
1718
import { MapStateProps, MapDispatchProps, MapDispatch } from './ThirdPartyCollectionDetailPage.types'
1819
import CollectionDetailPage from './ThirdPartyCollectionDetailPage'
1920

@@ -38,7 +39,8 @@ const mapState = (state: RootState): MapStateProps => {
3839
isLoadingType(getLoadingCollection(state), FETCH_COLLECTIONS_REQUEST) ||
3940
isLoadingType(getLoadingCollection(state), DELETE_COLLECTION_REQUEST) ||
4041
isLoadingType(getLoadingItem(state), FETCH_COLLECTION_ITEMS_REQUEST),
41-
isLoadingAvailableSlots: isFetchingAvailableSlots(state)
42+
isLoadingAvailableSlots: isFetchingAvailableSlots(state),
43+
lastLocation: getLastLocation(state)
4244
}
4345
}
4446

src/components/ThirdPartyCollectionDetailPage/ThirdPartyCollectionDetailPage.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ enum ItemStatus {
5656

5757
export default function ThirdPartyCollectionDetailPage({
5858
currentPage,
59+
lastLocation,
5960
wallet,
6061
thirdParty,
6162
items,
@@ -73,6 +74,7 @@ export default function ThirdPartyCollectionDetailPage({
7374
const [shouldFetchAllPages, setShouldFetchAllPages] = useState(false)
7475
const [itemStatus, setItemStatus] = useState<ItemStatus>(ItemStatus.ALL)
7576
const history = useHistory()
77+
const isComingFromTheCollectionsPage = lastLocation === locations.collections()
7678

7779
useEffect(() => {
7880
if (thirdParty && thirdParty.availableSlots === undefined && !isLoadingAvailableSlots) {
@@ -108,8 +110,12 @@ export default function ThirdPartyCollectionDetailPage({
108110
}, [collection, onOpenModal])
109111

110112
const handleGoBack = useCallback(() => {
111-
history.push(locations.collections())
112-
}, [history])
113+
if (isComingFromTheCollectionsPage) {
114+
history.goBack()
115+
} else {
116+
history.push(locations.collections())
117+
}
118+
}, [history, isComingFromTheCollectionsPage])
113119

114120
const handlePageChange = useCallback(
115121
(_event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps) => {

src/components/ThirdPartyCollectionDetailPage/ThirdPartyCollectionDetailPage.types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type Props = {
2525
itemCurations: ItemCuration[]
2626
isOnSaleLoading: boolean
2727
authorizations: Authorization[]
28+
lastLocation?: string
2829
isLoading: boolean
2930
isLoadingAvailableSlots: boolean
3031
isThirdPartyV2Enabled: boolean
@@ -54,6 +55,7 @@ export type MapStateProps = Pick<
5455
| 'items'
5556
| 'isThirdPartyV2Enabled'
5657
| 'paginatedData'
58+
| 'lastLocation'
5759
>
5860
export type MapDispatchProps = Pick<Props, 'onOpenModal' | 'onFetchAvailableSlots'>
5961
export type MapDispatch = Dispatch<

src/modules/ui/location/action.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { action } from 'typesafe-actions'
2+
3+
export const SAVE_LAST_LOCATION = 'Save last location'
4+
export const saveLastLocation = (location: string) => action(SAVE_LAST_LOCATION, { location })
5+
export type SaveLastLocationAction = ReturnType<typeof saveLastLocation>
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { saveLastLocation } from './action'
2+
import { locationReducer, LocationState } from './reducer'
3+
4+
let state: LocationState
5+
6+
describe('when reducing the save last location action', () => {
7+
beforeEach(() => {
8+
state = {
9+
lastLocation: undefined
10+
}
11+
})
12+
13+
it('should set the last location', () => {
14+
expect(locationReducer(state, saveLastLocation('/some-location'))).toEqual({
15+
lastLocation: '/some-location'
16+
})
17+
})
18+
})

src/modules/ui/location/reducer.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { SAVE_LAST_LOCATION, SaveLastLocationAction } from './action'
2+
3+
export type LocationState = {
4+
lastLocation?: string
5+
}
6+
7+
export const INITIAL_STATE: LocationState = {
8+
lastLocation: undefined
9+
}
10+
11+
export function locationReducer(state = INITIAL_STATE, action: SaveLastLocationAction) {
12+
switch (action.type) {
13+
case SAVE_LAST_LOCATION: {
14+
return {
15+
...state,
16+
lastLocation: action.payload.location
17+
}
18+
}
19+
default:
20+
return state
21+
}
22+
}
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { RootState } from 'modules/common/types'
2+
import { getLastLocation } from './selector'
3+
4+
let state: RootState
5+
6+
beforeEach(() => {
7+
state = {
8+
ui: {
9+
location: {
10+
lastLocation: undefined
11+
}
12+
}
13+
} as RootState
14+
})
15+
16+
describe('when getting the last location', () => {
17+
describe('and the last location is not set', () => {
18+
beforeEach(() => {
19+
state.ui.location.lastLocation = undefined
20+
})
21+
22+
it('should return undefined', () => {
23+
expect(getLastLocation(state)).toBeUndefined()
24+
})
25+
})
26+
27+
describe('and the last location is set', () => {
28+
beforeEach(() => {
29+
state.ui.location.lastLocation = '/some-location'
30+
})
31+
32+
it('should return the last location', () => {
33+
expect(getLastLocation(state)).toEqual('/some-location')
34+
})
35+
})
36+
})

src/modules/ui/location/selector.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { RootState } from 'modules/common/types'
2+
3+
export const getLastLocation = (state: RootState) => state.ui.location.lastLocation

src/modules/ui/reducer.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { landReducer as land, LandState } from './land/reducer'
66
import { CreateMultipleItemsState, createMultipleItemsReducer as createMultipleItems } from './createMultipleItems/reducer'
77
import { ThirdPartyReducer as thirdParty } from './thirdparty/reducer'
88
import { ThirdPartyState } from './thirdparty/reducer'
9+
import { LocationState, locationReducer as location } from './location/reducer'
910

1011
export type UIState = {
1112
sidebar: SidebarState
@@ -14,6 +15,7 @@ export type UIState = {
1415
land: LandState
1516
createMultipleItems: CreateMultipleItemsState
1617
thirdParty: ThirdPartyState
18+
location: LocationState
1719
}
1820

1921
export const uiReducer = combineReducers({
@@ -22,5 +24,6 @@ export const uiReducer = combineReducers({
2224
collection,
2325
land,
2426
createMultipleItems,
25-
thirdParty
27+
thirdParty,
28+
location
2629
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { connect } from 'react-redux'
2+
import { saveLastLocation } from 'modules/ui/location/action'
3+
import { AppRoutes } from './AppRoutes'
4+
import { MapDispatch, MapDispatchProps } from './AppRoutes.types'
5+
6+
const mapDispatch = (dispatch: MapDispatch): MapDispatchProps => ({
7+
saveLastLocation: (location: string) => dispatch(saveLastLocation(location))
8+
})
9+
10+
export default connect(undefined, mapDispatch)(AppRoutes)

src/routing/AppRoutes.tsx src/routing/AppRoutes/AppRoutes.tsx

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import React from 'react'
2-
import { Switch, Route, Redirect } from 'react-router-dom'
1+
import React, { useEffect, useState } from 'react'
2+
import { Switch, Route, Redirect, useLocation } from 'react-router-dom'
33
import { Loader, Responsive } from 'decentraland-ui'
44
import { usePageTracking } from 'decentraland-dapps/dist/hooks/usePageTracking'
55

66
import { locations } from 'routing/locations'
77
import LoadingPage from 'components/LoadingPage'
88
import MobilePage from 'components/MobilePage'
99
import { ProtectedRoute } from 'modules/ProtectedRoute'
10+
import { Props } from './AppRoutes.types'
1011

1112
const ScenesPage = React.lazy(() => import('components/ScenesPage'))
1213
const HomePage = React.lazy(() => import('components/HomePage'))
@@ -39,7 +40,17 @@ const CurationPage = React.lazy(() => import('components/CurationPage'))
3940
const TemplatesPage = React.lazy(() => import('components/TemplatesPage'))
4041
const TemplateDetailPage = React.lazy(() => import('components/TemplateDetailPage'))
4142

42-
export function AppRoutes() {
43+
export function AppRoutes({ saveLastLocation }: Props) {
44+
// Save the last location
45+
const location = useLocation()
46+
const [currentRoute, setCurrentRoute] = useState(location.pathname)
47+
useEffect(() => {
48+
if (currentRoute !== location.pathname) {
49+
saveLastLocation(currentRoute)
50+
setCurrentRoute(location.pathname)
51+
}
52+
}, [location.pathname, currentRoute])
53+
4354
usePageTracking()
4455
return (
4556
<React.Suspense fallback={<Loader size="huge" active />}>
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Dispatch } from 'react'
2+
import { SaveLastLocationAction } from 'modules/ui/location/action'
3+
4+
export type Props = {
5+
saveLastLocation: (location: string) => void
6+
}
7+
8+
export type MapDispatchProps = Pick<Props, 'saveLastLocation'>
9+
export type MapDispatch = Dispatch<SaveLastLocationAction>

src/routing/AppRoutes/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import AppRoutes from './AppRoutes.container'
2+
export { AppRoutes }

0 commit comments

Comments
 (0)