Skip to content

Commit

Permalink
chore: refactor containers to use composition
Browse files Browse the repository at this point in the history
  • Loading branch information
pete-watters committed Jul 9, 2024
1 parent cf35f60 commit 8302c84
Show file tree
Hide file tree
Showing 82 changed files with 902 additions and 769 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import get from 'lodash.get';

import { Button, Dialog } from '@leather.io/ui';

import { Footer } from '@app/ui/components/containers/footers/footer';
import { DialogHeader } from '@app/ui/components/containers/headers/dialog-header';
import { Footer } from '@app/features/container/containers/footers/footer';
import { DialogHeader } from '@app/features/container/containers/headers/dialog-header';

export function BroadcastErrorDialog() {
const navigate = useNavigate();
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/request-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { analytics } from '@shared/utils/analytics';
import { useKeyActions } from '@app/common/hooks/use-key-actions';
import { buildEnterKeyEvent } from '@app/common/hooks/use-modifier-key';
import { WaitingMessages, useWaitingMessage } from '@app/common/hooks/use-waiting-message';
import { Footer } from '@app/ui/components/containers/footers/footer';
import { Footer } from '@app/features/container/containers/footers/footer';
import { Card } from '@app/ui/layout/card/card';
import { Page } from '@app/ui/layout/page/page.layout';

Expand Down
2 changes: 2 additions & 0 deletions src/app/features/add-network/add-network.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Stack, styled } from 'leather-styles/jsx';
import { Button } from '@leather.io/ui';

import { ErrorLabel } from '@app/components/error-label';
import { useUpdatePageHeaderContext } from '@app/features/container/containers/page/page.context';
import { Card } from '@app/ui/layout/card/card';
import { Page } from '@app/ui/layout/page/page.layout';

Expand All @@ -13,6 +14,7 @@ import { useAddNetwork } from './use-add-network';

