Skip to content

Commit

Permalink
chore: WIP continue page refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
pete-watters committed Jul 10, 2024
1 parent 71f2565 commit 7bfd15e
Show file tree
Hide file tree
Showing 82 changed files with 872 additions and 771 deletions.
62 changes: 62 additions & 0 deletions src/app/common/page/page.context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ReactNode, createContext, useContext, useEffect, useReducer } from 'react';

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

interface HeaderPayloadState {
title?: string;
isSummaryPage?: boolean;
isSessionLocked?: boolean;
isSettingsVisibleOnSm?: boolean;
onBackLocation?: RouteUrls;
onClose?(): void;
}

interface UpdateAction {
type: 'update';
payload: HeaderPayloadState;
}

interface ResetAction {
type: 'reset';
}
type Action = UpdateAction | ResetAction;

const initialPageState = { isSessionLocked: false, isSettingsVisibleOnSm: true };
const pageReducer = (state: HeaderPayloadState, action: Action): HeaderPayloadState => {
switch (action.type) {
case 'update':
return { ...state, ...action.payload };
case 'reset':
default:
return initialPageState;
}
};

const PageContext = createContext<
{ state: HeaderPayloadState; dispatch: React.Dispatch<Action> } | undefined
>(undefined);

export function PageProvider({ children }: { children: ReactNode }) {
const [state, dispatch] = useReducer(pageReducer, initialPageState);
const value = { state, dispatch };
return <PageContext.Provider value={value}>{children}</PageContext.Provider>;
}

export const usePageContext = () => {
const context = useContext(PageContext);
if (context === undefined) {
throw new Error('usePageContext must be used within a PageProvider');
}
return context;
};

export function useUpdatePageHeaderContext(payload: HeaderPayloadState) {
const { dispatch } = usePageContext();

useEffect(() => {
dispatch({ type: 'update', payload });
return () => {
dispatch({ type: 'reset' });
};
});
}
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/ui/layout/containers/footers/footer';
import { DialogHeader } from '@app/ui/layout/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,8 +10,8 @@ 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 { Card } from '@app/ui/layout/card/card';
import { Footer } from '@app/ui/layout/containers/footers/footer';
import { Page } from '@app/ui/layout/page/page.layout';

import { ErrorLabel } from './error-label';
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 @@ -4,6 +4,7 @@ import { Stack, styled } from 'leather-styles/jsx';

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

import { useUpdatePageHeaderContext } from '@app/common/page/page.context';
import { ErrorLabel } from '@app/components/error-label';
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 @@ -11,7 +11,7 @@ import { BitcoinCustomFee } from '@app/components/bitcoin-custom-fee/bitcoin-cus
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 { useCurrentBtcCryptoAssetBalanceNativeSegwit } from '@app/query/bitcoin/balance/btc-balance-native-segwit.hooks';
import { AvailableBalance } from '@app/ui/components/containers/footers/available-balance';
import { AvailableBalance } from '@app/ui/layout/containers/footers/available-balance';

import { BitcoinChooseFeeLayout } from './components/bitcoin-choose-fee.layout';
import { ChooseFeeSubtitle } from './components/choose-fee-subtitle';
Expand Down
16 changes: 16 additions & 0 deletions src/app/features/container/components/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>
);
}
53 changes: 53 additions & 0 deletions src/app/features/container/components/home/home-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
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" gridTemplateColumns="auto" gridAutoFlow="column" width="100%">
<GridItem justifySelf="start">
<Flex py={{ base: 0, md: 'space.01' }}>{logo}</Flex>
</GridItem>

<GridItem>
<HStack alignItems="center" justifyContent="flex-end">
{networkBadge}
<Settings
triggerButton={<HamburgerIcon data-testid={SettingsSelectors.SettingsMenuBtn} />}
toggleSwitchAccount={() => setIsShowingSwitchAccount(!isShowingSwitchAccount)}
/>
</HStack>
</GridItem>
</Grid>
</styled.header>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { ReactNode } from 'react';

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

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

import { HeaderActionButton } from '../../../../ui/layout/containers/headers/components/header-action-button';

interface HeaderProps {
onClose?(): void;
onGoBack?(): void;
title?: ReactNode;
settingsMenu?: ReactNode;
networkBadge?: ReactNode;
logo?: ReactNode;
}

