Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create new token card and format mechanism #223

Merged
merged 6 commits into from
Feb 24, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

- [#223](https://github.com/alleslabs/celatone-frontend/pull/223) Newer version of token card and format mechanism
- [#218](https://github.com/alleslabs/celatone-frontend/pull/218) Add instantiated and admin contracts of an account
- [#192](https://github.com/alleslabs/celatone-frontend/pull/192) Add alternative sidebar with only icons
- [#210](https://github.com/alleslabs/celatone-frontend/pull/210) New design for token card, currently support price
Expand Down
90 changes: 90 additions & 0 deletions src/lib/components/TokenCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Badge, Flex, Image, Text, Tooltip } from "@chakra-ui/react";
import { useState } from "react";

import { Copier } from "lib/components/copy";
import { NAToken } from "lib/icon";
import type { BalanceWithAssetInfo, Token, U, USD } from "lib/types";
import {
calAssetValueWithPrecision,
formatPrice,
formatUTokenWithPrecision,
} from "lib/utils";

interface TokenCardProps {
userBalance: BalanceWithAssetInfo;
}

export const TokenCard = ({ userBalance }: TokenCardProps) => {
const [logoError, setLogoError] = useState(false);
const { symbol, price, amount, precision, id } = userBalance.balance;

return (
<Tooltip
hasArrow
label={`Token ID: ${id}`}
placement="top"
bg="honeydew.darker"
maxW="240px"
whiteSpace="pre-line"
textAlign="center"
>
<Flex
direction="column"
h="101px"
gap={2}
p={3}
background="pebble.900"
borderRadius="8px"
_hover={{
bgColor: "pebble.800",
"& .copy-button": { display: "flex" },
}}
>
<Flex
gap={1}
alignItems="center"
borderBottom="1px solid"
borderBottomColor="pebble.700"
pb={2}
>
{!logoError ? (
<Image
boxSize={6}
src={userBalance.assetInfo?.logo}
alt={symbol}
onError={() => setLogoError(true)}
/>
) : (
<NAToken />
)}
<Text variant="body2" className="ellipsis" maxW="91">
{symbol}
</Text>
<Badge variant="gray" ml="6px">
{price ? formatPrice(price as USD<number>) : "N/A"}
</Badge>
<Copier
value={id}
copyLabel="Token ID Copied!"
ml="1px"
display="none"
className="copy-button"
/>
</Flex>

<Flex direction="column">
<Text fontWeight="700" variant="body2">
{formatUTokenWithPrecision(amount as U<Token>, precision)}
</Text>
<Text variant="body3" color="grey.400">
{price
? `(${formatPrice(
calAssetValueWithPrecision(userBalance.balance)
)})`
: "N/A"}
</Text>
</Flex>
</Flex>
</Tooltip>
);
};
81 changes: 0 additions & 81 deletions src/lib/pages/contract-details/components/token/TokenCard.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { useMemo, useState } from "react";

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

import { TokenCard } from "./TokenCard";

interface TokenSectionProps {
balances: Option<BalanceWithAssetInfo[]>;
}
Expand Down
52 changes: 42 additions & 10 deletions src/lib/utils/formatter/token.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { BigSource } from "big.js";
import type { Big, BigSource } from "big.js";
import big from "big.js";

import type { Token, U, USD } from "lib/types";

const B = 1_000_000_000;

export const formatDemimal =
({
decimalPoints,
Expand Down Expand Up @@ -31,26 +33,56 @@ export const formatDemimal =
return (ii === "0" && num[0] === "-" ? "-" : "") + ii + dd;
};

const d2Formatter = formatDemimal({ decimalPoints: 2, delimiter: true });
const d6Formatter = formatDemimal({ decimalPoints: 6, delimiter: true });

export const toToken = (
uAmount: U<Token<BigSource>>,
precision: number
): Token<BigSource> =>
big(uAmount).div(big(10).pow(precision)) as Token<BigSource>;
): Token<Big> => big(uAmount).div(big(10).pow(precision)) as Token<Big>;

/**
* @remarks
* If token is more than or equal to 1 billion, should add postfix M and format to 2 decimal point
*
*/
export const formatUTokenWithPrecision = (
amount: U<Token<BigSource>>,
precision: number
): string => d6Formatter(toToken(amount, precision), "0");
): string => {
const token = toToken(amount, precision);
if (token.gte(B)) {
return `${formatDemimal({ decimalPoints: 2, delimiter: true })(
token.div(B),
"0.00"
)}B`;
}
return formatDemimal({ decimalPoints: precision, delimiter: true })(
token,
"0.00"
);
};

const d2Formatter = formatDemimal({ decimalPoints: 2, delimiter: true });
const d6Formatter = formatDemimal({ decimalPoints: 6, delimiter: true });

/**
* @remarks
* If the value is greater than or equal to 1, should return 2 decimal points else 6 decimal points
*
* Condition for price rendering
* $0 or >= $1 -> 2d
* < $1 -> 6d
* <$0.000001 -> <$0.000001
*/
export const formatPrice = (value: USD<BigSource>): string => {
const price = big(value);
return price.gte(1) ? d2Formatter(price, "0") : d6Formatter(price, "0");
const lowestThreshold = 0.000001;

const d2 = d2Formatter(price, "0.00");
const d6 = d6Formatter(price, "0.00");

if (price.eq(0) || price.gte(1)) {
return `$${d2}`;
}

if (price.lt(lowestThreshold)) {
return `<$${lowestThreshold}`;
}
return `$${d6}`;
};