Skip to content

Commit

Permalink
Merge pull request #94 from alleslabs/feat/unsupported-tokens
Browse files Browse the repository at this point in the history
feat(components): implement unsupported assets in contract details page
  • Loading branch information
tansawit committed Jan 20, 2023
2 parents 905517f + d91d58d commit 3a83ef1
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 34 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
131 changes: 131 additions & 0 deletions src/lib/components/modal/UnsupportedTokensModal.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Flex
borderRadius="8px"
bg="gray.900"
justify="space-between"
p={4}
role="group"
>
<Flex direction="column" maxW="70%">
<Flex direction="row" alignItems="center">
<Text variant="body2" className="ellipsis">
{tokenLabel}
</Text>
<Box _groupHover={{ display: "flex" }} display="none">
<Copier value={balance.id} />
</Box>
</Flex>
<Text variant="body3" color="text.dark">
{`${tokenType} Token`}
</Text>
</Flex>
<Text variant="body2" fontWeight="900">
{formatToken(balance.amount, balance.precision)}
</Text>
</Flex>
);
};

export const UnsupportedTokensModal = ({
unsupportedAssets,
}: UnsupportedTokensModalProps) => {
const contractAddress = getFirstQueryParam(router.query.contractAddress);

const { isOpen, onOpen, onClose } = useDisclosure();

if (unsupportedAssets.length === 0) return null;

return (
<>
<Flex onClick={onOpen}>
<Button variant="ghost" color="text.dark" mb={1} fontWeight={500}>
{`View ${unsupportedAssets.length} Unsupported Assets`}
</Button>
</Flex>
<Modal isOpen={isOpen} onClose={onClose} isCentered>
<ModalOverlay />
<ModalContent w="700px">
<ModalHeader>
<Flex w="full" direction="row" alignItems="center" gap={2} pt={1}>
<Icon as={MdAttachMoney} boxSize={5} color="gray.600" />
<Heading variant="h5" as="h5">
Unsupported Assets
</Heading>
</Flex>
</ModalHeader>

<ModalCloseButton color="gray.600" />
<ModalBody maxH="400px" overflow="overlay">
<Flex direction="column" gap={5}>
<Flex direction="row" gap={4}>
<Text variant="body2" fontWeight="700">
Contract Address
</Text>
<ExplorerLink value={contractAddress} type="contract_address" />
</Flex>
<Flex gap={2} direction="column">
{unsupportedAssets.map((asset) => (
<UnsupportedToken
balance={asset.balance}
key={asset.balance.id}
/>
))}
</Flex>
</Flex>
</ModalBody>
</ModalContent>
</Modal>
</>
);
};
63 changes: 41 additions & 22 deletions src/lib/pages/contract-details/components/token/TokenSection.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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 (
<Text variant="body2" color="text.dark" mb={1} fontWeight={500}>
This contract does not hold any assets
</Text>
);
}
return (
<Text variant="body2" color="text.dark" mb={1} fontWeight={500}>
This contract does not hold any assets
</Text>
<>
<Grid gridGap={4} gridTemplateColumns="repeat(4, 1fr)">
{supportedAssets.map((balance, index) => {
if (!showMore && index >= 4) {
return null;
}
return <TokenCard key={balance.balance.id} userBalance={balance} />;
})}
</Grid>
{supportedAssets.length > 4 && (
<ShowMoreButton
showMoreText="View All Assets"
showLessText="View Less Assets"
toggleShowMore={showMore}
setToggleShowMore={() => setShowMore(!showMore)}
/>
)}
</>
);
};

return (
<>
{/* TODO - Implement unsupported assets */}
<Grid gridGap={4} gridTemplateColumns="repeat(4, 1fr)">
{supportedAssets.map((balance, index) => {
if (!showMore && index >= 4) {
return null;
}
return <TokenCard key={balance.balance.id} userBalance={balance} />;
})}
</Grid>
{supportedAssets.length > 4 && (
<ShowMoreButton
showMoreText="View All Assets"
showLessText="View Less Assets"
toggleShowMore={showMore}
setToggleShowMore={() => setShowMore(!showMore)}
/>
)}
<Flex justify="space-between">
<Text variant="body2" color="text.dark" mb={1} fontWeight={500}>
Assets
</Text>
<UnsupportedTokensModal unsupportedAssets={unsupportedAssets} />
</Flex>
{renderContext()}
</>
);
};
4 changes: 0 additions & 4 deletions src/lib/pages/contract-details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
Tabs,
TabPanels,
TabPanel,
Text,
} from "@chakra-ui/react";
import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
Expand Down Expand Up @@ -58,9 +57,6 @@ const ContractDetailsBody = observer(
<ContractTop contractData={contractData} />
{/* Tokens Section */}
<Flex direction="column">
<Text variant="body2" color="text.dark" mb={1} fontWeight={500}>
Assets
</Text>
<TokenSection balances={contractData.balances} />
</Flex>
{/* Contract Description Section */}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/utils/formatter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export * from "./denom";
export * from "./camelToSnake";
export * from "./snakeToCamel";
export * from "./formatBalanceWithDenom";
export * from "./tokenType";
export * from "./token";
4 changes: 2 additions & 2 deletions src/lib/utils/formatter/token.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { BigSource } from "big.js";
import big from "big.js";
import numeral from "numeral";

export const formatDemimal =
({
Expand All @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions src/lib/utils/formatter/tokenType.ts
Original file line number Diff line number Diff line change
@@ -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();
}
};
5 changes: 0 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

3 comments on commit 3a83ef1

@vercel
Copy link

@vercel vercel bot commented on 3a83ef1 Jan 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 3a83ef1 Jan 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 3a83ef1 Jan 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.