export function AddNetwork() {
const { error, initialFormValues, loading, onSubmit } = useAddNetwork();
useUpdatePageHeaderContext({ title: 'Add Network' });

return (
<Page>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function Sip10TokenAssetList({
{tokens.map(token => (
<Sip10TokenAssetItem
balance={token.balance}
key={token.info.name}
key={token.info.name + token.info.contractId}
info={token.info}
isLoading={isLoading}
marketData={priceAsMarketData(
Expand Down
2 changes: 1 addition & 1 deletion src/app/features/bitcoin-choose-fee/bitcoin-choose-fee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import type { TransferRecipient } from '@shared/models/form.model';
import { BitcoinCustomFee } from '@app/components/bitcoin-custom-fee/bitcoin-custom-fee';
import { MAX_FEE_RATE_MULTIPLIER } from '@app/components/bitcoin-custom-fee/hooks/use-bitcoin-custom-fee';
import { OnChooseFeeArgs } from '@app/components/bitcoin-fees-list/bitcoin-fees-list';
import { AvailableBalance } from '@app/features/container/containers/footers/available-balance';
import { useCurrentBtcCryptoAssetBalanceNativeSegwit } from '@app/query/bitcoin/balance/btc-balance-native-segwit.hooks';
import { AvailableBalance } from '@app/ui/components/containers/footers/available-balance';

import { BitcoinChooseFeeLayout } from './components/bitcoin-choose-fee.layout';
import { ChooseFeeSubtitle } from './components/choose-fee-subtitle';
Expand Down
148 changes: 4 additions & 144 deletions src/app/features/container/container.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,24 @@
import { useEffect, useState } from 'react';
import { Outlet, useLocation, useNavigate } from 'react-router-dom';

import { ChainID } from '@stacks/transactions';
import { OnboardingSelectors } from '@tests/selectors/onboarding.selectors';
import { SettingsSelectors } from '@tests/selectors/settings.selectors';
import { Box } from 'leather-styles/jsx';

import { Flag, HamburgerIcon, Logo, NetworkModeBadge } from '@leather.io/ui';
import { useEffect } from 'react';
import { Outlet, useLocation } from 'react-router-dom';

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

import { useInitalizeAnalytics } from '@app/common/app-analytics';
import { LoadingSpinner } from '@app/components/loading-spinner';
import { CurrentAccountAvatar } from '@app/features/current-account/current-account-avatar';
import { CurrentAccountName } from '@app/features/current-account/current-account-name';
import { SwitchAccountDialog } from '@app/features/dialogs/switch-account-dialog/switch-account-dialog';
import { InAppMessages } from '@app/features/hiro-messages/in-app-messages';
import { useOnSignOut } from '@app/routes/hooks/use-on-sign-out';
import { useOnWalletLock } from '@app/routes/hooks/use-on-wallet-lock';
import { useHasStateRehydrated } from '@app/store';
import { useCurrentNetworkState } from '@app/store/networks/networks.hooks';
import { ContainerLayout } from '@app/ui/components/containers/container.layout';
import { Header } from '@app/ui/components/containers/headers/header';

import { useRestoreFormState } from '../popup-send-form-restoration/use-restore-form-state';
import { Settings } from '../settings/settings';
import { TotalBalance } from './total-balance';
import {
getDisplayAddresssBalanceOf,
isKnownPopupRoute,
isRpcRoute,
showAccountInfo,
showBalanceInfo,
} from './utils/get-popup-header';
import { getTitleFromUrl } from './utils/get-title-from-url';
import {
canGoBack,
getIsSessionLocked,
getPageVariant,
hideLogo,
hideSettingsOnSm,
isLandingPage,
isNoHeaderPopup,
isSummaryPage,
} from './utils/route-helpers';

export function Container() {
const [isShowingSwitchAccount, setIsShowingSwitchAccount] = useState(false);
const navigate = useNavigate();
const { pathname: locationPathname } = useLocation();
const pathname = locationPathname as RouteUrls;

const hasStateRehydrated = useHasStateRehydrated();
const { chain, name: chainName } = useCurrentNetworkState();

useOnWalletLock(() => closeWindow());
useOnSignOut(() => closeWindow());
Expand All @@ -63,117 +27,13 @@ export function Container() {

useEffect(() => void analytics.page('view', `${pathname}`), [pathname]);

const variant = getPageVariant(pathname);

const displayHeader = !isLandingPage(pathname) && !isNoHeaderPopup(pathname);
const isSessionLocked = getIsSessionLocked(pathname);

// TODO: Refactor? This is very hard to manage with dynamic routes. Temporarily
// added a fix to catch the swap route: '/swap/:base/:quote?'
function getOnGoBackLocation(pathname: RouteUrls) {
if (pathname.includes('/swap')) return navigate(RouteUrls.Home);
switch (pathname) {
case RouteUrls.Fund.replace(':currency', 'STX'):
case RouteUrls.Fund.replace(':currency', 'BTC'):
case RouteUrls.SendCryptoAssetForm.replace(':symbol', 'stx'):
case RouteUrls.SendCryptoAssetForm.replace(':symbol', 'btc'):
return navigate(RouteUrls.Home);
case RouteUrls.SendStxConfirmation:
return navigate(RouteUrls.SendCryptoAssetForm.replace(':symbol', 'stx'));
case RouteUrls.SendBtcConfirmation:
return navigate(RouteUrls.SendCryptoAssetForm.replace(':symbol', 'btc'));
default:
return navigate(-1);
}
}

if (!hasStateRehydrated) return <LoadingSpinner />;

const showLogoSm = variant === 'home' || isSessionLocked || isKnownPopupRoute(pathname);
const hideSettings =
isKnownPopupRoute(pathname) || isSummaryPage(pathname) || variant === 'onboarding';

const isLogoClickable = variant !== 'home' && !isRpcRoute(pathname);
return (
<>
{isShowingSwitchAccount && (
<SwitchAccountDialog
isShowing={isShowingSwitchAccount}
onClose={() => setIsShowingSwitchAccount(false)}
/>
)}

<InAppMessages />
<ContainerLayout
header={
displayHeader ? (
<Header
variant={variant}
onGoBack={canGoBack(pathname) ? () => getOnGoBackLocation(pathname) : undefined}
onClose={isSummaryPage(pathname) ? () => navigate(RouteUrls.Home) : undefined}
settingsMenu={
hideSettings ? null : (
<Settings
triggerButton={
<HamburgerIcon
data-testid={SettingsSelectors.SettingsMenuBtn}
hideBelow={hideSettingsOnSm(pathname) ? 'sm' : undefined}
/>
}
toggleSwitchAccount={() => setIsShowingSwitchAccount(!isShowingSwitchAccount)}
/>
)
}
networkBadge={
<NetworkModeBadge
isTestnetChain={chain.stacks.chainId === ChainID.Testnet}
name={chainName}
/>
}
title={getTitleFromUrl(pathname)}
logo={
!hideLogo(pathname) && (
<Box
height="headerContainerHeight"
margin="auto"
px="space.02"
hideBelow={showLogoSm ? undefined : 'sm'}
hideFrom={isSessionLocked ? 'sm' : undefined}
>
<Logo
data-testid={OnboardingSelectors.LogoRouteToHome}
onClick={isLogoClickable ? () => navigate(RouteUrls.Home) : undefined}
/>
</Box>
)
}
account={
showAccountInfo(pathname) && (
<Flag
align="middle"
img={
<CurrentAccountAvatar
toggleSwitchAccount={() =>
setIsShowingSwitchAccount(!isShowingSwitchAccount)
}
/>
}
>
<CurrentAccountName />
</Flag>
)
}
totalBalance={
showBalanceInfo(pathname) && (
<TotalBalance displayAddresssBalanceOf={getDisplayAddresssBalanceOf(pathname)} />
)
}
/>
) : null
}
>
<Outlet context={{ isShowingSwitchAccount, setIsShowingSwitchAccount }} />
</ContainerLayout>

<Outlet />
</>
);
}
16 changes: 16 additions & 0 deletions src/app/features/container/containers/container.layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Flex } from 'leather-styles/jsx';

interface ContainerLayoutProps {
content?: React.JSX.Element | React.JSX.Element[];
header?: React.JSX.Element | null;
}
export function ContainerLayout({ content, header }: ContainerLayoutProps) {
return (
<Flex flexDirection="column" flexGrow={1} width="100%" height={{ base: '100vh', sm: '100%' }}>
{header}
<Flex className="main-content" flexGrow={1} position="relative" width="100%">
{content}
</Flex>
</Flex>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import { CloseIcon, IconButton } from '@leather.io/ui';
interface DialogHeaderProps {
onClose?(): void;
title?: ReactNode;
variant?: 'default' | 'large';
}

export function DialogHeader({ onClose, title }: DialogHeaderProps) {
export function DialogHeader({ onClose, title, variant = 'default' }: DialogHeaderProps) {
return (
<Flex
justifyContent="flex-end"
Expand All @@ -21,7 +22,11 @@ export function DialogHeader({ onClose, title }: DialogHeaderProps) {
minHeight="40px"
>
{title && (
<styled.h2 flex="1" textAlign="center" textStyle="heading.05">
<styled.h2
flex="1"
textAlign={variant === 'large' ? 'left' : 'center'}
textStyle={variant === 'large' ? 'heading.03' : 'heading.05'}
>
{title}
</styled.h2>
)}
Expand Down
61 changes: 61 additions & 0 deletions src/app/features/container/containers/home/home-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { ReactNode, useState } from 'react';

import { SettingsSelectors } from '@tests/selectors/settings.selectors';
import { Flex, Grid, GridItem, HStack, styled } from 'leather-styles/jsx';

import { HamburgerIcon } from '@leather.io/ui';

import { SwitchAccountDialog } from '@app/features/dialogs/switch-account-dialog/switch-account-dialog';

import { Settings } from '../../../settings/settings';

interface HomeHeaderProps {
networkBadge?: ReactNode;
logo?: ReactNode;
}

export function HomeHeader({ networkBadge, logo }: HomeHeaderProps) {
const [isShowingSwitchAccount, setIsShowingSwitchAccount] = useState(false);
return (
<>
{isShowingSwitchAccount && (
<SwitchAccountDialog
isShowing={isShowingSwitchAccount}
onClose={() => setIsShowingSwitchAccount(false)}
/>
)}
<styled.header
justifyContent="center"
margin={{ base: 0, md: 'auto' }}
p="space.04"
bg="transparent"
maxWidth={{ base: '100vw', md: 'fullPageMaxWidth' }}
width="100%"
>
<Grid
alignItems="center"
// same as onboarding-header.tsx - don't need grid really as no title
gridTemplateColumns={'auto 4fr auto'}
gridAutoFlow="column"
width="100%"
>
<GridItem justifySelf="start">
<Flex py={{ base: 0, md: 'space.01' }}>{logo}</Flex>
</GridItem>

{/* This grid item could be un-needed */}
<GridItem margin="auto"></GridItem>
<GridItem>
<HStack alignItems="center" justifyContent="flex-end">
{networkBadge}
<Settings
triggerButton={<HamburgerIcon data-testid={SettingsSelectors.SettingsMenuBtn} />}
toggleSwitchAccount={() => setIsShowingSwitchAccount(!isShowingSwitchAccount)}
/>
</HStack>
</GridItem>
</Grid>
</styled.header>
</>
);
}
36 changes: 36 additions & 0 deletions src/app/features/container/containers/home/home.layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Outlet } from 'react-router-dom';

import { ChainID } from '@stacks/transactions';
import { Box } from 'leather-styles/jsx';

import { Logo, NetworkModeBadge } from '@leather.io/ui';

import { useCurrentNetworkState } from '@app/store/networks/networks.hooks';

import { ContainerLayout } from '../container.layout';
import { HomeHeader } from './home-header';

export function HomeLayout() {
const { chain, name: chainName } = useCurrentNetworkState();

return (
<ContainerLayout
header={
<HomeHeader
networkBadge={
<NetworkModeBadge
isTestnetChain={chain.stacks.chainId === ChainID.Testnet}
name={chainName}
/>
}
logo={
<Box height="headerContainerHeight" margin="auto" px="space.02">
<Logo />
</Box>
}
/>
}
content={<Outlet />}
/>
);
}
Loading

0 comments on commit 8302c84

Please sign in to comment.