Skip to content

Commit

Permalink
Merge pull request #636 from alleslabs/feat/cfe-24-api-v1-balances
Browse files Browse the repository at this point in the history
[after #634] feat: api v1 balances
  • Loading branch information
songwongtp committed Dec 1, 2023
2 parents 140efeb + 24b1e7d commit 97e3330
Show file tree
Hide file tree
Showing 43 changed files with 617 additions and 1,095 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Improvements

- [#636](https://github.com/alleslabs/celatone-frontend/pull/636) api v1 - balances
- [#641](https://github.com/alleslabs/celatone-frontend/pull/641) api v1 - recent txs list
- [#640](https://github.com/alleslabs/celatone-frontend/pull/640) api v1 - recent blocks list
- [#634](https://github.com/alleslabs/celatone-frontend/pull/634) api v1 - move pool info
Expand Down
4 changes: 2 additions & 2 deletions src/lib/app-provider/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ export enum CELATONE_QUERY_KEYS {
SIMULATE_FEE = "CELATONE_QUERY_SIMULATE_FEE",
SIMULATE_FEE_STORE_CODE = "CELATONE_QUERY_SIMULATE_FEE_STORE_CODE",
SIMULATE_FEE_STORE_CODE_PROPOSAL = "CELATONE_QUERY_SIMULATE_FEE_STORE_CODE_PROPOSAL",
// BALANCES
BALANCES = "CELATONE_QUERY_BALANCES",
// CONTRACT,CODE LCD
CODE_INFO = "CELATONE_QUERY_CODE_INFO",
CONTRACT_DETAIL_BY_CONTRACT_ADDRESS = "CELATONE_QUERY_CONTRACT_DETAIL_BY_CONTRACT_ADDRESS",
CONTRACT_CW2_INFO = "CELATONE_QUERY_CONTRACT_CW2_INFO",
CONTRACT_BALANCES_INFO = "CELATONE_QUERY_CONTRACT_BALANCES_INFO",
CONTRACT_INFO = "CELATONE_QUERY_CONTRACT_INFO",
CONTRACT_QUERY_CMDS = "CELATONE_QUERY_CONTRACT_QUERY_CMDS",
CONTRACT_QUERY = "CELATONE_QUERY_CONTRACT_QUERY",
CONTRACT_STATE = "CELATONE_QUERY_CONTRACT_STATE",
// ACCOUNT
ACCOUNT_BALANCES_INFO = "CELATONE_QUERY_ACCOUNT_BALANCES_INFO",
ACCOUNT_ID = "CELATONE_QUERY_ACCOUNT_ID",
ACCOUNT_TYPE = "CELATONE_QUERY_ACCOUNT_TYPE",
// ASSET
Expand Down
2 changes: 1 addition & 1 deletion src/lib/app-provider/hooks/useBaseApiRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const useBaseApiRoute = (
case "txs":
return `${api}/v1/${chain}/${currentChainId}/txs`;
case "balances":
return `${api}/balances/${chain}/${currentChainId}`;
return `${api}/v1/${chain}/${currentChainId}/balances`;
case "assets":
return `${api}/v1/${chain}/${currentChainId}/assets`;
case "blocks":
Expand Down
58 changes: 17 additions & 41 deletions src/lib/components/modal/UnsupportedTokensModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,40 @@ import {
Button,
Heading,
} from "@chakra-ui/react";
import { useMemo } from "react";

import { ExplorerLink } from "../ExplorerLink";
import type { IconKeys } from "../icon";
import { CustomIcon } from "../icon";
import { Tooltip } from "../Tooltip";
import { trackUseUnsupportedToken } from "lib/amplitude";
import { useGetAddressType, useGetAddressTypeByLength } from "lib/app-provider";
import { useGetAddressType } from "lib/app-provider";
import type { AddressReturnType } from "lib/app-provider";
import { Copier } from "lib/components/copy";
import type { BalanceWithAssetInfo, Balance, Token, U, Addr } from "lib/types";
import type { Addr, TokenWithValue } from "lib/types";
import {
getTokenType,
getTokenLabel,
formatUTokenWithPrecision,
} from "lib/utils";

interface UnsupportedTokensModalProps {
unsupportedAssets: BalanceWithAssetInfo[];
unsupportedAssets: TokenWithValue[];
address?: Addr;
addressType?: AddressReturnType;
buttonProps?: ButtonProps;
amptrackSection?: string;
}

interface UnsupportedTokenProps {
balance: Balance;
}

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

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

return (
<Flex
Expand All @@ -84,16 +70,16 @@ const UnsupportedToken = ({ balance }: UnsupportedTokenProps) => {
>
<Flex gap={1} alignItems="center">
<Text variant="body2" className="ellipsis">
{tokenLabel}
{getTokenLabel(token.denom, token.symbol)}
</Text>
<Tooltip label={`Token ID: ${balance.id}`} maxW="500px">
<Tooltip label={`Token ID: ${token.denom}`} maxW="500px">
<Flex cursor="pointer" className="info" visibility="hidden">
<CustomIcon name="info-circle" boxSize={3} color="gray.600" />
</Flex>
</Tooltip>
<Copier
type="unsupported_asset"
value={balance.id}
value={token.denom}
copyLabel="Token ID Copied!"
ml={0}
display="none"
Expand All @@ -105,11 +91,7 @@ const UnsupportedToken = ({ balance }: UnsupportedTokenProps) => {
</Text>
</Flex>
<Text variant="body2" fontWeight="900">
{formatUTokenWithPrecision(
balance.amount as U<Token>,
balance.precision,
false
)}
{formatUTokenWithPrecision(token.amount, token.precision ?? 0, false)}
</Text>
</Flex>
);
Expand All @@ -128,7 +110,7 @@ const unsupportedTokensContent = (
case "user_address": {
return {
icon: "assets-solid",
header: "Wallet Address",
header: "Account Address",
};
}
default:
Expand All @@ -142,17 +124,14 @@ const unsupportedTokensContent = (
export const UnsupportedTokensModal = ({
unsupportedAssets,
address,
addressType = "invalid_address",
buttonProps,
amptrackSection,
}: UnsupportedTokensModalProps) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const getAddressTypeByLength = useGetAddressTypeByLength();

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

const addressType = getAddressTypeByLength(address);
const content = unsupportedTokensContent(addressType);

return (
<>
<Button
Expand Down Expand Up @@ -191,10 +170,7 @@ export const UnsupportedTokensModal = ({
)}
<Flex gap={3} direction="column">
{unsupportedAssets.map((asset) => (
<UnsupportedToken
balance={asset.balance}
key={asset.balance.id}
/>
<UnsupportedToken key={asset.denom} token={asset} />
))}
</Flex>
</Flex>
Expand Down
2 changes: 0 additions & 2 deletions src/lib/components/pagination/PageDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Flex, Select, Text } from "@chakra-ui/react";
import type { ChangeEvent } from "react";

import { CustomIcon } from "../icon";
import { AmpEvent, track } from "lib/amplitude";

interface PageDetailProps {
Expand Down Expand Up @@ -49,7 +48,6 @@ export const PageDetail = ({
<option value="20">20</option>
<option value="50">50</option>
<option value="100">100</option>
<CustomIcon name="chevron-down" color="gray.600" />
</Select>
</Flex>
<Text variant="body3" minW="fit-content" ml={7}>
Expand Down
118 changes: 54 additions & 64 deletions src/lib/components/token/TokenCard.tsx
Original file line number Diff line number Diff line change
@@ -1,87 +1,77 @@
import type { FlexProps } from "@chakra-ui/react";
import { Badge, Flex, Text } from "@chakra-ui/react";
import { isUndefined } from "lodash";

import { Copier } from "../copy";
import { Tooltip } from "../Tooltip";
import type { BalanceWithAssetInfo, Token, U, USD } from "lib/types";
import type { TokenWithValue } from "lib/types";
import {
calAssetValueWithPrecision,
formatPrice,
formatUTokenWithPrecision,
getTokenLabel,
} from "lib/utils";

import { TokenImageRender } from "./TokenImageRender";

interface TokenCardProps extends FlexProps {
userBalance: BalanceWithAssetInfo;
token: TokenWithValue;
amptrackSection?: string;
}

export const TokenCard = ({
userBalance,
token,
amptrackSection,
...cardProps
}: TokenCardProps) => {
const { symbol, price, amount, precision, id } = userBalance.balance;
const priceExist = price !== undefined;
return (
<Tooltip label={`Token ID: ${id}`} maxW="240px" textAlign="center">
}: TokenCardProps) => (
<Tooltip label={`Token ID: ${token.denom}`} maxW="240px" textAlign="center">
<Flex
className="copier-wrapper"
direction="column"
minH="101px"
gap={2}
p={3}
background="gray.900"
borderRadius="8px"
{...cardProps}
>
<Flex
className="copier-wrapper"
direction="column"
minH="101px"
gap={2}
p={3}
background="gray.900"
borderRadius="8px"
{...cardProps}
gap={1}
alignItems="center"
borderBottom="1px solid"
borderBottomColor="gray.700"
pb={2}
>
<Flex
gap={1}
alignItems="center"
borderBottom="1px solid"
borderBottomColor="gray.700"
pb={2}
>
<TokenImageRender
logo={userBalance.logo ?? userBalance.assetInfo?.logo}
alt={symbol}
boxSize={6}
/>
<Text
variant="body2"
className="ellipsis"
maxW="91"
fontWeight="bold"
>
{symbol}
</Text>
<Badge variant="gray" ml={2}>
{priceExist ? formatPrice(price as USD<number>) : "N/A"}
</Badge>
<Copier
type={priceExist ? "supported_asset" : "unsupported_asset"}
value={id}
copyLabel="Token ID Copied!"
display={{ base: "flex", md: "none" }}
ml={1}
amptrackSection={amptrackSection}
/>
</Flex>
<TokenImageRender
logo={token.logo}
alt={getTokenLabel(token.denom, token.symbol)}
boxSize={6}
/>
<Text variant="body2" className="ellipsis" maxW="91" fontWeight="bold">
{token.symbol}
</Text>
<Badge variant="gray" ml={2}>
{!isUndefined(token.price) ? formatPrice(token.price) : "N/A"}
</Badge>
<Copier
type={
!isUndefined(token.price) ? "supported_asset" : "unsupported_asset"
}
value={token.denom}
copyLabel="Token ID Copied!"
display={{ base: "flex", md: "none" }}
ml={1}
amptrackSection={amptrackSection}
/>
</Flex>

<Flex direction="column">
<Text fontWeight={700} variant="body2">
{formatUTokenWithPrecision(amount as U<Token>, precision, false)}
</Text>
<Text variant="body3" color="text.dark">
{priceExist
? `(${formatPrice(
calAssetValueWithPrecision(userBalance.balance)
)})`
: "N/A"}
</Text>
</Flex>
<Flex direction="column">
<Text fontWeight={700} variant="body2">
{formatUTokenWithPrecision(token.amount, token.precision ?? 0, false)}
</Text>
<Text variant="body3" color="text.dark">
{!isUndefined(token.value) ? `(${formatPrice(token.value)})` : "N/A"}
</Text>
</Flex>
</Tooltip>
);
};
</Flex>
</Tooltip>
);
48 changes: 48 additions & 0 deletions src/lib/pages/account-details/components/asset/AssetCta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Button, Flex } from "@chakra-ui/react";

import { trackUseViewJSON } from "lib/amplitude";
import { CustomIcon } from "lib/components/icon";
import { UnsupportedTokensModal } from "lib/components/modal";
import { useOpenAssetTab } from "lib/hooks";
import type { Addr, TokenWithValue } from "lib/types";

interface AssetCtaProps {
unsupportedAssets: TokenWithValue[];
totalAsset: number;
address: Addr;
}

export const AssetCta = ({
unsupportedAssets,
totalAsset,
address,
}: AssetCtaProps) => {
const openAssetTab = useOpenAssetTab();

return (
<Flex
w={{ base: "full", md: "auto" }}
justify="center"
mb={{ base: 4, md: 0 }}
>
{totalAsset > 0 && (
<Button
variant="ghost-gray"
size="sm"
rightIcon={<CustomIcon name="launch" boxSize={3} color="text.dark" />}
onClick={() => {
trackUseViewJSON("account_details_page_assets");
openAssetTab(address);
}}
>
View in JSON
</Button>
)}
<UnsupportedTokensModal
unsupportedAssets={unsupportedAssets}
address={address}
addressType="user_address"
/>
</Flex>
);
};
Loading

2 comments on commit 97e3330

@vercel
Copy link

@vercel vercel bot commented on 97e3330 Dec 1, 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 97e3330 Dec 1, 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.