Skip to content
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

Closed
wants to merge 8 commits into from

Conversation

pete-watters
Copy link
Contributor

@pete-watters pete-watters commented Jul 26, 2023

Try out this version of the Hiro Wallet - download extension builds.

This PR makes a change to how we handle modals displayed over routes.

location.state is used to store the background route to prevent it being unmounted by feeding that to the router if available

@@ -47,7 +52,13 @@ function HomeContainer({ account }: HomeContainerProps) {
actions={<HomeActions />}
>
<HomeTabs>
<Outlet context={{ address: account.address }} />
<>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to declare Routes here so I can manipulate the location depending on whether backgroundLocation is populated or not.

backgroundLocation is the route above which the modal should appear.

Copy link
Collaborator

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 createHashRouter and createRoutesFromElements and I was unable to figure out how to pass the location there.

Eventually I came up with the idea of using <Routes nested in <Home so I could then trick the location.

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 app-routes

@pete-watters pete-watters force-pushed the fix/4028/send-inscription-routing-clean branch from 716b35a to ca60339 Compare July 26, 2023 13:54
@vercel vercel bot temporarily deployed to Preview July 26, 2023 13:54 Inactive
@pete-watters pete-watters force-pushed the fix/4028/send-inscription-routing-clean branch from ca60339 to 498742b Compare July 26, 2023 13:54
@vercel vercel bot temporarily deployed to Preview July 26, 2023 13:55 Inactive
@@ -186,8 +185,9 @@ function useAppRoutes() {
</AccountGate>
}
>
<Route index element={<BalancesList />} />
<Route path={RouteUrls.Activity} element={<ActivityList />} />
<Route path={RouteUrls.Activity} element={<ActivityList />}>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ActivityList is loaded in home.tsx but the route needs to be declared here also.

Similarly settingsModalRoutes needs to be passed in so you can use the settings modals from /activities

@@ -47,7 +52,13 @@ function HomeContainer({ account }: HomeContainerProps) {
actions={<HomeActions />}
>
<HomeTabs>
<Outlet context={{ address: account.address }} />
<>
Copy link
Collaborator

Choose a reason for hiding this comment

The 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

src/app/pages/receive-tokens/receive-modal.tsx Outdated Show resolved Hide resolved
@pete-watters pete-watters force-pushed the fix/4028/send-inscription-routing-clean branch from 498742b to a78237a Compare July 26, 2023 14:53
@vercel vercel bot temporarily deployed to Preview July 26, 2023 14:53 Inactive
@vercel vercel bot temporarily deployed to Preview July 26, 2023 15:20 Inactive
@vercel vercel bot temporarily deployed to Preview July 26, 2023 15:54 Inactive
@pete-watters pete-watters force-pushed the fix/4028/send-inscription-routing-clean branch from f31f274 to 5f39481 Compare July 27, 2023 08:11
@vercel vercel bot temporarily deployed to Preview July 27, 2023 08:11 Inactive
@pete-watters pete-watters force-pushed the fix/4028/send-inscription-routing-clean branch from 5f39481 to d0b9454 Compare July 27, 2023 08:30
@vercel vercel bot temporarily deployed to Preview July 27, 2023 08:34 Inactive
@pete-watters pete-watters force-pushed the fix/4028/send-inscription-routing-clean branch from d0b9454 to c269825 Compare July 27, 2023 08:42
@vercel vercel bot temporarily deployed to Preview July 27, 2023 08:42 Inactive
@vercel vercel bot temporarily deployed to Preview July 27, 2023 09:06 Inactive
@vercel vercel bot temporarily deployed to Preview July 27, 2023 13:16 Inactive
@vercel vercel bot temporarily deployed to Preview July 27, 2023 15:18 Inactive
@vercel vercel bot temporarily deployed to Preview July 28, 2023 08:34 Inactive
@vercel vercel bot temporarily deployed to Preview July 28, 2023 13:34 Inactive
@@ -0,0 +1,34 @@
import { useEffect } from 'react';
Copy link
Contributor Author

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:

  • If you have a modal open
  • Open a new tab
  • It will update the backgroundLocation to be the home page
Kapture.2023-07-28.at.14.28.19.mp4

Without doing this, an empty screen appears behind the modal

Copy link
Collaborator

@kyranjamie kyranjamie Jul 31, 2023

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:

// src/app/pages/sign-out-confirm/sign-out-confirm.tsx
useDefaultBackgroundLocation(RouteUrls.Home)

which internally handles the

if (!backgroundLocation) navigate(currentRoute, { 
  state: { 
    backgroundLocation: defaultVal, 
    // this might fix the problem you've commented in the other file re route state
    ...otherRouteState 
  } 
})`

Copy link
Contributor Author

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 route

I can give it a try but I think once you open a new tab the location.state gets wiped completely.

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:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For RouteUrls.ReceiveCollectibleOrdinal, it relies on btcAddressTaproot that is set in location.state.

If you open a new tab this state is lost and although the modal opens, the btcAddressTaproot is lost so it's unusable.

For now I just send users back to RouteUrls.Home. This could probably be improved by refactoring how we get btcAddressTaproot in ReceiveCollectibleOrdinal

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of using a switch(true). Why not just use ifs?

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like using switch(true) as I think its cleaner and more elegant than a lot of if statements. I can change it though and use early returns here and in future to match the code base.

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:

Screenshot 2023-07-31 at 11 16 23

For RouteUrls.ReceiveCollectibleOrdinal we will need to do something though as we lose track of the taproot address when opening in a new tab and the modal shows but is non-functional as there is no address to copy:
Screenshot 2023-07-31 at 11 21 10

@pete-watters pete-watters marked this pull request as ready for review July 28, 2023 14:43
@pete-watters
Copy link
Contributor Author

This PR is working and I tested it a lot but it would be good to give it a thorough look.

It still throws a warning in the console due to how I have had to use <Routes nested in home.tsx. It could be something easily fixed that I missed but I'm not sure.
Screenshot 2023-07-28 at 15 43 12

I did some more work refactoring app-routes to use <HashRouter instead of createHashRouter and createRoutesFromElements to try and improve this but I will exclude it from this PR. I'm not sure if we need React Router v6.4 Data APIs. If not this could be a cleaner solution if I can get it to work.

The stumbling block is that we need to use <Routes to be able to pass a dynamic location and to trick the router into thinking we are on the same location when showing a modal above it.

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:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of using a switch(true). Why not just use ifs?

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.

Comment on lines +10 to +11
export function useLocationState(propName: 'accountIndex'): number;
export function useLocationState(propName: 'backgroundLocation'): Location;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes mean useLocationState is now aware of implementation details of some of the cases in which it's used.

Why not extend the function to support a generic type argument, rather than extending it with use-case specific typings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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

@pete-watters pete-watters linked an issue Aug 2, 2023 that may be closed by this pull request
@vercel vercel bot temporarily deployed to Preview August 4, 2023 10:59 Inactive
@pete-watters
Copy link
Contributor Author

Closing this in favour of : #4099

@pete-watters pete-watters deleted the fix/4028/send-inscription-routing-clean branch February 7, 2024 09:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wallet always opens to Balances tab Fix state change behavior upon selecting "Send" for inscription
2 participants