Skip to content

Commit

Permalink
feat: add token card to coins value
Browse files Browse the repository at this point in the history
  • Loading branch information
poomthiti committed Mar 1, 2023
1 parent e64b05c commit 5af959b
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 78 deletions.
21 changes: 15 additions & 6 deletions src/lib/components/copy/CopyButton.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
import { CopyIcon } from "@chakra-ui/icons";
import { Button } from "@chakra-ui/react";
import type { ButtonProps } from "@chakra-ui/react";
import type { ButtonProps, TooltipProps } from "@chakra-ui/react";

import { AmpEvent, AmpTrack } from "lib/services/amplitude";

import { CopyTemplate } from "./CopyTemplate";

interface CopyButtonProps {
interface CopyButtonProps extends ButtonProps {
isDisable?: boolean;
value: string;
size?: ButtonProps["size"];
copyLabel?: string;
hasIcon?: boolean;
buttonText?: string;
tooltipBgColor?: TooltipProps["bgColor"];
}

export const CopyButton = ({
isDisable,
value,
size = "sm",
copyLabel,
hasIcon = true,
variant = "outline-info",
buttonText = "Copy",
tooltipBgColor,
...buttonProps
}: CopyButtonProps) => (
<CopyTemplate
value={value}
copyLabel={copyLabel}
tooltipBgColor={tooltipBgColor}
triggerElement={
<Button
isDisabled={isDisable}
variant="outline-info"
variant={variant}
size={size}
float="right"
onClick={() => AmpTrack(AmpEvent.USE_COPY_BUTTON)}
leftIcon={<CopyIcon boxSize="4" />}
leftIcon={hasIcon ? <CopyIcon boxSize="4" /> : undefined}
{...buttonProps}
>
Copy
{buttonText}
</Button>
}
/>
Expand Down
5 changes: 4 additions & 1 deletion src/lib/components/copy/CopyTemplate.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import type { TooltipProps } from "@chakra-ui/react";
import { Box, Tooltip, useClipboard } from "@chakra-ui/react";
import { useEffect } from "react";

interface CopyTemplateProps {
value: string;
copyLabel?: string;
triggerElement: JSX.Element;
tooltipBgColor?: TooltipProps["bgColor"];
}

export const CopyTemplate = ({
value,
copyLabel = "Copied!",
triggerElement,
tooltipBgColor = "honeydew.darker",
}: CopyTemplateProps) => {
const { onCopy, hasCopied, setValue } = useClipboard(value);
useEffect(() => setValue(value), [value, setValue]);
Expand All @@ -22,7 +25,7 @@ export const CopyTemplate = ({
label={copyLabel}
placement="top"
arrowSize={8}
bg="honeydew.darker"
bgColor={tooltipBgColor}
>
<Box
onClick={(e) => {
Expand Down
44 changes: 33 additions & 11 deletions src/lib/components/modal/UnsupportedTokensModal.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ButtonProps } from "@chakra-ui/react";
import {
Modal,
ModalHeader,
Expand All @@ -22,7 +23,7 @@ import { MdAttachMoney } from "react-icons/md";
import { ExplorerLink } from "../ExplorerLink";
import { Copier } from "lib/components/copy";
import type { AddressReturnType } from "lib/hooks";
import { getAddressTypeByLength } from "lib/hooks";
import { useGetAddressType, getAddressTypeByLength } from "lib/hooks";
import type { BalanceWithAssetInfo, Balance, Token, U, Addr } from "lib/types";
import {
getTokenType,
Expand All @@ -32,22 +33,34 @@ import {

interface UnsupportedTokensModalProps {
unsupportedAssets: BalanceWithAssetInfo[];
address: Addr;
address?: Addr;
buttonProps?: ButtonProps;
}

interface UnsupportedTokenProps {
balance: Balance;
}

const getTokenTypeWithAddress = (
type: Balance["type"],
addrType: AddressReturnType
) => {
if (type) return getTokenType(type);
return addrType === "contract_address"
? getTokenType("cw20")
: getTokenType("native");
};

const UnsupportedToken = ({ balance }: UnsupportedTokenProps) => {
const getAddressType = useGetAddressType();
// TODO - Move this to utils
const [tokenLabel, tokenType] = useMemo(() => {
const label = getTokenLabel(balance.id);
const type = !balance.id.includes("/")
? getTokenType(balance.type)
? getTokenTypeWithAddress(balance.type, getAddressType(balance.id))
: getTokenType(balance.id.split("/")[0]);
return [label, type];
}, [balance]);
}, [balance, getAddressType]);

return (
<Flex
Expand Down Expand Up @@ -106,6 +119,7 @@ const unsupportedTokensContent = (addressType: AddressReturnType) => {
export const UnsupportedTokensModal = ({
unsupportedAssets,
address,
buttonProps,
}: UnsupportedTokensModalProps) => {
const { currentChainName } = useWallet();
const { isOpen, onOpen, onClose } = useDisclosure();
Expand All @@ -118,7 +132,13 @@ export const UnsupportedTokensModal = ({
return (
<>
<Flex onClick={onOpen}>
<Button variant="ghost" color="text.dark" mb={1} fontWeight={500}>
<Button
variant="ghost"
color="text.dark"
mb={1}
fontWeight={500}
{...buttonProps}
>
{`View ${unsupportedAssets.length} Unsupported Assets`}
</Button>
</Flex>
Expand All @@ -137,12 +157,14 @@ export const UnsupportedTokensModal = ({
<ModalCloseButton color="pebble.600" />
<ModalBody maxH="400px" overflow="overlay" pb={6}>
<Flex direction="column" gap={5}>
<Flex direction="row" gap={4}>
<Text variant="body2" fontWeight="700">
{content.header}
</Text>
<ExplorerLink value={address} type={addressType} />
</Flex>
{address && (
<Flex direction="row" gap={4}>
<Text variant="body2" fontWeight="700">
{content.header}
</Text>
<ExplorerLink value={address} type={addressType} />
</Flex>
)}
<Flex gap={3} direction="column">
{unsupportedAssets.map((asset) => (
<UnsupportedToken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Flex } from "@chakra-ui/react";

import { TxReceiptRender } from "lib/components/tx/receipt";
import { useGetAddressType } from "lib/hooks";
import { useAssetInfos } from "lib/services/assetService";
import type { TxReceipt } from "lib/types";

import type { TxMsgData } from ".";
Expand All @@ -14,7 +15,8 @@ interface TxMsgDetailsProps extends TxMsgData {

export const TxMsgDetails = ({ isExpand, ...txMsgData }: TxMsgDetailsProps) => {
const getAddressType = useGetAddressType();
const receipts = generateReceipts(txMsgData, getAddressType)
const assetInfos = useAssetInfos();
const receipts = generateReceipts(txMsgData, getAddressType, assetInfos)
.filter(Boolean)
.concat(
txMsgData.log
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { Flex, Grid } from "@chakra-ui/react";
import type { Coin } from "@cosmjs/stargate";
import { useState } from "react";

import { ShowMoreButton } from "lib/components/button";
import { UnsupportedTokensModal } from "lib/components/modal/UnsupportedTokensModal";
import { TokenCard } from "lib/components/TokenCard";
import type { AssetInfo, Option } from "lib/types";

type AssetObject = { [key: string]: AssetInfo };

interface CoinComponentProps<
T extends Coin | Coin[],
A extends Option<AssetObject> | AssetObject
> {
amount: T;
assetInfos: A;
}

const MultiCoin = ({
amount,
assetInfos,
}: CoinComponentProps<Coin[], AssetObject>) => {
const [supportedCoins, unsupportedCoins] = [
amount.filter((coin) => Boolean(assetInfos[coin.denom])),
amount.filter((coin) => !assetInfos[coin.denom]),
];
const [showMore, setShowMore] = useState(false);

const hasSupportedCoins = supportedCoins.length > 0;
return (
<Flex direction="column" w="full">
{hasSupportedCoins && (
<Grid gridGap={4} gridTemplateColumns="1fr 1fr">
{supportedCoins.slice(0, showMore ? undefined : 2).map((coin) => {
const assetInfo = assetInfos[coin.denom];
return (
<TokenCard
key={coin.denom}
userBalance={{
balance: {
amount: coin.amount,
id: assetInfo.id,
name: assetInfo.name,
precision: assetInfo.precision,
symbol: assetInfo.symbol,
type: assetInfo.type,
price: assetInfo.price,
},
assetInfo,
}}
/>
);
})}
</Grid>
)}
<Flex gap={2} mt={hasSupportedCoins ? 2 : 0}>
{supportedCoins.length > 2 && (
<ShowMoreButton
showMoreText="View All Assets"
showLessText="View Less Assets"
toggleShowMore={showMore}
setToggleShowMore={() => setShowMore(!showMore)}
/>
)}
{unsupportedCoins && (
<UnsupportedTokensModal
unsupportedAssets={unsupportedCoins.map((coin) => {
const assetInfo = assetInfos[coin.denom];
return {
balance: {
amount: coin.amount,
id: coin.denom,
precision: 0,
},
assetInfo,
};
})}
buttonProps={{ fontSize: "12px", mb: 0 }}
/>
)}
</Flex>
</Flex>
);
};
const SingleCoin = ({
amount,
assetInfos,
}: CoinComponentProps<Coin, AssetObject>) => {
const assetInfo = assetInfos[amount.denom];
return assetInfo ? (
<TokenCard
userBalance={{
balance: {
amount: amount.amount,
id: assetInfo.id,
name: assetInfo.name,
precision: assetInfo.precision,
symbol: assetInfo.symbol,
type: assetInfo.type,
price: assetInfo.price,
},
assetInfo,
}}
/>
) : (
<UnsupportedTokensModal
unsupportedAssets={[
{
balance: {
amount: amount.amount,
id: amount.denom,
precision: 0,
},
assetInfo,
},
]}
/>
);
};

export const CoinComponent = ({
amount,
assetInfos,
}: CoinComponentProps<Coin | Coin[], Option<AssetObject>>) => {
if (!assetInfos) return <>{JSON.stringify(amount)}</>;
return Array.isArray(amount) ? (
<MultiCoin amount={amount} assetInfos={assetInfos} />
) : (
<SingleCoin amount={amount} assetInfos={assetInfos} />
);
};
Loading

0 comments on commit 5af959b

Please sign in to comment.