export function OnboardingHeader({ onGoBack, networkBadge, logo }: HeaderProps) {
const logoItem = onGoBack || logo;

return (
<styled.header
justifyContent="center"
margin={{ base: 0, md: 'auto' }}
p="space.04"
paddingLeft={{ base: undefined, sm: 0 }}
bg="transparent"
maxWidth={{ base: '100vw', md: 'fullPageMaxWidth' }}
width="100%"
>
<Grid alignItems="center" gridTemplateColumns="auto" gridAutoFlow="column" width="100%">
<GridItem justifySelf="start">
{logoItem && (
<Flex py={{ base: 0, md: 'space.01' }}>
{onGoBack && (
<HeaderActionButton
icon={<ArrowLeftIcon />}
onAction={onGoBack}
dataTestId={SharedComponentsSelectors.HeaderBackBtn}
/>
)}
{logo}
</Flex>
)}
</GridItem>

<GridItem>
<HStack alignItems="center" justifyContent="flex-end">
{networkBadge}
</HStack>
</GridItem>
</Grid>
</styled.header>
);
}
120 changes: 120 additions & 0 deletions src/app/features/container/components/page/page.header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { useState } from 'react';
import { 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 { SharedComponentsSelectors } from '@tests/selectors/shared-component.selectors';
import { Box, Flex, Grid, GridItem, HStack, styled } from 'leather-styles/jsx';

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

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

import { SwitchAccountDialog } from '@app/features/dialogs/switch-account-dialog/switch-account-dialog';
import { useCurrentNetworkState } from '@app/store/networks/networks.hooks';

import { usePageContext } from '../../../../common/page/page.context';
import { HeaderActionButton } from '../../../../ui/layout/containers/headers/components/header-action-button';
import { Settings } from '../../../settings/settings';

function LogoBox({ isSessionLocked }: { isSessionLocked: boolean | undefined }) {
const navigate = useNavigate();
return (
<Box
height="headerContainerHeight"
margin="auto"
px="space.02"
hideBelow={isSessionLocked ? undefined : 'sm'}
hideFrom={isSessionLocked ? 'sm' : undefined}
>
<Logo
data-testid={OnboardingSelectors.LogoRouteToHome}
onClick={() => navigate(RouteUrls.Home)}
/>
</Box>
);
}

export function PageHeader() {
const [isShowingSwitchAccount, setIsShowingSwitchAccount] = useState(false);
const navigate = useNavigate();
const { chain, name: chainName } = useCurrentNetworkState();

const {
state: { title, isSummaryPage, isSessionLocked, isSettingsVisibleOnSm, onBackLocation },
} = usePageContext();

// pages with nested dialogs need to specify onBackLocation
// to go back and to prevent navigate(-1) re-opening the dialog
const onGoBack = onBackLocation ? () => navigate(onBackLocation) : () => navigate(-1);
const canGoBack = !isSummaryPage && !isSessionLocked;

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"
gridTemplateColumns={title ? '2fr 4fr 2fr' : 'auto 4fr auto'}
gridAutoFlow="column"
width="100%"
>
<GridItem justifySelf="start">
<Flex py={{ base: 0, md: 'space.01' }}>
{canGoBack && (
<HeaderActionButton
icon={<ArrowLeftIcon />}
onAction={onGoBack}
dataTestId={SharedComponentsSelectors.HeaderBackBtn}
/>
)}
<LogoBox isSessionLocked={isSessionLocked} />
</Flex>
</GridItem>
<GridItem margin="auto">
<styled.span textStyle="heading.05">{title}</styled.span>
</GridItem>
<GridItem>
<HStack alignItems="center" justifyContent="flex-end">
<NetworkModeBadge
isTestnetChain={chain.stacks.chainId === ChainID.Testnet}
name={chainName}
/>

{!isSummaryPage && (
<styled.div hideBelow={isSettingsVisibleOnSm ? undefined : 'sm'}>
<Settings
triggerButton={
<HamburgerIcon data-testid={SettingsSelectors.SettingsMenuBtn} />
}
toggleSwitchAccount={() => setIsShowingSwitchAccount(!isShowingSwitchAccount)}
/>
</styled.div>
)}
{isSummaryPage && (
<HeaderActionButton
icon={<CloseIcon />}
dataTestId={SharedComponentsSelectors.HeaderCloseBtn}
onAction={() => navigate(RouteUrls.Home)}
/>
)}
</HStack>
</GridItem>
</Grid>
</styled.header>
</>
);
}
Loading

0 comments on commit 7bfd15e

Please sign in to comment.