mirror of
https://github.com/zhigang1992/wallet.git
synced 2026-01-12 22:53:27 +08:00
chore: refactor receive modal to share code better
This commit is contained in:
6
src/app/components/icons/btc-stamps-icon.tsx
Normal file
6
src/app/components/icons/btc-stamps-icon.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import BitcoinStampImg from '@assets/images/bitcoin-stamp.png';
|
||||
import { Box } from '@stacks/ui';
|
||||
|
||||
export function BtcStampsIcon() {
|
||||
return <Box as="img" src={BitcoinStampImg} width="36px" />;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
import toast from 'react-hot-toast';
|
||||
import { useLocation, 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 { 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';
|
||||
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
|
||||
import { useCurrentAccountStxAddressState } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
|
||||
|
||||
import { ReceiveCollectibleItem } from './receive-collectible-item';
|
||||
|
||||
export function ReceiveCollectible() {
|
||||
const analytics = useAnalytics();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const accountIndex = get(location.state, 'accountIndex', undefined);
|
||||
const btcAddressNativeSegwit = useCurrentAccountNativeSegwitAddressIndexZero();
|
||||
const btcAddressTaproot = useZeroIndexTaprootAddress(accountIndex);
|
||||
|
||||
// TODO: Reuse later for privacy mode
|
||||
// const { isLoading, isError, data: btcAddress } = useNextFreshTaprootAddressQuery(accountIndex);
|
||||
|
||||
const stxAddress = useCurrentAccountStxAddressState();
|
||||
const { onCopy: onCopyOrdinal } = useClipboard(btcAddressTaproot);
|
||||
const { onCopy: onCopyBitcoin } = useClipboard(btcAddressNativeSegwit);
|
||||
const { onCopy: onCopyStacks } = useClipboard(stxAddress);
|
||||
|
||||
function copyBitcoinAddressToClipboard(copyHandler: () => void) {
|
||||
void analytics.track('select_stamp_to_add_new_collectible');
|
||||
toast.success('Copied to clipboard!');
|
||||
copyHandler();
|
||||
}
|
||||
|
||||
function copyStacksAddressToClipboard(copyHandler: () => void) {
|
||||
void analytics.track('select_nft_to_add_new_collectible');
|
||||
toast.success('Copied to clipboard!');
|
||||
copyHandler();
|
||||
}
|
||||
|
||||
if (!btcAddressTaproot) return null;
|
||||
|
||||
return (
|
||||
<Stack spacing="loose" mt="base" mb="extra-loose">
|
||||
<ReceiveCollectibleItem
|
||||
address={btcAddressTaproot}
|
||||
icon={<OrdinalIcon />}
|
||||
dataTestId={HomePageSelectors.ReceiveBtcTaprootQrCodeBtn}
|
||||
onCopyAddress={() => copyBitcoinAddressToClipboard(onCopyOrdinal)}
|
||||
onClickQrCode={() => {
|
||||
void analytics.track('select_inscription_to_add_new_collectible');
|
||||
navigate(RouteUrls.ReceiveCollectibleOrdinal, { state: { btcAddressTaproot } });
|
||||
}}
|
||||
title="Ordinal inscription"
|
||||
/>
|
||||
<ReceiveCollectibleItem
|
||||
address={btcAddressNativeSegwit}
|
||||
icon={
|
||||
<Box>
|
||||
<img src={BitcoinStampImg} width="36px" />
|
||||
</Box>
|
||||
}
|
||||
onCopyAddress={() => copyBitcoinAddressToClipboard(onCopyBitcoin)}
|
||||
title="Bitcoin Stamp"
|
||||
/>
|
||||
<ReceiveCollectibleItem
|
||||
address={stxAddress}
|
||||
icon={<StxAvatar />}
|
||||
dataTestId={HomePageSelectors.ReceiveStxQrCodeBtn}
|
||||
onCopyAddress={() => copyStacksAddressToClipboard(onCopyStacks)}
|
||||
onClickQrCode={() => navigate(RouteUrls.ReceiveStx)}
|
||||
title="Stacks NFT"
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
import toast from 'react-hot-toast';
|
||||
import { FiCopy } from 'react-icons/fi';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { Box, Button, Flex, Stack, useClipboard } from '@stacks/ui';
|
||||
import { color, truncateMiddle } from '@stacks/ui-utils';
|
||||
import { HomePageSelectors } from '@tests/selectors/home.selectors';
|
||||
|
||||
import { RouteUrls } from '@shared/route-urls';
|
||||
|
||||
import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
|
||||
import { StxAvatar } from '@app/components/crypto-assets/stacks/components/stx-avatar';
|
||||
import { BaseDrawer } from '@app/components/drawer/base-drawer';
|
||||
import { BtcIcon } from '@app/components/icons/btc-icon';
|
||||
import { Flag } from '@app/components/layout/flag';
|
||||
import { QrCodeIcon } from '@app/components/qr-code-icon';
|
||||
import { ReceiveCollectible } from '@app/components/receive/receive-collectible';
|
||||
import { Caption } from '@app/components/typography';
|
||||
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
|
||||
import { useCurrentAccountStxAddressState } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
|
||||
|
||||
export function ReceiveModal() {
|
||||
const analytics = useAnalytics();
|
||||
const navigate = useNavigate();
|
||||
const btcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
|
||||
const stxAddress = useCurrentAccountStxAddressState();
|
||||
const { onCopy: onCopyBtc } = useClipboard(btcAddress);
|
||||
const { onCopy: onCopyStacks } = useClipboard(stxAddress);
|
||||
|
||||
function copyToClipboard(copyHandler: () => void) {
|
||||
void analytics.track('copy_address_to_clipboard');
|
||||
toast.success('Copied to clipboard!');
|
||||
copyHandler();
|
||||
}
|
||||
return (
|
||||
<BaseDrawer title="Select asset to receive" isShowing onClose={() => navigate('../')}>
|
||||
<Box mx="extra-loose">
|
||||
<Caption style={{ fontSize: '14px' }}>Tokens</Caption>
|
||||
|
||||
<Stack spacing="loose" mt="base" mb="extra-loose">
|
||||
<Flag img={<BtcIcon />} spacing="base">
|
||||
<Flex justifyContent="space-between">
|
||||
<Box>
|
||||
Bitcoin
|
||||
<Caption mt="2px">{truncateMiddle(btcAddress, 6)}</Caption>
|
||||
</Box>
|
||||
<Stack>
|
||||
<Box>
|
||||
<Button
|
||||
borderRadius="10px"
|
||||
mode="tertiary"
|
||||
onClick={() => copyToClipboard(onCopyBtc)}
|
||||
>
|
||||
<FiCopy />
|
||||
</Button>
|
||||
<Button
|
||||
borderRadius="10px"
|
||||
data-testid={HomePageSelectors.ReceiveBtcNativeSegwitQrCodeBtn}
|
||||
mode="tertiary"
|
||||
ml="tight"
|
||||
onClick={() => navigate(RouteUrls.ReceiveBtc)}
|
||||
>
|
||||
<Box color={color('text-caption')} size="14px">
|
||||
<QrCodeIcon />
|
||||
</Box>
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Flag>
|
||||
<Flag img={<StxAvatar />} spacing="base">
|
||||
<Flex justifyContent="space-between">
|
||||
<Box>
|
||||
Stacks
|
||||
<Caption mt="2px">{truncateMiddle(stxAddress, 6)}</Caption>
|
||||
</Box>
|
||||
<Stack>
|
||||
<Box>
|
||||
<Button
|
||||
borderRadius="10px"
|
||||
mode="tertiary"
|
||||
onClick={() => copyToClipboard(onCopyStacks)}
|
||||
>
|
||||
<FiCopy />
|
||||
</Button>
|
||||
<Button
|
||||
borderRadius="10px"
|
||||
data-testid={HomePageSelectors.ReceiveStxQrCodeBtn}
|
||||
mode="tertiary"
|
||||
ml="tight"
|
||||
onClick={() => navigate(RouteUrls.ReceiveStx)}
|
||||
>
|
||||
<Box color={color('text-caption')} size="14px">
|
||||
<QrCodeIcon />
|
||||
</Box>
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Flag>
|
||||
</Stack>
|
||||
<Caption style={{ fontSize: '14px' }}>Collectibles</Caption>
|
||||
|
||||
<ReceiveCollectible />
|
||||
</Box>
|
||||
</BaseDrawer>
|
||||
);
|
||||
}
|
||||
@@ -3,12 +3,11 @@ import { FiCopy } from 'react-icons/fi';
|
||||
import { Box, Button, ButtonProps, Flex, Stack } from '@stacks/ui';
|
||||
import { color, truncateMiddle } from '@stacks/ui-utils';
|
||||
|
||||
import { Caption } from '@app/components//typography';
|
||||
import { Flag } from '@app/components/layout/flag';
|
||||
import { QrCodeIcon } from '@app/components/qr-code-icon';
|
||||
|
||||
import { Flag } from '../layout/flag';
|
||||
import { Caption } from '../typography';
|
||||
|
||||
interface ReceiveCollectibleItemProps extends ButtonProps {
|
||||
interface ReceiveItemProps extends ButtonProps {
|
||||
address: string;
|
||||
dataTestId?: string;
|
||||
icon: React.JSX.Element;
|
||||
@@ -16,15 +15,14 @@ interface ReceiveCollectibleItemProps extends ButtonProps {
|
||||
onClickQrCode?(): void;
|
||||
title: string;
|
||||
}
|
||||
export function ReceiveCollectibleItem({
|
||||
export function ReceiveItem({
|
||||
address,
|
||||
dataTestId,
|
||||
icon,
|
||||
onCopyAddress,
|
||||
onClickQrCode,
|
||||
title,
|
||||
...rest
|
||||
}: ReceiveCollectibleItemProps) {
|
||||
}: ReceiveItemProps) {
|
||||
return (
|
||||
<Flag img={icon} spacing="base">
|
||||
<Flex justifyContent="space-between">
|
||||
@@ -34,7 +32,7 @@ export function ReceiveCollectibleItem({
|
||||
</Box>
|
||||
<Stack>
|
||||
<Box>
|
||||
<Button borderRadius="10px" mode="tertiary" onClick={onCopyAddress} {...rest}>
|
||||
<Button borderRadius="10px" mode="tertiary" onClick={onCopyAddress}>
|
||||
<FiCopy />
|
||||
</Button>
|
||||
{onClickQrCode && (
|
||||
@@ -45,9 +43,7 @@ export function ReceiveCollectibleItem({
|
||||
ml="tight"
|
||||
onClick={onClickQrCode}
|
||||
>
|
||||
<Box color={color('text-caption')} size="14px">
|
||||
<QrCodeIcon />
|
||||
</Box>
|
||||
<QrCodeIcon color={color('text-caption')} size="14px" />
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
18
src/app/pages/receive/components/receive-items.tsx
Normal file
18
src/app/pages/receive/components/receive-items.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ButtonProps, Stack } from '@stacks/ui';
|
||||
|
||||
import { Caption } from '@app/components//typography';
|
||||
|
||||
interface ReceiveItemListProps extends ButtonProps {
|
||||
children: React.ReactNode;
|
||||
title?: string;
|
||||
}
|
||||
export function ReceiveItemList({ children, title }: ReceiveItemListProps) {
|
||||
return (
|
||||
<>
|
||||
{title && <Caption>{title}</Caption>}
|
||||
<Stack spacing="loose" mt="base" mb="extra-loose">
|
||||
{children}
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { useCurrentAccountDisplayName } from '@app/common/hooks/account/use-acco
|
||||
import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
|
||||
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
|
||||
|
||||
import { ReceiveTokensLayout } from './components/receive-tokens.layout';
|
||||
import { ReceiveTokensLayout } from '../components/receive-tokens.layout';
|
||||
|
||||
// ts-unused-exports:disable-next-line
|
||||
export function ReceiveTokens() {
|
||||
@@ -1,18 +0,0 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { Box } from '@stacks/ui';
|
||||
|
||||
import { BaseDrawer } from '@app/components/drawer/base-drawer';
|
||||
import { ReceiveCollectible } from '@app/components/receive/receive-collectible';
|
||||
|
||||
export function ReceiveCollectibleModal() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<BaseDrawer title="Add collectible" isShowing onClose={() => navigate('../')}>
|
||||
<Box mx="extra-loose">
|
||||
<ReceiveCollectible />
|
||||
</Box>
|
||||
</BaseDrawer>
|
||||
);
|
||||
}
|
||||
104
src/app/pages/receive/receive-modal.tsx
Normal file
104
src/app/pages/receive/receive-modal.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import toast from 'react-hot-toast';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { Box, 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 { StxAvatar } from '@app/components/crypto-assets/stacks/components/stx-avatar';
|
||||
import { BaseDrawer } from '@app/components/drawer/base-drawer';
|
||||
import { BtcIcon } from '@app/components/icons/btc-icon';
|
||||
import { BtcStampsIcon } from '@app/components/icons/btc-stamps-icon';
|
||||
import { OrdinalIcon } from '@app/components/icons/ordinal-icon';
|
||||
import { useZeroIndexTaprootAddress } from '@app/query/bitcoin/ordinals/use-zero-index-taproot-address';
|
||||
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
|
||||
import { useCurrentAccountStxAddressState } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
|
||||
|
||||
import { ReceiveItem } from './components/receive-item';
|
||||
import { ReceiveItemList } from './components/receive-items';
|
||||
|
||||
type ReceiveModal = 'full' | 'collectible';
|
||||
|
||||
interface ReceiveModalProps {
|
||||
type?: 'full' | 'collectible';
|
||||
}
|
||||
|
||||
export function ReceiveModal({ type = 'full' }: ReceiveModalProps) {
|
||||
const analytics = useAnalytics();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const btcAddressNativeSegwit = useCurrentAccountNativeSegwitAddressIndexZero();
|
||||
const stxAddress = useCurrentAccountStxAddressState();
|
||||
const accountIndex = get(location.state, 'accountIndex', undefined);
|
||||
const btcAddressTaproot = useZeroIndexTaprootAddress(accountIndex);
|
||||
|
||||
const { onCopy: onCopyBtc } = useClipboard(btcAddressNativeSegwit);
|
||||
const { onCopy: onCopyStx } = useClipboard(stxAddress);
|
||||
const { onCopy: onCopyOrdinal } = useClipboard(btcAddressTaproot);
|
||||
|
||||
function copyToClipboard(copyHandler: () => void, tracker = 'copy_address_to_clipboard') {
|
||||
void analytics.track(tracker);
|
||||
toast.success('Copied to clipboard!');
|
||||
copyHandler();
|
||||
}
|
||||
|
||||
const title = type === 'full' ? 'Select asset to receive' : 'Add collectible';
|
||||
|
||||
return (
|
||||
<BaseDrawer title={title} isShowing onClose={() => navigate('../')}>
|
||||
<Box mx="extra-loose">
|
||||
{type === 'full' && (
|
||||
<ReceiveItemList title="Tokens">
|
||||
<ReceiveItem
|
||||
address={btcAddressNativeSegwit}
|
||||
icon={<BtcIcon />}
|
||||
dataTestId={HomePageSelectors.ReceiveBtcNativeSegwitQrCodeBtn}
|
||||
onCopyAddress={() => copyToClipboard(onCopyBtc)}
|
||||
onClickQrCode={() => navigate(RouteUrls.ReceiveBtc)}
|
||||
title="Bitcoin"
|
||||
/>
|
||||
<ReceiveItem
|
||||
address={stxAddress}
|
||||
icon={<StxAvatar />}
|
||||
dataTestId={HomePageSelectors.ReceiveStxQrCodeBtn}
|
||||
onCopyAddress={() => copyToClipboard(onCopyStx)}
|
||||
onClickQrCode={() => navigate(RouteUrls.ReceiveStx)}
|
||||
title="Stacks"
|
||||
/>
|
||||
</ReceiveItemList>
|
||||
)}
|
||||
<ReceiveItemList title={type === 'full' ? 'Collectibles' : undefined}>
|
||||
<ReceiveItem
|
||||
address={btcAddressTaproot}
|
||||
icon={<OrdinalIcon />}
|
||||
dataTestId={HomePageSelectors.ReceiveBtcTaprootQrCodeBtn}
|
||||
onCopyAddress={() =>
|
||||
copyToClipboard(onCopyOrdinal, 'select_stamp_to_add_new_collectible')
|
||||
}
|
||||
onClickQrCode={() => {
|
||||
void analytics.track('select_inscription_to_add_new_collectible');
|
||||
navigate(RouteUrls.ReceiveCollectibleOrdinal, { state: { btcAddressTaproot } });
|
||||
}}
|
||||
title="Ordinal inscription"
|
||||
/>
|
||||
<ReceiveItem
|
||||
address={btcAddressNativeSegwit}
|
||||
icon={<BtcStampsIcon />}
|
||||
onCopyAddress={() => copyToClipboard(onCopyBtc, 'select_stamp_to_add_new_collectible')}
|
||||
title="Bitcoin Stamp"
|
||||
/>
|
||||
<ReceiveItem
|
||||
address={stxAddress}
|
||||
icon={<StxAvatar />}
|
||||
onCopyAddress={() => copyToClipboard(onCopyStx, 'select_nft_to_add_new_collectible')}
|
||||
onClickQrCode={() => navigate(RouteUrls.ReceiveStx)}
|
||||
title="Stacks NFT"
|
||||
/>
|
||||
</ReceiveItemList>
|
||||
</Box>
|
||||
</BaseDrawer>
|
||||
);
|
||||
}
|
||||
@@ -35,11 +35,10 @@ import { BackUpSecretKeyPage } from '@app/pages/onboarding/back-up-secret-key/ba
|
||||
import { SignIn } from '@app/pages/onboarding/sign-in/sign-in';
|
||||
import { WelcomePage } from '@app/pages/onboarding/welcome/welcome';
|
||||
import { PsbtRequest } from '@app/pages/psbt-request/psbt-request';
|
||||
import { ReceiveBtcModal } from '@app/pages/receive-tokens/receive-btc';
|
||||
import { ReceiveModal } from '@app/pages/receive-tokens/receive-modal';
|
||||
import { ReceiveStxModal } from '@app/pages/receive-tokens/receive-stx';
|
||||
import { ReceiveCollectibleModal } from '@app/pages/receive/receive-collectible/receive-collectible-modal';
|
||||
import { ReceiveCollectibleOrdinal } from '@app/pages/receive/receive-collectible/receive-collectible-oridinal';
|
||||
import { ReceiveBtcModal } from '@app/pages/receive/receive-btc';
|
||||
import { ReceiveCollectibleOrdinal } from '@app/pages/receive/receive-collectible-oridinal';
|
||||
import { ReceiveModal } from '@app/pages/receive/receive-modal';
|
||||
import { ReceiveStxModal } from '@app/pages/receive/receive-stx';
|
||||
import { RequestError } from '@app/pages/request-error/request-error';
|
||||
import { RpcGetAddresses } from '@app/pages/rpc-get-addresses/rpc-get-addresses';
|
||||
import { rpcSendTransferRoutes } from '@app/pages/rpc-send-transfer/rpc-send-transfer.routes';
|
||||
@@ -213,7 +212,10 @@ function useAppRoutes() {
|
||||
<Route path={RouteUrls.IncreaseFeeSent} element={<IncreaseFeeSentDrawer />} />
|
||||
|
||||
<Route path={RouteUrls.Receive} element={<ReceiveModal />} />
|
||||
<Route path={RouteUrls.ReceiveCollectible} element={<ReceiveCollectibleModal />} />
|
||||
<Route
|
||||
path={RouteUrls.ReceiveCollectible}
|
||||
element={<ReceiveModal type="collectible" />}
|
||||
/>
|
||||
<Route
|
||||
path={RouteUrls.ReceiveCollectibleOrdinal}
|
||||
element={<ReceiveCollectibleOrdinal />}
|
||||
|
||||
Reference in New Issue
Block a user