diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f43cf949..2995798ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#94](https://github.com/alleslabs/celatone-frontend/pull/94) Add unsupported assets in contract details page - [#72](https://github.com/alleslabs/celatone-frontend/pull/72) Fix general wording and grammar - [#110](https://github.com/alleslabs/celatone-frontend/pull/110) Fix proposal detail rendering - [#109](https://github.com/alleslabs/celatone-frontend/pull/109) Fix incorrect rendering of zero value badges diff --git a/package.json b/package.json index 844bcb827..01d1be7f6 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,6 @@ "next": "^13.0.0", "next-pwa": "^5.6.0", "next-seo": "^5.8.0", - "numeral": "^2.0.6", "react": "^18.2.0", "react-ace": "^10.1.0", "react-dom": "^18.2.0", diff --git a/src/lib/components/modal/UnsupportedTokensModal.tsx b/src/lib/components/modal/UnsupportedTokensModal.tsx new file mode 100644 index 000000000..a260cd59f --- /dev/null +++ b/src/lib/components/modal/UnsupportedTokensModal.tsx @@ -0,0 +1,131 @@ +import { + Modal, + ModalHeader, + Flex, + Icon, + Text, + ModalOverlay, + ModalContent, + ModalCloseButton, + useDisclosure, + ModalBody, + Button, + Heading, + Box, +} from "@chakra-ui/react"; +import router from "next/router"; +import { useMemo } from "react"; +import { MdAttachMoney } from "react-icons/md"; + +import { Copier } from "../Copier"; +import { ExplorerLink } from "../ExplorerLink"; +import type { BalanceWithAssetInfo, Balance } from "lib/types"; +import { + getFirstQueryParam, + getTokenType, + truncate, + formatToken, +} from "lib/utils"; + +interface UnsupportedTokensModalProps { + unsupportedAssets: BalanceWithAssetInfo[]; +} + +interface UnsupportedTokenProps { + balance: Balance; +} + +const UnsupportedToken = ({ balance }: UnsupportedTokenProps) => { + // TODO - Move this to utils + const [tokenLabel, tokenType] = useMemo(() => { + const splitId = balance.id.split("/"); + const type = !balance.id.includes("/") + ? getTokenType(balance.type) + : getTokenType(splitId[0]); + if (splitId[1]) { + splitId[1] = truncate(splitId[1]); + } + const label = splitId.length === 1 ? balance.id : splitId.join("/"); + return [label, type]; + }, [balance]); + + return ( + + + + + {tokenLabel} + + + + + + + {`${tokenType} Token`} + + + + {formatToken(balance.amount, balance.precision)} + + + ); +}; + +export const UnsupportedTokensModal = ({ + unsupportedAssets, +}: UnsupportedTokensModalProps) => { + const contractAddress = getFirstQueryParam(router.query.contractAddress); + + const { isOpen, onOpen, onClose } = useDisclosure(); + + if (unsupportedAssets.length === 0) return null; + + return ( + <> + + + + + + + + + + + Unsupported Assets + + + + + + + + + + Contract Address + + + + + {unsupportedAssets.map((asset) => ( + + ))} + + + + + + + ); +}; diff --git a/src/lib/pages/contract-details/components/token/TokenSection.tsx b/src/lib/pages/contract-details/components/token/TokenSection.tsx index a467b2a4b..3b19ab29e 100644 --- a/src/lib/pages/contract-details/components/token/TokenSection.tsx +++ b/src/lib/pages/contract-details/components/token/TokenSection.tsx @@ -1,7 +1,8 @@ -import { Grid, Text } from "@chakra-ui/react"; +import { Flex, Grid, Text } from "@chakra-ui/react"; import { useMemo, useState } from "react"; import { ShowMoreButton } from "lib/components/button"; +import { UnsupportedTokensModal } from "lib/components/modal/UnsupportedTokensModal"; import type { BalanceWithAssetInfo, Option } from "lib/types"; import { TokenCard } from "./TokenCard"; @@ -11,37 +12,55 @@ interface TokenSectionProps { } export const TokenSection = ({ balances }: TokenSectionProps) => { const [showMore, setShowMore] = useState(false); + const unsupportedAssets = useMemo( + () => balances?.filter((balance) => !balance.assetInfo) ?? [], + [balances] + ); + const supportedAssets = useMemo( () => balances?.filter((balance) => balance.assetInfo) ?? [], [balances] ); - if (!balances?.length) + const renderContext = () => { + if (!balances?.length) { + return ( + + This contract does not hold any assets + + ); + } return ( - - This contract does not hold any assets - + <> + + {supportedAssets.map((balance, index) => { + if (!showMore && index >= 4) { + return null; + } + return ; + })} + + {supportedAssets.length > 4 && ( + setShowMore(!showMore)} + /> + )} + ); + }; return ( <> - {/* TODO - Implement unsupported assets */} - - {supportedAssets.map((balance, index) => { - if (!showMore && index >= 4) { - return null; - } - return ; - })} - - {supportedAssets.length > 4 && ( - setShowMore(!showMore)} - /> - )} + + + Assets + + + + {renderContext()} ); }; diff --git a/src/lib/pages/contract-details/index.tsx b/src/lib/pages/contract-details/index.tsx index 7831840a6..393fe5a6a 100644 --- a/src/lib/pages/contract-details/index.tsx +++ b/src/lib/pages/contract-details/index.tsx @@ -5,7 +5,6 @@ import { Tabs, TabPanels, TabPanel, - Text, } from "@chakra-ui/react"; import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; @@ -58,9 +57,6 @@ const ContractDetailsBody = observer( {/* Tokens Section */} - - Assets - {/* Contract Description Section */} diff --git a/src/lib/utils/formatter/index.ts b/src/lib/utils/formatter/index.ts index 186256c30..307a42162 100644 --- a/src/lib/utils/formatter/index.ts +++ b/src/lib/utils/formatter/index.ts @@ -4,3 +4,5 @@ export * from "./denom"; export * from "./camelToSnake"; export * from "./snakeToCamel"; export * from "./formatBalanceWithDenom"; +export * from "./tokenType"; +export * from "./token"; diff --git a/src/lib/utils/formatter/token.ts b/src/lib/utils/formatter/token.ts index d95254211..d38511a10 100644 --- a/src/lib/utils/formatter/token.ts +++ b/src/lib/utils/formatter/token.ts @@ -1,6 +1,5 @@ import type { BigSource } from "big.js"; import big from "big.js"; -import numeral from "numeral"; export const formatDemimal = ({ @@ -23,8 +22,9 @@ export const formatDemimal = if (num === "NaN") return fallbackValue; const [i, d] = num.split("."); + const thousands = /\B(?=(\d{3})+(?!\d))/g; - const ii = delimiter ? numeral(i).format("0,0") : i; + const ii = delimiter ? i.replace(thousands, ",") : i; const dd = d ? `.${d}` : ""; return (ii === "0" && num[0] === "-" ? "-" : "") + ii + dd; diff --git a/src/lib/utils/formatter/tokenType.ts b/src/lib/utils/formatter/tokenType.ts new file mode 100644 index 000000000..3a829984c --- /dev/null +++ b/src/lib/utils/formatter/tokenType.ts @@ -0,0 +1,9 @@ +export const getTokenType = (type: string) => { + switch (type.toLowerCase()) { + case "ibc": + case "cw20": + return type.toUpperCase(); + default: + return type.charAt(0).toUpperCase() + type.slice(1).toLowerCase(); + } +}; diff --git a/yarn.lock b/yarn.lock index 54f70b8f4..17be17990 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8331,11 +8331,6 @@ nullthrows@^1.1.1: resolved "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz" integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== -numeral@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506" - integrity sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA== - object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"