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"