Skip to content

Commit

Permalink
feat: add fund btc screen
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarkhanzadian committed Dec 13, 2023
1 parent a87a438 commit df77eb9
Show file tree
Hide file tree
Showing 23 changed files with 395 additions and 110 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Flex } from 'leather-styles/jsx';

import { HasChildren } from '@app/common/has-children';
import { whenPageMode } from '@app/common/utils';

export function ChooseAssetContainer({ children }: HasChildren) {
return whenPageMode({
full: (
<Flex
borderRadius={['unset', '16px']}
height="fit-content"
maxWidth={['100%', 'centeredPageFullWidth']}
minWidth={['100%', 'centeredPageFullWidth']}
background="accent.background-primary"
>
{children}
</Flex>
),
popup: (
<Flex background="accent.background-primary" width="100%">
{children}
</Flex>
),
});
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box, Flex, StackProps, styled } from 'leather-styles/jsx';

export function ChooseCryptoAssetLayout({ children }: StackProps) {
export function ChooseCryptoAssetLayout({ children, title }: StackProps & { title: string }) {
return (
<Flex
alignItems="left"
Expand All @@ -12,10 +12,8 @@ export function ChooseCryptoAssetLayout({ children }: StackProps) {
pb="space.05"
>
<Box pb="space.05" pt={['unset', 'space.05']} px="space.05">
<styled.h1 textStyle="heading.03">
CHOOSE ASSET
<br />
TO SEND
<styled.h1 width="250px" textStyle="heading.03">
{title}
</styled.h1>
</Box>
{children}
Expand Down
81 changes: 81 additions & 0 deletions src/app/pages/fund/choose-asset-to-fund/choose-asset-to-fund.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useCallback, useMemo } from 'react';
import { Outlet, useNavigate } from 'react-router-dom';

import { AllTransferableCryptoAssetBalances } from '@shared/models/crypto-asset-balance.model';
import { RouteUrls } from '@shared/route-urls';

import { useStxBalance } from '@app/common/hooks/balance/stx/use-stx-balance';
import { useRouteHeader } from '@app/common/hooks/use-route-header';
import { useWalletType } from '@app/common/use-wallet-type';
import { ChooseAssetContainer } from '@app/components/crypto-assets/choose-crypto-asset/choose-asset-container';
import { ChooseCryptoAssetLayout } from '@app/components/crypto-assets/choose-crypto-asset/choose-crypto-asset.layout';
import { CryptoAssetList } from '@app/components/crypto-assets/choose-crypto-asset/crypto-asset-list';
import { ModalHeader } from '@app/components/modal-header';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { createStacksCryptoCurrencyAssetTypeWrapper } from '@app/query/stacks/balance/stacks-ft-balances.utils';
import { useCurrentAccountNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCheckLedgerBlockchainAvailable } from '@app/store/accounts/blockchain/utils';

function useBtcCryptoCurrencyAssetBalance() {
const currentBtcSigner = useCurrentAccountNativeSegwitSigner();
if (!currentBtcSigner?.(0).address) throw new Error('No bitcoin address');

return useNativeSegwitBalance(currentBtcSigner?.(0).address);
}

function useStxCryptoCurrencyAssetBalance() {
const { availableBalance: availableStxBalance } = useStxBalance();
return createStacksCryptoCurrencyAssetTypeWrapper(availableStxBalance.amount);
}

export function ChooseCryptoAssetToFund() {
const btcCryptoCurrencyAssetBalance = useBtcCryptoCurrencyAssetBalance();
const stxCryptoCurrencyAssetBalance = useStxCryptoCurrencyAssetBalance();

const cryptoCurrencyAssetBalances = useMemo(
() => [btcCryptoCurrencyAssetBalance, stxCryptoCurrencyAssetBalance],
[btcCryptoCurrencyAssetBalance, stxCryptoCurrencyAssetBalance]
);

const { whenWallet } = useWalletType();
const navigate = useNavigate();

const checkBlockchainAvailable = useCheckLedgerBlockchainAvailable();

const filteredCryptoAssetBalances = useMemo(
() =>
cryptoCurrencyAssetBalances.filter(assetBalance =>
whenWallet({
ledger: checkBlockchainAvailable(assetBalance.blockchain),
software: true,
})
),
[cryptoCurrencyAssetBalances, checkBlockchainAvailable, whenWallet]
);

useRouteHeader(<ModalHeader hideActions onGoBack={() => navigate(RouteUrls.Home)} title=" " />);

const navigateToSendForm = useCallback(
(cryptoAssetBalance: AllTransferableCryptoAssetBalances) => {
const { asset } = cryptoAssetBalance;

const symbol = asset.symbol === '' ? asset.contractAssetName : asset.symbol;
navigate(RouteUrls.Fund.replace(':currency', symbol.toUpperCase()));
},
[navigate]
);

return (
<>
<ChooseAssetContainer>
<ChooseCryptoAssetLayout title="choose asset to fund">
<CryptoAssetList
onItemClick={navigateToSendForm}
cryptoAssetBalances={filteredCryptoAssetBalances}
/>
</ChooseCryptoAssetLayout>
</ChooseAssetContainer>
<Outlet />
</>
);
}
26 changes: 17 additions & 9 deletions src/app/pages/fund/components/fiat-providers.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import TransakIcon from '@assets/images/fund/fiat-providers/transak-icon.png';
import { generateOnRampURL } from '@coinbase/cbpay-js';

import { COINBASE_APP_ID, MOONPAY_API_KEY, TRANSAK_API_KEY } from '@shared/environment';
import { CryptoCurrencies } from '@shared/models/currencies.model';

import { ActiveFiatProvider } from '@app/query/common/remote-config/remote-config.query';

Expand Down Expand Up @@ -41,32 +42,37 @@ export const activeFiatProviderIcons: Record<ActiveFiatProvider['name'], string>
[ActiveFiatProviders.Transak]: TransakIcon,
};

function makeCoinbaseUrl(address: string) {
function makeCoinbaseUrl(address: string, symbol: CryptoCurrencies) {
const code = symbol.toUpperCase();

const onRampURL = generateOnRampURL({
appId: COINBASE_APP_ID,
destinationWallets: [
{
address,
assets: ['STX'],
assets: [code],
},
],
});
return onRampURL;
}

function makeMoonPayUrl(address: string) {
return `https://buy.moonpay.com?apiKey=${MOONPAY_API_KEY}&currencyCode=stx&walletAddress=${address}`;
function makeMoonPayUrl(address: string, symbol: CryptoCurrencies) {
const code = symbol.toLowerCase();
return `https://buy.moonpay.com?apiKey=${MOONPAY_API_KEY}&currencyCode=${code}&walletAddress=${address}`;
}

function makeTransakUrl(address: string) {
function makeTransakUrl(address: string, symbol: CryptoCurrencies) {
const screenTitle = 'Buy Stacks';
const code = symbol.toUpperCase();

return `https://global.transak.com?apiKey=${TRANSAK_API_KEY}&cryptoCurrencyCode=STX&exchangeScreenTitle=${encodeURI(
return `https://global.transak.com?apiKey=${TRANSAK_API_KEY}&cryptoCurrencyCode=${code}&exchangeScreenTitle=${encodeURI(
screenTitle
)}&defaultPaymentMethod=credit_debit_card&walletAddress=${address}`;
}

function makeFiatProviderFaqUrl(address: string, provider: string) {
// TODO: Add FAQ for BTC
return `https://hiro.so/wallet-faq/how-do-i-buy-stx-from-an-exchange?provider=${provider}&address=${address}`;
}

Expand All @@ -75,23 +81,25 @@ interface GetProviderNameArgs {
hasFastCheckoutProcess: boolean;
key: string;
name: string;
symbol: CryptoCurrencies;
}
export function getProviderUrl({
address,
hasFastCheckoutProcess,
key,
name,
symbol,
}: GetProviderNameArgs) {
if (!hasFastCheckoutProcess) {
return makeFiatProviderFaqUrl(address, name);
}
switch (key) {
case ActiveFiatProviders.Coinbase:
return makeCoinbaseUrl(address);
return makeCoinbaseUrl(address, symbol);
case ActiveFiatProviders.MoonPay:
return makeMoonPayUrl(address);
return makeMoonPayUrl(address, symbol);
case ActiveFiatProviders.Transak:
return makeTransakUrl(address);
return makeTransakUrl(address, symbol);
default:
return makeFiatProviderFaqUrl(address, name);
}
Expand Down
8 changes: 4 additions & 4 deletions src/app/pages/fund/components/fund-account-tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ interface FundAccountTileProps {
description: string;
icon: string;
onClickTile(): void;
receiveStxIcon?: React.JSX.Element;
ReceiveStxIcon?(): React.JSX.Element;
testId: string;
title?: string;
}
export function FundAccountTile(props: FundAccountTileProps) {
const { attributes, description, icon, onClickTile, receiveStxIcon, testId, title } = props;
const { attributes, description, icon, onClickTile, ReceiveStxIcon, testId, title } = props;

return (
<styled.button
Expand All @@ -38,8 +38,8 @@ export function FundAccountTile(props: FundAccountTileProps) {
width={['100%', '17.5rem']}
>
<Stack alignItems="flex-start" gap="space.03" p="space.05">
<HStack alignItems="center" gap={receiveStxIcon ? 'space.02' : 'space.04'}>
{receiveStxIcon}
<HStack alignItems="center" gap={ReceiveStxIcon ? 'space.02' : 'space.04'}>
{ReceiveStxIcon ? <ReceiveStxIcon /> : null}
<Box
alignItems="center"
border="default"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import { Flex, Stack, styled } from 'leather-styles/jsx';

import { FiatProvidersList } from './components/fiat-providers-list';
import { CryptoCurrencies } from '@shared/models/currencies.model';

interface FundLayoutProps {
address: string;
import { HasChildren } from '@app/common/has-children';

const nameMap: Record<CryptoCurrencies, { name: string; symbol: string }> = {
BTC: {
name: 'Bitcoin',
symbol: 'BTC',
},
STX: {
name: 'Stacks',
symbol: 'STX',
},
};

interface FundLayoutProps extends HasChildren {
symbol: CryptoCurrencies;
}
export function FundLayout({ address }: FundLayoutProps) {

export function FundLayout({ symbol, children }: FundLayoutProps) {
const name = nameMap[symbol].name;
const nameAbbr = nameMap[symbol].symbol;
return (
<Flex
alignItems={['left', 'center']}
Expand Down Expand Up @@ -35,12 +51,12 @@ export function FundLayout({ address }: FundLayoutProps) {
maxWidth="544px"
textAlign={['left', 'center']}
>
Choose an exchange to fund your account with Stacks (STX) or deposit from elsewhere.
Exchanges with “Fast checkout” make it easier to purchase STX for direct deposit into your
wallet with a credit card.
Choose an exchange to fund your account with {name} ({nameAbbr}) or deposit from
elsewhere. Exchanges with “Fast checkout” make it easier to purchase {nameAbbr} for direct
deposit into your wallet with a credit card.
</styled.span>
</Stack>
<FiatProvidersList address={address} />
{children}
</Flex>
);
}
30 changes: 30 additions & 0 deletions src/app/pages/fund/components/icon-components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import BitcoinIcon from '@assets/images/btc-icon.png';
import ReceiveFundsEllipses from '@assets/images/fund/receive-funds-ellipses.png';
import StacksIcon from '@assets/images/fund/stacks-icon.png';
import { Box } from 'leather-styles/jsx';

export function StacksIconComponent() {
return (
<>
<Box>
<img src={StacksIcon} width="40px" />
</Box>
<Box>
<img src={ReceiveFundsEllipses} width="24px" />
</Box>
</>
);
}

export function BitcoinIconComponent() {
return (
<>
<Box>
<img src={BitcoinIcon} width="40px" />
</Box>
<Box>
<img src={ReceiveFundsEllipses} width="24px" />
</Box>
</>
);
}
40 changes: 40 additions & 0 deletions src/app/pages/fund/components/receive-funds-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';

import QRCodeIcon from '@assets/images/fund/qr-code-icon.png';
import { FundPageSelectors } from '@tests/selectors/fund.selectors';

import { CryptoCurrencies } from '@shared/models/currencies.model';

import { FundAccountTile } from './fund-account-tile';
import { BitcoinIconComponent, StacksIconComponent } from './icon-components';

interface CryptoDescription {
title: string;
IconComponent(): React.JSX.Element;
}

const cryptoDescriptions: Record<CryptoCurrencies, CryptoDescription> = {
STX: {
title: 'Receive STX from a friend or deposit from a separate wallet',
IconComponent: StacksIconComponent,
},
BTC: {
title: 'Receive BTC from a friend or deposit from a separate wallet',
IconComponent: BitcoinIconComponent,
},
};
interface ReceiveStxItemProps {
onReceive(): void;
symbol: CryptoCurrencies;
}
export function ReceiveFundsItem({ onReceive, symbol }: ReceiveStxItemProps) {
return (
<FundAccountTile
description={cryptoDescriptions[symbol].title}
icon={QRCodeIcon}
onClickTile={onReceive}
ReceiveStxIcon={cryptoDescriptions[symbol].IconComponent}
testId={FundPageSelectors.BtnReceiveStx}
/>
);
}
33 changes: 0 additions & 33 deletions src/app/pages/fund/components/receive-stx-item.tsx

This file was deleted.

Loading

0 comments on commit df77eb9

Please sign in to comment.