Skip to content

Commit

Permalink
fix: refactor routes to prevent unmount using modals and overlay, closes
Browse files Browse the repository at this point in the history
  • Loading branch information
pete-watters committed Aug 4, 2023
1 parent 281e138 commit d7591ed
Show file tree
Hide file tree
Showing 21 changed files with 390 additions and 255 deletions.
34 changes: 34 additions & 0 deletions src/app/common/hooks/use-background-location-redirect.ts
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:
// return navigate(RouteUrls.Home);

case backgroundLocation === undefined:
return navigate(pathname, {
state: { backgroundLocation: { pathname: RouteUrls.Home } },
});
default:
return false;
}
})();
}, [backgroundLocation, navigate, pathname, state]);
}
2 changes: 2 additions & 0 deletions src/app/common/hooks/use-location-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { isUndefined } from '@shared/utils';

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;
export function useLocationState(propName: string, defaultValue?: string) {
const location = useLocation();
return get(location, `state.${propName}`, defaultValue);
Expand Down
18 changes: 13 additions & 5 deletions src/app/components/receive/receive-collectible.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import toast from 'react-hot-toast';
import { useLocation, useNavigate } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';

import BitcoinStampImg from '@assets/images/bitcoin-stamp.png';
import { Box, Stack, useClipboard } from '@stacks/ui';
import { HomePageSelectors } from '@tests/selectors/home.selectors';
import get from 'lodash.get';

import { RouteUrls } from '@shared/route-urls';

import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { useLocationState } from '@app/common/hooks/use-location-state';
import { StxAvatar } from '@app/components/crypto-assets/stacks/components/stx-avatar';
import { OrdinalIcon } from '@app/components/icons/ordinal-icon';
import { useZeroIndexTaprootAddress } from '@app/query/bitcoin/ordinals/use-zero-index-taproot-address';
Expand All @@ -19,9 +19,9 @@ import { ReceiveCollectibleItem } from './receive-collectible-item';

export function ReceiveCollectible() {
const analytics = useAnalytics();
const location = useLocation();
const backgroundLocation = useLocationState('backgroundLocation');
const accountIndex = useLocationState('accountIndex');
const navigate = useNavigate();
const accountIndex = get(location.state, 'accountIndex', undefined);
const btcAddressNativeSegwit = useCurrentAccountNativeSegwitAddressIndexZero();
const btcAddressTaproot = useZeroIndexTaprootAddress(accountIndex);

Expand Down Expand Up @@ -54,7 +54,15 @@ export function ReceiveCollectible() {
data-testid={HomePageSelectors.ReceiveBtcTaprootQrCodeBtn}
onCopyAddress={() => {
void analytics.track('select_inscription_to_add_new_collectible');
navigate(RouteUrls.ReceiveCollectibleOrdinal, { state: { btcAddressTaproot } });
// TODO improve and refactor
// using absolute path here so it opens from Add new OR inside Receive modal
// FIXME - BUG - not seeing taproot when open in new tab
navigate(`/${RouteUrls.Receive}/${RouteUrls.ReceiveCollectibleOrdinal}`, {
state: {
btcAddressTaproot,
backgroundLocation: backgroundLocation,
},
});
}}
title="Ordinal inscription"
/>
Expand Down
3 changes: 1 addition & 2 deletions src/app/features/asset-list/asset-list.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Outlet } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { Outlet, useNavigate } from 'react-router-dom';

import { Box, Stack } from '@stacks/ui';
import { HomePageSelectorsLegacy } from '@tests-legacy/page-objects/home.selectors';
Expand Down
9 changes: 7 additions & 2 deletions src/app/features/collectibles/components/add-collectible.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useNavigate } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router-dom';

import { Box } from '@stacks/ui';

Expand All @@ -25,13 +25,18 @@ const backgroundProps = {
export function AddCollectible() {
const navigate = useNavigate();
const analytics = useAnalytics();
const location = useLocation();

return (
<CollectibleItemLayout
backgroundElementProps={backgroundProps}
onClickLayout={() => {
void analytics.track('select_add_new_collectible');
navigate(RouteUrls.ReceiveCollectible);
navigate(`${RouteUrls.Receive}/${RouteUrls.ReceiveCollectible}`, {
state: {
backgroundLocation: location,
},
});
}}
subtitle="Collectible"
title="Add new"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useNavigate } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router-dom';

import { Inscription as InscriptionType } from '@shared/models/inscription.model';
import { RouteUrls } from '@shared/route-urls';
Expand All @@ -18,10 +18,11 @@ interface InscriptionProps {
export function Inscription({ rawInscription }: InscriptionProps) {
const inscription = convertInscriptionToSupportedInscriptionType(rawInscription);
const navigate = useNavigate();
const location = useLocation();

function openSendInscriptionModal() {
navigate(RouteUrls.SendOrdinalInscription, {
state: { inscription },
state: { inscription, backgroundLocation: location },
});
}

Expand Down
15 changes: 11 additions & 4 deletions src/app/features/settings-dropdown/settings-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export function SettingsDropdown() {

useOnClickOutside(ref, isShowing ? handleClose : null);

console.info('settings, location', location);

return (
<>
{hasCreatedAccount && <Overlay />}
Expand Down Expand Up @@ -95,7 +97,9 @@ export function SettingsDropdown() {
data-testid={SettingsSelectors.ToggleTheme}
onClick={wrappedCloseCallback(() => {
void analytics.track('click_change_theme_menu_item');
navigate(RouteUrls.ChangeTheme, { relative: 'path' });
navigate(RouteUrls.ChangeTheme, {
state: { backgroundLocation: location },
});
})}
>
Change theme
Expand Down Expand Up @@ -147,15 +151,16 @@ export function SettingsDropdown() {
data-testid={SettingsSelectors.ChangeNetworkAction}
onClick={wrappedCloseCallback(() => {
void analytics.track('click_change_network_menu_item');
navigate(RouteUrls.SelectNetwork, { relative: 'path' });
navigate(RouteUrls.SelectNetwork, {
state: { backgroundLocation: location },
});
})}
>
<Flex width="100%" alignItems="center" justifyContent="space-between">
<Box>Change network</Box>
<Caption data-testid={SettingsSelectors.CurrentNetwork}>{currentNetworkId}</Caption>
</Flex>
</MenuItem>

<Divider />
{showAdvancedMenuOptions && (
<AdvancedMenuItems
Expand All @@ -178,7 +183,9 @@ export function SettingsDropdown() {
<MenuItem
color={color('feedback-error')}
onClick={wrappedCloseCallback(() =>
navigate(RouteUrls.SignOutConfirm, { relative: 'path' })
navigate(RouteUrls.SignOutConfirm, {
state: { backgroundLocation: location },
})
)}
data-testid="settings-sign-out"
>
Expand Down
6 changes: 5 additions & 1 deletion src/app/features/theme-drawer/theme-drawer.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { useNavigate } from 'react-router-dom';

import { useBackgroundLocationRedirect } from '@app/common/hooks/use-background-location-redirect';
import { useLocationState } from '@app/common/hooks/use-location-state';
import { BaseDrawer } from '@app/components/drawer/base-drawer';

import { ThemeList } from './theme-list';

export function ThemesDrawer() {
useBackgroundLocationRedirect();
const navigate = useNavigate();
const backgroundLocation = useLocationState('backgroundLocation');
return (
<BaseDrawer title="Select Theme" isShowing onClose={() => navigate('..')}>
<BaseDrawer title="Select Theme" isShowing onClose={() => navigate(backgroundLocation)}>
<ThemeList />
</BaseDrawer>
);
Expand Down
16 changes: 8 additions & 8 deletions src/app/pages/home/components/home-tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { StackProps } from '@stacks/ui';

import { RouteUrls } from '@shared/route-urls';

import { useLocationState } from '@app/common/hooks/use-location-state';
import { LoadingSpinner } from '@app/components/loading-spinner';
import { Tabs } from '@app/components/tabs';

Expand All @@ -15,26 +16,25 @@ interface HomeTabsProps extends StackProps {
// TODO #4013: Abstract this to generic RouteTab once choose-fee-tab updated
export function HomeTabs({ children }: HomeTabsProps) {
const navigate = useNavigate();
const { pathname } = useLocation();
const location = useLocation();
const backgroundLocation = useLocationState('backgroundLocation');

const tabs = useMemo(
() => [
{ slug: RouteUrls.Home, label: 'balances' },
{ slug: RouteUrls.Activity, label: 'activity' },
{ slug: `${RouteUrls.Home}${RouteUrls.Activity}`, label: 'activity' },
],
[]
);

const getActiveTab = useCallback(
() => tabs.findIndex(tab => tab.slug === pathname),
[tabs, pathname]
);
const getActiveTab = useCallback(() => {
const path = backgroundLocation ? backgroundLocation.pathname : location?.pathname;
return tabs.findIndex(tab => tab.slug === path);
}, [tabs, backgroundLocation, location]);

const setActiveTab = useCallback(
(index: number) => navigate(tabs[index]?.slug),
[navigate, tabs]
);

return (
<Stack flexGrow={1} mt="loose" spacing="extra-loose">
<Tabs
Expand Down
14 changes: 12 additions & 2 deletions src/app/pages/home/components/receive-button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useNavigate } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router-dom';

import { ButtonProps } from '@stacks/ui';
import { HomePageSelectors } from '@tests/selectors/home.selectors';
Expand All @@ -13,15 +13,25 @@ import { HomeActionButton } from './tx-button';

export function ReceiveButton(props: ButtonProps) {
const navigate = useNavigate();
const location = useLocation();
const isBitcoinEnabled = useConfigBitcoinEnabled();
const receivePath = isBitcoinEnabled
? RouteUrls.Receive
: `${RouteUrls.Receive}/${RouteUrls.ReceiveStx}`;

return (
<HomeActionButton
buttonComponent={PrimaryButton}
data-testid={HomePageSelectors.ReceiveCryptoAssetBtn}
icon={QrCodeIcon}
label="Receive"
onClick={() => navigate(isBitcoinEnabled ? RouteUrls.Receive : RouteUrls.ReceiveStx)}
onClick={() =>
navigate(receivePath, {
state: {
backgroundLocation: location,
},
})
}
{...props}
/>
);
Expand Down
26 changes: 21 additions & 5 deletions src/app/pages/home/home.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { Outlet, useNavigate } from 'react-router-dom';
import { Navigate, 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 { receiveRoutes, settingsModalRoutes } from '@app/routes/app-routes';

import { CurrentAccount } from './components/account-area';
import { HomeTabs } from './components/home-tabs';
Expand All @@ -19,8 +22,11 @@ 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(
Expand All @@ -33,15 +39,25 @@ export function Home() {
useOnMount(() => {
if (decodedAuthRequest) navigate(RouteUrls.ChooseAccount);
});

return (
<HomeLayout
suggestedFirstSteps={<SuggestedFirstSteps />}
currentAccount={<CurrentAccount />}
actions={<HomeActions />}
>
<HomeTabs>
<Outlet context={{ address: stacksAccount?.address }} />
<>
<Routes location={backgroundLocation || location}>
<Route index element={<AssetsList />} />
<Route path={RouteUrls.Activity} element={<ActivityList />} />
{/* Routes also need to be declared to work when opened in new tab */}
{/* TODO- refactor this again so it's just one import */}
{receiveRoutes}
{settingsModalRoutes}
<Route path="*" element={<Navigate replace to={RouteUrls.Home} />} />
</Routes>
{backgroundLocation && <Outlet />}
</>
</HomeTabs>
</HomeLayout>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import { useNavigate } from 'react-router-dom';
import { Box, Button, Flex, Text, color } from '@stacks/ui';
import { SharedComponentsSelectors } from '@tests/selectors/shared-component.selectors';

import { RouteUrls } from '@shared/route-urls';

import { useBackgroundLocationRedirect } from '@app/common/hooks/use-background-location-redirect';
import { AddressDisplayer } from '@app/components/address-displayer/address-displayer';
import { BaseDrawer } from '@app/components/drawer/base-drawer';
import { Title } from '@app/components/typography';
Expand All @@ -21,11 +20,11 @@ interface ReceiveTokensLayoutProps {
hasSubtitle?: boolean;
}
export function ReceiveTokensLayout(props: ReceiveTokensLayoutProps) {
useBackgroundLocationRedirect();
const { address, accountName, onCopyAddressToClipboard, title, warning, hasSubtitle } = props;
const navigate = useNavigate();

return (
<BaseDrawer title={title} isShowing onClose={() => navigate(RouteUrls.Home)}>
<BaseDrawer title={title} isShowing onClose={() => navigate('..')}>
<Flex alignItems="center" flexDirection="column" pb={['loose', '48px']} px="loose">
{hasSubtitle && (
<Text color={color('text-caption')} mb="tight" textAlign="left">
Expand Down
Loading

0 comments on commit d7591ed

Please sign in to comment.