-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: use location.state to store background route to prevent unmount #4062
Changes from 7 commits
c269825
5c0e4a3
de2e7c5
406fdd1
b05ef6b
b9f772b
364a7cd
2d5b02b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { useEffect } from 'react'; | ||
import { useLocation, useNavigate } from 'react-router-dom'; | ||
|
||
import { RouteUrls } from '@shared/route-urls'; | ||
|
||
import { useLocationState } from '@app/common/hooks/use-location-state'; | ||
|
||
/* | ||
when modals are opened in a new tab they lose the location.state.backgroundLocation | ||
this hook sets the backgroundLocation to be RouteUrls.Home to improve UX | ||
*/ | ||
export function useBackgroundLocationRedirect() { | ||
const { pathname, state } = useLocation(); | ||
const navigate = useNavigate(); | ||
const backgroundLocation = useLocationState('backgroundLocation'); | ||
|
||
useEffect(() => { | ||
void (async () => { | ||
switch (true) { | ||
// FIXME ReceiveCollectibleOrdinal loses state?.btcAddressTaproot in a new tab | ||
// this can be improved to try and fetch btcAddressTaproot | ||
case pathname === RouteUrls.ReceiveCollectibleOrdinal && !state?.btcAddressTaproot: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For If you open a new tab this state is lost and although the modal opens, the For now I just send users back to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a big fan of using a This is better for readability imo. My thoughts map to the first comment of the HN post of a guy who wrote an article doing this (https://news.ycombinator.com/item?id=26777090) re favouring early return. Separately—while identical behaviour of modals when doing a fresh load of the app would be ideal—if we need to add a lot of logic to handle this, then I wouldn't consider it a dealbreaker if the under layer doesn't load correctly. Contextually, in case of sign out, it isn't so important. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like using If we are OK with having an empty screen behind all modals opened in a new tab then we can avoid the addition of this logic. It will look like this, with home tabs but no tab content: For |
||
return navigate(RouteUrls.Home); | ||
|
||
case backgroundLocation === undefined: | ||
return navigate(pathname, { | ||
state: { backgroundLocation: { pathname: RouteUrls.Home } }, | ||
}); | ||
default: | ||
return false; | ||
} | ||
})(); | ||
}, [backgroundLocation, navigate, pathname, state]); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ import { isUndefined } from '@shared/utils'; | |
|
||
pete-watters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
export function useLocationState(propName: string): string | undefined; | ||
export function useLocationState(propName: string, defaultValue: string): string; | ||
export function useLocationState(propName: 'accountIndex'): number; | ||
export function useLocationState(propName: 'backgroundLocation'): Location; | ||
Comment on lines
+10
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These changes mean Why not extend the function to support a generic type argument, rather than extending it with use-case specific typings? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can change this, no problem. I struggled with extending the type initially so opted for this to narrow the type to their key. I'll clean it up |
||
export function useLocationState(propName: string, defaultValue?: string) { | ||
const location = useLocation(); | ||
return get(location, `state.${propName}`, defaultValue); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,19 @@ | ||
import { Outlet, useNavigate } from 'react-router-dom'; | ||
import { Outlet, Route, Routes, useLocation, useNavigate } from 'react-router-dom'; | ||
|
||
import { RouteUrls } from '@shared/route-urls'; | ||
|
||
import { useTrackFirstDeposit } from '@app/common/hooks/analytics/transactions-analytics.hooks'; | ||
import { useOnboardingState } from '@app/common/hooks/auth/use-onboarding-state'; | ||
import { useLocationState } from '@app/common/hooks/use-location-state'; | ||
import { useOnMount } from '@app/common/hooks/use-on-mount'; | ||
import { useRouteHeader } from '@app/common/hooks/use-route-header'; | ||
import { Header } from '@app/components/header'; | ||
import { ActivityList } from '@app/features/activity-list/activity-list'; | ||
import { AssetsList } from '@app/features/asset-list/asset-list'; | ||
import { InAppMessages } from '@app/features/hiro-messages/in-app-messages'; | ||
import { SuggestedFirstSteps } from '@app/features/suggested-first-steps/suggested-first-steps'; | ||
import { HomeActions } from '@app/pages/home/components/home-actions'; | ||
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; | ||
import { homeModalRoutes } from '@app/routes/app-routes'; | ||
|
||
import { CurrentAccount } from './components/account-area'; | ||
import { HomeTabs } from './components/home-tabs'; | ||
|
@@ -19,8 +22,10 @@ import { HomeLayout } from './components/home.layout'; | |
export function Home() { | ||
const { decodedAuthRequest } = useOnboardingState(); | ||
|
||
const stacksAccount = useCurrentStacksAccount(); | ||
const navigate = useNavigate(); | ||
|
||
const location = useLocation(); | ||
const backgroundLocation = useLocationState('backgroundLocation'); | ||
useTrackFirstDeposit(); | ||
|
||
useRouteHeader( | ||
|
@@ -33,15 +38,21 @@ export function Home() { | |
useOnMount(() => { | ||
if (decodedAuthRequest) navigate(RouteUrls.ChooseAccount); | ||
}); | ||
|
||
return ( | ||
<HomeLayout | ||
suggestedFirstSteps={<SuggestedFirstSteps />} | ||
currentAccount={<CurrentAccount />} | ||
actions={<HomeActions />} | ||
> | ||
<HomeTabs> | ||
<Outlet context={{ address: stacksAccount?.address }} /> | ||
<> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I need to declare
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't it possible to also read location in app-routes to see if bg location is defined? Nw if not, just curious There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can read the location there but the issue I struggled with is how to then feed said location into how we are creating the routes. We are using Eventually I came up with the idea of using We can probably improve on that structure with more time and I am open to suggestions but I didn't want to start refactoring the whole of |
||
<Routes location={backgroundLocation || location}> | ||
<Route path={RouteUrls.Home} element={<AssetsList />} /> | ||
<Route path={RouteUrls.Activity} element={<ActivityList />} /> | ||
{homeModalRoutes} | ||
</Routes> | ||
{backgroundLocation && <Outlet />} | ||
</> | ||
</HomeTabs> | ||
</HomeLayout> | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this hook so that:
backgroundLocation
to be the home pageKapture.2023-07-28.at.14.28.19.mp4
Without doing this, an empty screen appears behind the modal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking on this further: couldn't each modal component handle their own
backgroundLocation
logic?Where the sign out modal component has a check in its render that, if there's no
backgroundLocation
, it should re-router to having a default value of home?Could work with a similar hook API, but where all the logic is colocated to the modal itself, rather than one big catch-all.
Something like:
which internally handles the
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we can definitely do that. I just implemented a catch all for now as
Home
seems like the logical background. I can change it to accept a preferred default routeI can give it a try but I think once you open a new tab the
location.state
gets wiped completely.