chore: updating nft numbers (#7351)
* format price impact * format price * adding confirm swap modal * removing export * adding export back * half of test functions done * format numbers tests * formatting * making numberFormat local * making formatCurrencyAmount internal * price impact * formatSlippage * formatTickPrice * formatNumberOrString * formatFiatPrice * removing formatPreciseFloat * formatReviewSwapCurrencyAmount * correct active currency * explore table * deleting formatTickPrice * fixing explore table * nft assset details * removing all instancees of ethnumberstandardformatter * removing format wei impls * explore table * collectino stats * removing almost everything from nft/numbers * filter button * final nft fixes * removing put commas * explore page * listing page * extraneous functions * responding to comments * formatEhter * updating formatter names * dep array * comments --------- Co-authored-by: John Short <john.short@CORN-Jack-899.local>
This commit is contained in:
parent
802d56231a
commit
bd30721989
@ -8,10 +8,10 @@ import { NftCard } from 'nft/components/card'
|
|||||||
import { detailsHref } from 'nft/components/card/utils'
|
import { detailsHref } from 'nft/components/card/utils'
|
||||||
import { VerifiedIcon } from 'nft/components/icons'
|
import { VerifiedIcon } from 'nft/components/icons'
|
||||||
import { WalletAsset } from 'nft/types'
|
import { WalletAsset } from 'nft/types'
|
||||||
import { floorFormatter } from 'nft/utils'
|
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
const FloorPrice = styled(Row)`
|
const FloorPrice = styled(Row)`
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@ -83,6 +83,8 @@ export function NFT({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function NFTDetails({ asset }: { asset: WalletAsset }) {
|
function NFTDetails({ asset }: { asset: WalletAsset }) {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box overflow="hidden" width="full" flexWrap="nowrap">
|
<Box overflow="hidden" width="full" flexWrap="nowrap">
|
||||||
<Row gap="4px">
|
<Row gap="4px">
|
||||||
@ -91,7 +93,9 @@ function NFTDetails({ asset }: { asset: WalletAsset }) {
|
|||||||
</Row>
|
</Row>
|
||||||
<FloorPrice>
|
<FloorPrice>
|
||||||
<ThemedText.BodySmall color="neutral2">
|
<ThemedText.BodySmall color="neutral2">
|
||||||
{asset.floorPrice ? `${floorFormatter(asset.floorPrice)} ETH` : ' '}
|
{asset.floorPrice
|
||||||
|
? `${formatNumberOrString({ input: asset.floorPrice, type: NumberType.NFTTokenFloorPrice })} ETH`
|
||||||
|
: ' '}
|
||||||
</ThemedText.BodySmall>
|
</ThemedText.BodySmall>
|
||||||
</FloorPrice>
|
</FloorPrice>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -13,13 +13,11 @@ import { Column, Row } from 'nft/components/Flex'
|
|||||||
import { VerifiedIcon } from 'nft/components/icons'
|
import { VerifiedIcon } from 'nft/components/icons'
|
||||||
import { vars } from 'nft/css/sprinkles.css'
|
import { vars } from 'nft/css/sprinkles.css'
|
||||||
import { GenieCollection } from 'nft/types'
|
import { GenieCollection } from 'nft/types'
|
||||||
import { ethNumberStandardFormatter } from 'nft/utils/currency'
|
|
||||||
import { putCommas } from 'nft/utils/putCommas'
|
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
import { useFormatter } from 'utils/formatNumbers'
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import { DeltaArrow, DeltaText } from '../Tokens/TokenDetails/Delta'
|
import { DeltaArrow, DeltaText } from '../Tokens/TokenDetails/Delta'
|
||||||
import { useAddRecentlySearchedAsset } from './RecentlySearchedAssets'
|
import { useAddRecentlySearchedAsset } from './RecentlySearchedAssets'
|
||||||
@ -49,6 +47,8 @@ export const CollectionRow = ({
|
|||||||
index,
|
index,
|
||||||
eventProperties,
|
eventProperties,
|
||||||
}: CollectionRowProps) => {
|
}: CollectionRowProps) => {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
|
|
||||||
const [brokenImage, setBrokenImage] = useState(false)
|
const [brokenImage, setBrokenImage] = useState(false)
|
||||||
const [loaded, setLoaded] = useState(false)
|
const [loaded, setLoaded] = useState(false)
|
||||||
|
|
||||||
@ -102,13 +102,17 @@ export const CollectionRow = ({
|
|||||||
<Box className={styles.primaryText}>{collection.name}</Box>
|
<Box className={styles.primaryText}>{collection.name}</Box>
|
||||||
{collection.isVerified && <VerifiedIcon className={styles.suggestionIcon} />}
|
{collection.isVerified && <VerifiedIcon className={styles.suggestionIcon} />}
|
||||||
</Row>
|
</Row>
|
||||||
<Box className={styles.secondaryText}>{putCommas(collection?.stats?.total_supply ?? 0)} items</Box>
|
<Box className={styles.secondaryText}>
|
||||||
|
{formatNumberOrString({ input: collection?.stats?.total_supply, type: NumberType.WholeNumber })} items
|
||||||
|
</Box>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
{collection.stats?.floor_price ? (
|
{collection.stats?.floor_price ? (
|
||||||
<Column className={styles.suggestionSecondaryContainer}>
|
<Column className={styles.suggestionSecondaryContainer}>
|
||||||
<Row gap="4">
|
<Row gap="4">
|
||||||
<Box className={styles.primaryText}>{ethNumberStandardFormatter(collection.stats?.floor_price)} ETH</Box>
|
<Box className={styles.primaryText}>
|
||||||
|
{formatNumberOrString({ input: collection.stats?.floor_price, type: NumberType.NFTToken })} ETH
|
||||||
|
</Box>
|
||||||
</Row>
|
</Row>
|
||||||
<Box className={styles.secondaryText}>Floor</Box>
|
<Box className={styles.secondaryText}>Floor</Box>
|
||||||
</Column>
|
</Column>
|
||||||
|
@ -31,12 +31,12 @@ import { useSubscribeTransactionState } from 'nft/hooks/useSubscribeTransactionS
|
|||||||
import { useTokenInput } from 'nft/hooks/useTokenInput'
|
import { useTokenInput } from 'nft/hooks/useTokenInput'
|
||||||
import { useWalletBalance } from 'nft/hooks/useWalletBalance'
|
import { useWalletBalance } from 'nft/hooks/useWalletBalance'
|
||||||
import { BagStatus } from 'nft/types'
|
import { BagStatus } from 'nft/types'
|
||||||
import { ethNumberStandardFormatter, formatWeiToDecimal } from 'nft/utils'
|
|
||||||
import { PropsWithChildren, useEffect, useMemo, useState } from 'react'
|
import { PropsWithChildren, useEffect, useMemo, useState } from 'react'
|
||||||
import { AlertTriangle, ChevronDown } from 'react-feather'
|
import { AlertTriangle, ChevronDown } from 'react-feather'
|
||||||
import { InterfaceTrade, TradeFillType, TradeState } from 'state/routing/types'
|
import { InterfaceTrade, TradeFillType, TradeState } from 'state/routing/types'
|
||||||
import styled, { useTheme } from 'styled-components'
|
import styled, { useTheme } from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import { BuyButtonStateData, BuyButtonStates, getBuyButtonStateData } from './ButtonStates'
|
import { BuyButtonStateData, BuyButtonStates, getBuyButtonStateData } from './ButtonStates'
|
||||||
|
|
||||||
@ -189,10 +189,12 @@ const InputCurrencyValue = ({
|
|||||||
tradeState: TradeState
|
tradeState: TradeState
|
||||||
trade?: InterfaceTrade
|
trade?: InterfaceTrade
|
||||||
}) => {
|
}) => {
|
||||||
|
const { formatEther, formatNumberOrString } = useFormatter()
|
||||||
|
|
||||||
if (!usingPayWithAnyToken) {
|
if (!usingPayWithAnyToken) {
|
||||||
return (
|
return (
|
||||||
<ThemedText.BodyPrimary lineHeight="20px" fontWeight="535">
|
<ThemedText.BodyPrimary lineHeight="20px" fontWeight="535">
|
||||||
{formatWeiToDecimal(totalEthPrice.toString())}
|
{formatEther({ input: totalEthPrice.toString(), type: NumberType.NFTToken })}
|
||||||
{activeCurrency?.symbol ?? 'ETH'}
|
{activeCurrency?.symbol ?? 'ETH'}
|
||||||
</ThemedText.BodyPrimary>
|
</ThemedText.BodyPrimary>
|
||||||
)
|
)
|
||||||
@ -208,7 +210,7 @@ const InputCurrencyValue = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ValueText color={tradeState === TradeState.LOADING ? 'neutral3' : 'neutral1'}>
|
<ValueText color={tradeState === TradeState.LOADING ? 'neutral3' : 'neutral1'}>
|
||||||
{ethNumberStandardFormatter(trade?.inputAmount.toExact())}
|
{formatNumberOrString({ input: trade?.inputAmount.toExact(), type: NumberType.NFTToken })}
|
||||||
</ValueText>
|
</ValueText>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -224,6 +226,8 @@ const FiatValue = ({
|
|||||||
tradeState: TradeState
|
tradeState: TradeState
|
||||||
usingPayWithAnyToken: boolean
|
usingPayWithAnyToken: boolean
|
||||||
}) => {
|
}) => {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
|
|
||||||
if (!usdcValue) {
|
if (!usdcValue) {
|
||||||
if (usingPayWithAnyToken && (tradeState === TradeState.INVALID || tradeState === TradeState.NO_ROUTE_FOUND)) {
|
if (usingPayWithAnyToken && (tradeState === TradeState.INVALID || tradeState === TradeState.NO_ROUTE_FOUND)) {
|
||||||
return null
|
return null
|
||||||
@ -247,7 +251,7 @@ const FiatValue = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<ThemedText.BodySmall color="neutral3" lineHeight="20px">
|
<ThemedText.BodySmall color="neutral3" lineHeight="20px">
|
||||||
{`${ethNumberStandardFormatter(usdcValue?.toExact(), true)}`}
|
{`${formatNumberOrString({ input: usdcValue?.toExact(), type: NumberType.FiatNFTToken })}`}
|
||||||
</ThemedText.BodySmall>
|
</ThemedText.BodySmall>
|
||||||
</PriceImpactContainer>
|
</PriceImpactContainer>
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { BigNumber } from '@ethersproject/bignumber'
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
import { formatEther } from '@ethersproject/units'
|
import { formatEther as ethersFormatEther } from '@ethersproject/units'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button'
|
import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button'
|
||||||
import { TimedLoader } from 'nft/components/bag/TimedLoader'
|
import { TimedLoader } from 'nft/components/bag/TimedLoader'
|
||||||
@ -18,10 +18,11 @@ import {
|
|||||||
import { bodySmall } from 'nft/css/common.css'
|
import { bodySmall } from 'nft/css/common.css'
|
||||||
import { loadingBlock } from 'nft/css/loading.css'
|
import { loadingBlock } from 'nft/css/loading.css'
|
||||||
import { GenieAsset, UpdatedGenieAsset } from 'nft/types'
|
import { GenieAsset, UpdatedGenieAsset } from 'nft/types'
|
||||||
import { ethNumberStandardFormatter, formatWeiToDecimal, getAssetHref } from 'nft/utils'
|
import { getAssetHref } from 'nft/utils'
|
||||||
import { MouseEvent, useCallback, useEffect, useReducer, useState } from 'react'
|
import { MouseEvent, useCallback, useEffect, useReducer, useState } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import * as styles from './BagRow.css'
|
import * as styles from './BagRow.css'
|
||||||
|
|
||||||
@ -90,6 +91,7 @@ interface BagRowProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const BagRow = ({ asset, usdPrice, removeAsset, showRemove, grayscale, isMobile }: BagRowProps) => {
|
export const BagRow = ({ asset, usdPrice, removeAsset, showRemove, grayscale, isMobile }: BagRowProps) => {
|
||||||
|
const { formatEther, formatNumberOrString } = useFormatter()
|
||||||
const [loadedImage, setImageLoaded] = useState(false)
|
const [loadedImage, setImageLoaded] = useState(false)
|
||||||
const [noImageAvailable, setNoImageAvailable] = useState(!asset.smallImageUrl)
|
const [noImageAvailable, setNoImageAvailable] = useState(!asset.smallImageUrl)
|
||||||
|
|
||||||
@ -99,11 +101,11 @@ export const BagRow = ({ asset, usdPrice, removeAsset, showRemove, grayscale, is
|
|||||||
const showRemoveButton = Boolean(showRemove && cardHovered && !isMobile)
|
const showRemoveButton = Boolean(showRemove && cardHovered && !isMobile)
|
||||||
|
|
||||||
const assetEthPrice = asset.updatedPriceInfo ? asset.updatedPriceInfo.ETHPrice : asset.priceInfo.ETHPrice
|
const assetEthPrice = asset.updatedPriceInfo ? asset.updatedPriceInfo.ETHPrice : asset.priceInfo.ETHPrice
|
||||||
const assetEthPriceFormatted = formatWeiToDecimal(assetEthPrice)
|
const assetEthPriceFormatted = formatEther({ input: assetEthPrice, type: NumberType.NFTToken })
|
||||||
const assetUSDPriceFormatted = ethNumberStandardFormatter(
|
const assetUSDPriceFormatted = formatNumberOrString({
|
||||||
usdPrice ? parseFloat(formatEther(assetEthPrice)) * usdPrice : usdPrice,
|
input: usdPrice ? parseFloat(ethersFormatEther(assetEthPrice)) * usdPrice : usdPrice,
|
||||||
true
|
type: NumberType.FiatNFTToken,
|
||||||
)
|
})
|
||||||
|
|
||||||
const handleRemoveClick = useCallback(
|
const handleRemoveClick = useCallback(
|
||||||
(e: MouseEvent<HTMLElement>) => {
|
(e: MouseEvent<HTMLElement>) => {
|
||||||
@ -175,6 +177,7 @@ interface PriceChangeBagRowProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const PriceChangeBagRow = ({ asset, usdPrice, markAssetAsReviewed, top, isMobile }: PriceChangeBagRowProps) => {
|
export const PriceChangeBagRow = ({ asset, usdPrice, markAssetAsReviewed, top, isMobile }: PriceChangeBagRowProps) => {
|
||||||
|
const { formatEther } = useFormatter()
|
||||||
const isPriceIncrease = BigNumber.from(asset.updatedPriceInfo?.ETHPrice).gt(BigNumber.from(asset.priceInfo.ETHPrice))
|
const isPriceIncrease = BigNumber.from(asset.updatedPriceInfo?.ETHPrice).gt(BigNumber.from(asset.priceInfo.ETHPrice))
|
||||||
const handleRemove = useCallback(
|
const handleRemove = useCallback(
|
||||||
(e: MouseEvent<HTMLButtonElement>) => {
|
(e: MouseEvent<HTMLButtonElement>) => {
|
||||||
@ -198,9 +201,10 @@ export const PriceChangeBagRow = ({ asset, usdPrice, markAssetAsReviewed, top, i
|
|||||||
<Column className={styles.priceChangeColumn} borderTopColor={top ? 'surface3' : 'transparent'}>
|
<Column className={styles.priceChangeColumn} borderTopColor={top ? 'surface3' : 'transparent'}>
|
||||||
<Row className={styles.priceChangeRow}>
|
<Row className={styles.priceChangeRow}>
|
||||||
{isPriceIncrease ? <SquareArrowUpIcon /> : <SquareArrowDownIcon />}
|
{isPriceIncrease ? <SquareArrowUpIcon /> : <SquareArrowDownIcon />}
|
||||||
<Box>{`Price ${isPriceIncrease ? 'increased' : 'decreased'} from ${formatWeiToDecimal(
|
<Box>{`Price ${isPriceIncrease ? 'increased' : 'decreased'} from ${formatEther({
|
||||||
asset.priceInfo.ETHPrice
|
input: asset.priceInfo.ETHPrice,
|
||||||
)} ETH`}</Box>
|
type: NumberType.NFTToken,
|
||||||
|
})} ETH`}</Box>
|
||||||
</Row>
|
</Row>
|
||||||
<Box style={{ marginLeft: '-8px', marginRight: '-8px' }}>
|
<Box style={{ marginLeft: '-8px', marginRight: '-8px' }}>
|
||||||
<BagRow asset={asset} usdPrice={usdPrice} removeAsset={() => undefined} isMobile={isMobile} />
|
<BagRow asset={asset} usdPrice={usdPrice} removeAsset={() => undefined} isMobile={isMobile} />
|
||||||
|
@ -3,7 +3,8 @@ import { Column, Row } from 'nft/components/Flex'
|
|||||||
import { body, bodySmall } from 'nft/css/common.css'
|
import { body, bodySmall } from 'nft/css/common.css'
|
||||||
import { useBag } from 'nft/hooks'
|
import { useBag } from 'nft/hooks'
|
||||||
import { useBagTotalEthPrice, useBagTotalUsdPrice } from 'nft/hooks/useBagTotalEthPrice'
|
import { useBagTotalEthPrice, useBagTotalUsdPrice } from 'nft/hooks/useBagTotalEthPrice'
|
||||||
import { ethNumberStandardFormatter, formatWeiToDecimal, roundAndPluralize } from 'nft/utils'
|
import { roundAndPluralize } from 'nft/utils'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import * as styles from './MobileHoverBag.css'
|
import * as styles from './MobileHoverBag.css'
|
||||||
export const MobileHoverBag = () => {
|
export const MobileHoverBag = () => {
|
||||||
@ -11,6 +12,7 @@ export const MobileHoverBag = () => {
|
|||||||
const toggleBag = useBag((state) => state.toggleBag)
|
const toggleBag = useBag((state) => state.toggleBag)
|
||||||
const totalEthPrice = useBagTotalEthPrice()
|
const totalEthPrice = useBagTotalEthPrice()
|
||||||
const totalUsdPrice = useBagTotalUsdPrice()
|
const totalUsdPrice = useBagTotalUsdPrice()
|
||||||
|
const { formatEther, formatNumberOrString } = useFormatter()
|
||||||
|
|
||||||
const shouldShowBag = itemsInBag.length > 0
|
const shouldShowBag = itemsInBag.length > 0
|
||||||
|
|
||||||
@ -48,9 +50,11 @@ export const MobileHoverBag = () => {
|
|||||||
{roundAndPluralize(itemsInBag.length, 'NFT')}
|
{roundAndPluralize(itemsInBag.length, 'NFT')}
|
||||||
</Box>
|
</Box>
|
||||||
<Row gap="8">
|
<Row gap="8">
|
||||||
<Box className={body}>{`${formatWeiToDecimal(totalEthPrice.toString())}`} ETH</Box>
|
<Box className={body}>
|
||||||
|
{`${formatEther({ input: totalEthPrice.toString(), type: NumberType.NFTToken })}`} ETH
|
||||||
|
</Box>
|
||||||
<Box color="neutral2" className={bodySmall}>
|
<Box color="neutral2" className={bodySmall}>
|
||||||
{ethNumberStandardFormatter(totalUsdPrice, true)}
|
{formatNumberOrString({ input: totalUsdPrice, type: NumberType.FiatNFTToken })}
|
||||||
</Box>
|
</Box>
|
||||||
</Row>
|
</Row>
|
||||||
</Column>
|
</Column>
|
||||||
|
@ -5,10 +5,10 @@ import { NftStandard } from 'graphql/data/__generated__/types-and-hooks'
|
|||||||
import { getMarketplaceIcon } from 'nft/components/card/utils'
|
import { getMarketplaceIcon } from 'nft/components/card/utils'
|
||||||
import { CollectionSelectedAssetIcon } from 'nft/components/icons'
|
import { CollectionSelectedAssetIcon } from 'nft/components/icons'
|
||||||
import { Markets } from 'nft/types'
|
import { Markets } from 'nft/types'
|
||||||
import { putCommas } from 'nft/utils'
|
|
||||||
import { AlertTriangle, Check, Tag } from 'react-feather'
|
import { AlertTriangle, Check, Tag } from 'react-feather'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
const StyledMarketplaceContainer = styled.div<{ isText?: boolean }>`
|
const StyledMarketplaceContainer = styled.div<{ isText?: boolean }>`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -114,6 +114,8 @@ const RarityInfo = styled(ThemedText.BodySmall)`
|
|||||||
`
|
`
|
||||||
|
|
||||||
export const Ranking = ({ provider }: RankingProps) => {
|
export const Ranking = ({ provider }: RankingProps) => {
|
||||||
|
const { formatNumber } = useFormatter()
|
||||||
|
|
||||||
if (!provider.rank) {
|
if (!provider.rank) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -131,7 +133,7 @@ export const Ranking = ({ provider }: RankingProps) => {
|
|||||||
}
|
}
|
||||||
placement="top"
|
placement="top"
|
||||||
>
|
>
|
||||||
# {putCommas(provider.rank)}
|
# {formatNumber({ input: provider.rank, type: NumberType.WholeNumber })}
|
||||||
</MouseoverTooltip>
|
</MouseoverTooltip>
|
||||||
</RarityInfo>
|
</RarityInfo>
|
||||||
)
|
)
|
||||||
|
@ -4,8 +4,8 @@ import { MediaContainer } from 'nft/components/card/media'
|
|||||||
import { detailsHref, getNftDisplayComponent, useSelectAsset } from 'nft/components/card/utils'
|
import { detailsHref, getNftDisplayComponent, useSelectAsset } from 'nft/components/card/utils'
|
||||||
import { useBag } from 'nft/hooks'
|
import { useBag } from 'nft/hooks'
|
||||||
import { GenieAsset, UniformAspectRatio, UniformAspectRatios, WalletAsset } from 'nft/types'
|
import { GenieAsset, UniformAspectRatio, UniformAspectRatios, WalletAsset } from 'nft/types'
|
||||||
import { floorFormatter } from 'nft/utils'
|
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
interface NftCardProps {
|
interface NftCardProps {
|
||||||
asset: GenieAsset | WalletAsset
|
asset: GenieAsset | WalletAsset
|
||||||
@ -74,12 +74,15 @@ export const NftCard = ({
|
|||||||
setBagExpanded: state.setBagExpanded,
|
setBagExpanded: state.setBagExpanded,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
const collectionNft = 'marketplace' in asset
|
const collectionNft = 'marketplace' in asset
|
||||||
const profileNft = 'asset_contract' in asset
|
const profileNft = 'asset_contract' in asset
|
||||||
const tokenType = collectionNft ? asset.tokenType : profileNft ? asset.asset_contract.tokenType : undefined
|
const tokenType = collectionNft ? asset.tokenType : profileNft ? asset.asset_contract.tokenType : undefined
|
||||||
const marketplace = collectionNft ? asset.marketplace : undefined
|
const marketplace = collectionNft ? asset.marketplace : undefined
|
||||||
const listedPrice =
|
const listedPrice =
|
||||||
profileNft && !isDisabled && asset.floor_sell_order_price ? floorFormatter(asset.floor_sell_order_price) : undefined
|
profileNft && !isDisabled && asset.floor_sell_order_price
|
||||||
|
? formatNumberOrString({ input: asset.floor_sell_order_price, type: NumberType.NFTTokenFloorPrice })
|
||||||
|
: undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card.Container
|
<Card.Container
|
||||||
|
@ -26,13 +26,12 @@ import {
|
|||||||
} from 'nft/types'
|
} from 'nft/types'
|
||||||
import { getMarketplaceIcon } from 'nft/utils'
|
import { getMarketplaceIcon } from 'nft/utils'
|
||||||
import { buildActivityAsset } from 'nft/utils/buildActivityAsset'
|
import { buildActivityAsset } from 'nft/utils/buildActivityAsset'
|
||||||
import { formatEth } from 'nft/utils/currency'
|
|
||||||
import { getTimeDifference } from 'nft/utils/date'
|
import { getTimeDifference } from 'nft/utils/date'
|
||||||
import { putCommas } from 'nft/utils/putCommas'
|
|
||||||
import { MouseEvent, ReactNode, useMemo, useState } from 'react'
|
import { MouseEvent, ReactNode, useMemo, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ExternalLink } from 'theme/components'
|
import { ExternalLink } from 'theme/components'
|
||||||
import { shortenAddress } from 'utils'
|
import { shortenAddress } from 'utils'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
||||||
|
|
||||||
import * as styles from './Activity.css'
|
import * as styles from './Activity.css'
|
||||||
@ -185,7 +184,11 @@ const PriceTooltip = ({ price }: { price: string }) => (
|
|||||||
)
|
)
|
||||||
|
|
||||||
export const PriceCell = ({ marketplace, price }: { marketplace?: Markets | string; price?: string | number }) => {
|
export const PriceCell = ({ marketplace, price }: { marketplace?: Markets | string; price?: string | number }) => {
|
||||||
const formattedPrice = useMemo(() => (price ? formatEth(parseFloat(price?.toString())) : null), [price])
|
const { formatNumberOrString } = useFormatter()
|
||||||
|
const formattedPrice = useMemo(
|
||||||
|
() => (price ? formatNumberOrString({ input: parseFloat(price?.toString()), type: NumberType.NFTToken }) : null),
|
||||||
|
[formatNumberOrString, price]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row display={{ sm: 'none', md: 'flex' }} gap="8">
|
<Row display={{ sm: 'none', md: 'flex' }} gap="8">
|
||||||
@ -257,7 +260,11 @@ export const EventCell = ({
|
|||||||
price,
|
price,
|
||||||
isMobile,
|
isMobile,
|
||||||
}: EventCellProps) => {
|
}: EventCellProps) => {
|
||||||
const formattedPrice = useMemo(() => (price ? formatEth(parseFloat(price?.toString())) : null), [price])
|
const { formatNumberOrString } = useFormatter()
|
||||||
|
const formattedPrice = useMemo(
|
||||||
|
() => (price ? formatNumberOrString({ input: parseFloat(price?.toString()), type: NumberType.NFTToken }) : null),
|
||||||
|
[formatNumberOrString, price]
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<Column height="full" justifyContent="center" gap="4">
|
<Column height="full" justifyContent="center" gap="4">
|
||||||
<Row className={styles.eventDetail} color={eventColors(eventType)}>
|
<Row className={styles.eventDetail} color={eventColors(eventType)}>
|
||||||
@ -318,6 +325,7 @@ interface RankingProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Ranking = ({ rarity, collectionName, rarityVerified }: RankingProps) => {
|
const Ranking = ({ rarity, collectionName, rarityVerified }: RankingProps) => {
|
||||||
|
const { formatNumber } = useFormatter()
|
||||||
const rank = (rarity as TokenRarity).rank || (rarity as Rarity).providers?.[0].rank
|
const rank = (rarity as TokenRarity).rank || (rarity as Rarity).providers?.[0].rank
|
||||||
|
|
||||||
if (!rank) return null
|
if (!rank) return null
|
||||||
@ -339,7 +347,7 @@ const Ranking = ({ rarity, collectionName, rarityVerified }: RankingProps) => {
|
|||||||
>
|
>
|
||||||
<Box className={styles.rarityInfo}>
|
<Box className={styles.rarityInfo}>
|
||||||
<Box paddingTop="2" paddingBottom="2" display="flex">
|
<Box paddingTop="2" paddingBottom="2" display="flex">
|
||||||
{putCommas(rank)}
|
{formatNumber({ input: rank, type: NumberType.WholeNumber })}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box display="flex" height="16">
|
<Box display="flex" height="16">
|
||||||
|
@ -6,8 +6,8 @@ import { NftCard, NftCardDisplayProps } from 'nft/components/card'
|
|||||||
import { Ranking as RankingContainer, Suspicious as SuspiciousContainer } from 'nft/components/card/icons'
|
import { Ranking as RankingContainer, Suspicious as SuspiciousContainer } from 'nft/components/card/icons'
|
||||||
import { useBag } from 'nft/hooks'
|
import { useBag } from 'nft/hooks'
|
||||||
import { GenieAsset, UniformAspectRatio } from 'nft/types'
|
import { GenieAsset, UniformAspectRatio } from 'nft/types'
|
||||||
import { formatWeiToDecimal } from 'nft/utils'
|
|
||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
interface CollectionAssetProps {
|
interface CollectionAssetProps {
|
||||||
asset: GenieAsset
|
asset: GenieAsset
|
||||||
@ -31,6 +31,7 @@ export const CollectionAsset = ({
|
|||||||
renderedHeight,
|
renderedHeight,
|
||||||
setRenderedHeight,
|
setRenderedHeight,
|
||||||
}: CollectionAssetProps) => {
|
}: CollectionAssetProps) => {
|
||||||
|
const { formatEther } = useFormatter()
|
||||||
const bagManuallyClosed = useBag((state) => state.bagManuallyClosed)
|
const bagManuallyClosed = useBag((state) => state.bagManuallyClosed)
|
||||||
const addAssetsToBag = useBag((state) => state.addAssetsToBag)
|
const addAssetsToBag = useBag((state) => state.addAssetsToBag)
|
||||||
const removeAssetsFromBag = useBag((state) => state.removeAssetsFromBag)
|
const removeAssetsFromBag = useBag((state) => state.removeAssetsFromBag)
|
||||||
@ -76,12 +77,23 @@ export const CollectionAsset = ({
|
|||||||
primaryInfo: asset.name ? asset.name : `#${asset.tokenId}`,
|
primaryInfo: asset.name ? asset.name : `#${asset.tokenId}`,
|
||||||
primaryInfoIcon: asset.susFlag ? <SuspiciousContainer /> : null,
|
primaryInfoIcon: asset.susFlag ? <SuspiciousContainer /> : null,
|
||||||
primaryInfoRight: asset.rarity && provider ? <RankingContainer provider={provider} /> : null,
|
primaryInfoRight: asset.rarity && provider ? <RankingContainer provider={provider} /> : null,
|
||||||
secondaryInfo: notForSale ? '' : `${formatWeiToDecimal(asset.priceInfo.ETHPrice, true)} ETH`,
|
secondaryInfo: notForSale
|
||||||
|
? ''
|
||||||
|
: `${formatEther({ input: asset.priceInfo.ETHPrice, type: NumberType.NFTToken })} ETH`,
|
||||||
selectedInfo: <Trans>Remove from bag</Trans>,
|
selectedInfo: <Trans>Remove from bag</Trans>,
|
||||||
notSelectedInfo: <Trans>Add to bag</Trans>,
|
notSelectedInfo: <Trans>Add to bag</Trans>,
|
||||||
disabledInfo: <Trans>Not listed</Trans>,
|
disabledInfo: <Trans>Not listed</Trans>,
|
||||||
}
|
}
|
||||||
}, [asset.name, asset.priceInfo.ETHPrice, asset.rarity, asset.susFlag, asset.tokenId, notForSale, provider])
|
}, [
|
||||||
|
asset.name,
|
||||||
|
asset.priceInfo.ETHPrice,
|
||||||
|
asset.rarity,
|
||||||
|
asset.susFlag,
|
||||||
|
asset.tokenId,
|
||||||
|
formatEther,
|
||||||
|
notForSale,
|
||||||
|
provider,
|
||||||
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NftCard
|
<NftCard
|
||||||
|
@ -8,11 +8,12 @@ import { themeVars } from 'nft/css/sprinkles.css'
|
|||||||
import { useBag, useIsMobile } from 'nft/hooks'
|
import { useBag, useIsMobile } from 'nft/hooks'
|
||||||
import { useIsCollectionLoading } from 'nft/hooks/useIsCollectionLoading'
|
import { useIsCollectionLoading } from 'nft/hooks/useIsCollectionLoading'
|
||||||
import { GenieCollection, TokenType } from 'nft/types'
|
import { GenieCollection, TokenType } from 'nft/types'
|
||||||
import { floorFormatter, quantityFormatter, roundWholePercentage, volumeFormatter } from 'nft/utils/numbers'
|
import { roundWholePercentage } from 'nft/utils/numbers'
|
||||||
import { ReactNode, useEffect, useReducer, useRef, useState } from 'react'
|
import { ReactNode, useEffect, useReducer, useRef, useState } from 'react'
|
||||||
import ReactMarkdown from 'react-markdown'
|
import ReactMarkdown from 'react-markdown'
|
||||||
import styled, { css } from 'styled-components'
|
import styled, { css } from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import { DiscordIcon, EllipsisIcon, ExternalIcon, InstagramIcon, TwitterIcon, VerifiedIcon, XMarkIcon } from '../icons'
|
import { DiscordIcon, EllipsisIcon, ExternalIcon, InstagramIcon, TwitterIcon, VerifiedIcon, XMarkIcon } from '../icons'
|
||||||
import * as styles from './CollectionStats.css'
|
import * as styles from './CollectionStats.css'
|
||||||
@ -338,20 +339,30 @@ const statsLoadingSkeleton = (isMobile: boolean) =>
|
|||||||
))
|
))
|
||||||
|
|
||||||
const StatsRow = ({ stats, isMobile, ...props }: { stats: GenieCollection; isMobile?: boolean } & BoxProps) => {
|
const StatsRow = ({ stats, isMobile, ...props }: { stats: GenieCollection; isMobile?: boolean } & BoxProps) => {
|
||||||
|
const { formatNumberOrString, formatDelta } = useFormatter()
|
||||||
|
|
||||||
const uniqueOwnersPercentage = stats?.stats?.total_supply
|
const uniqueOwnersPercentage = stats?.stats?.total_supply
|
||||||
? roundWholePercentage(((stats.stats.num_owners ?? 0) / stats.stats.total_supply) * 100)
|
? roundWholePercentage(((stats.stats.num_owners ?? 0) / stats.stats.total_supply) * 100)
|
||||||
: 0
|
: 0
|
||||||
const totalSupplyStr = stats.stats ? quantityFormatter(stats.stats.total_supply ?? 0) : 0
|
const totalSupplyStr = stats.stats
|
||||||
|
? formatNumberOrString({ input: stats.stats.total_supply ?? 0, type: NumberType.NFTCollectionStats })
|
||||||
|
: 0
|
||||||
const listedPercentageStr = stats?.stats?.total_supply
|
const listedPercentageStr = stats?.stats?.total_supply
|
||||||
? roundWholePercentage(((stats.stats.total_listings ?? 0) / stats.stats.total_supply) * 100)
|
? roundWholePercentage(((stats.stats.total_listings ?? 0) / stats.stats.total_supply) * 100)
|
||||||
: 0
|
: 0
|
||||||
const isCollectionStatsLoading = useIsCollectionLoading((state) => state.isCollectionStatsLoading)
|
const isCollectionStatsLoading = useIsCollectionLoading((state) => state.isCollectionStatsLoading)
|
||||||
|
|
||||||
// round daily volume & floorPrice to 3 decimals or less
|
// round daily volume & floorPrice to 3 decimals or less
|
||||||
const totalVolumeStr = volumeFormatter(Number(stats.stats?.total_volume) ?? 0)
|
const totalVolumeStr = formatNumberOrString({
|
||||||
const floorPriceStr = floorFormatter(stats.stats?.floor_price ?? 0)
|
input: Number(stats.stats?.total_volume) ?? 0,
|
||||||
|
type: NumberType.NFTCollectionStats,
|
||||||
|
})
|
||||||
|
const floorPriceStr = formatNumberOrString({
|
||||||
|
input: stats.stats?.floor_price ?? 0,
|
||||||
|
type: NumberType.NFTTokenFloorPrice,
|
||||||
|
})
|
||||||
// graphQL formatted %age values out of 100, whereas v3 endpoint did a decimal between 0 & 1
|
// graphQL formatted %age values out of 100, whereas v3 endpoint did a decimal between 0 & 1
|
||||||
const floorChangeStr = Math.round(Math.abs(stats?.stats?.one_day_floor_change ?? 0))
|
const floorChangeStr = formatDelta(Math.round(Math.abs(stats?.stats?.one_day_floor_change ?? 0)))
|
||||||
|
|
||||||
const isBagExpanded = useBag((state) => state.bagExpanded)
|
const isBagExpanded = useBag((state) => state.bagExpanded)
|
||||||
const isScreenSize = useScreenSize()
|
const isScreenSize = useScreenSize()
|
||||||
@ -372,7 +383,7 @@ const StatsRow = ({ stats, isMobile, ...props }: { stats: GenieCollection; isMob
|
|||||||
<StatsItem label="Floor 24H" shouldHide={false}>
|
<StatsItem label="Floor 24H" shouldHide={false}>
|
||||||
<PercentChange isNegative={stats.stats.one_day_floor_change < 0}>
|
<PercentChange isNegative={stats.stats.one_day_floor_change < 0}>
|
||||||
<DeltaArrow delta={stats?.stats?.one_day_floor_change} />
|
<DeltaArrow delta={stats?.stats?.one_day_floor_change} />
|
||||||
{floorChangeStr}%
|
{floorChangeStr}
|
||||||
</PercentChange>
|
</PercentChange>
|
||||||
</StatsItem>
|
</StatsItem>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -4,7 +4,8 @@ import * as styles from 'nft/components/collection/FilterButton.css'
|
|||||||
import { FilterIcon } from 'nft/components/icons'
|
import { FilterIcon } from 'nft/components/icons'
|
||||||
import { buttonTextMedium } from 'nft/css/common.css'
|
import { buttonTextMedium } from 'nft/css/common.css'
|
||||||
import { breakpoints } from 'nft/css/sprinkles.css'
|
import { breakpoints } from 'nft/css/sprinkles.css'
|
||||||
import { pluralize, putCommas } from 'nft/utils'
|
import { pluralize } from 'nft/utils'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
export const FilterButton = ({
|
export const FilterButton = ({
|
||||||
onClick,
|
onClick,
|
||||||
@ -17,6 +18,7 @@ export const FilterButton = ({
|
|||||||
onClick: () => void
|
onClick: () => void
|
||||||
collectionCount?: number
|
collectionCount?: number
|
||||||
}) => {
|
}) => {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
const hideResultsCount = window.innerWidth >= breakpoints.sm && window.innerWidth < breakpoints.md
|
const hideResultsCount = window.innerWidth >= breakpoints.sm && window.innerWidth < breakpoints.md
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -41,7 +43,10 @@ export const FilterButton = ({
|
|||||||
{' '}
|
{' '}
|
||||||
{!collectionCount || hideResultsCount
|
{!collectionCount || hideResultsCount
|
||||||
? 'Filter'
|
? 'Filter'
|
||||||
: `Filter • ${putCommas(collectionCount)} result${pluralize(collectionCount)}`}
|
: `Filter • ${formatNumberOrString({
|
||||||
|
input: collectionCount,
|
||||||
|
type: NumberType.WholeNumber,
|
||||||
|
})} result${pluralize(collectionCount)}`}
|
||||||
</Box>
|
</Box>
|
||||||
) : null}
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import 'rc-slider/assets/index.css'
|
import 'rc-slider/assets/index.css'
|
||||||
|
|
||||||
import { BigNumber } from '@ethersproject/bignumber'
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
import { formatEther, parseEther } from '@ethersproject/units'
|
import { formatEther as ethersFormatEther, parseEther } from '@ethersproject/units'
|
||||||
import { Trans } from '@lingui/macro'
|
import { Trans } from '@lingui/macro'
|
||||||
import { SweepFetcherParams, useSweepNftAssets } from 'graphql/data/nft/Asset'
|
import { SweepFetcherParams, useSweepNftAssets } from 'graphql/data/nft/Asset'
|
||||||
import { useBag, useCollectionFilters } from 'nft/hooks'
|
import { useBag, useCollectionFilters } from 'nft/hooks'
|
||||||
import { GenieAsset, isPooledMarket, Markets } from 'nft/types'
|
import { GenieAsset, isPooledMarket, Markets } from 'nft/types'
|
||||||
import { calcPoolPrice, formatWeiToDecimal, isInSameSudoSwapPool } from 'nft/utils'
|
import { calcPoolPrice, isInSameSudoSwapPool } from 'nft/utils'
|
||||||
import { default as Slider } from 'rc-slider'
|
import { default as Slider } from 'rc-slider'
|
||||||
import { useEffect, useMemo, useReducer, useState } from 'react'
|
import { useEffect, useMemo, useReducer, useState } from 'react'
|
||||||
import styled, { useTheme } from 'styled-components'
|
import styled, { useTheme } from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
const SweepContainer = styled.div`
|
const SweepContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -160,6 +161,7 @@ interface SweepProps {
|
|||||||
|
|
||||||
export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => {
|
export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const { formatEther } = useFormatter()
|
||||||
|
|
||||||
const [isItemsToggled, toggleSweep] = useReducer((state) => !state, true)
|
const [isItemsToggled, toggleSweep] = useReducer((state) => !state, true)
|
||||||
const [sweepAmount, setSweepAmount] = useState<string>('')
|
const [sweepAmount, setSweepAmount] = useState<string>('')
|
||||||
@ -374,8 +376,12 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => {
|
|||||||
<StyledSlider
|
<StyledSlider
|
||||||
defaultValue={0}
|
defaultValue={0}
|
||||||
min={0}
|
min={0}
|
||||||
max={isItemsToggled ? sortedAssets?.length ?? 0 : parseFloat(formatEther(sortedAssetsTotalEth).toString())}
|
max={
|
||||||
value={isItemsToggled ? sweepItemsInBag.length : parseFloat(formatWeiToDecimal(sweepEthPrice.toString()))}
|
isItemsToggled
|
||||||
|
? sortedAssets?.length ?? 0
|
||||||
|
: parseFloat(ethersFormatEther(sortedAssetsTotalEth).toString())
|
||||||
|
}
|
||||||
|
value={isItemsToggled ? sweepItemsInBag.length : parseFloat(ethersFormatEther(sweepEthPrice.toString()))}
|
||||||
step={isItemsToggled ? 1 : 0.01}
|
step={isItemsToggled ? 1 : 0.01}
|
||||||
trackStyle={{
|
trackStyle={{
|
||||||
top: '3px',
|
top: '3px',
|
||||||
@ -424,9 +430,10 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => {
|
|||||||
</SweepSubContainer>
|
</SweepSubContainer>
|
||||||
</SweepLeftmostContainer>
|
</SweepLeftmostContainer>
|
||||||
<SweepRightmostContainer>
|
<SweepRightmostContainer>
|
||||||
<ThemedText.SubHeader font-size="14px">{`${formatWeiToDecimal(
|
<ThemedText.SubHeader font-size="14px">{`${formatEther({
|
||||||
sweepEthPrice.toString()
|
input: sweepEthPrice.toString(),
|
||||||
)} ETH`}</ThemedText.SubHeader>
|
type: NumberType.NFTToken,
|
||||||
|
})} ETH`}</ThemedText.SubHeader>
|
||||||
<NftDisplay nfts={sweepItemsInBag} />
|
<NftDisplay nfts={sweepItemsInBag} />
|
||||||
</SweepRightmostContainer>
|
</SweepRightmostContainer>
|
||||||
</SweepContainer>
|
</SweepContainer>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { formatEther } from '@ethersproject/units'
|
import { formatEther as ethersFormatEther } from '@ethersproject/units'
|
||||||
import { Trans } from '@lingui/macro'
|
import { Trans } from '@lingui/macro'
|
||||||
import { InterfaceModalName, NFTEventName } from '@uniswap/analytics-events'
|
import { InterfaceModalName, NFTEventName } from '@uniswap/analytics-events'
|
||||||
import { Trace, useTrace } from 'analytics'
|
import { Trace, useTrace } from 'analytics'
|
||||||
@ -12,17 +12,11 @@ import { Overlay, stopPropagation } from 'nft/components/modals/Overlay'
|
|||||||
import { themeVars, vars } from 'nft/css/sprinkles.css'
|
import { themeVars, vars } from 'nft/css/sprinkles.css'
|
||||||
import { useIsMobile, useNativeUsdPrice, useSendTransaction, useTransactionResponse } from 'nft/hooks'
|
import { useIsMobile, useNativeUsdPrice, useSendTransaction, useTransactionResponse } from 'nft/hooks'
|
||||||
import { TxResponse, TxStateType } from 'nft/types'
|
import { TxResponse, TxStateType } from 'nft/types'
|
||||||
import {
|
import { generateTweetForPurchase, getSuccessfulImageSize, parseTransactionResponse } from 'nft/utils'
|
||||||
formatEthPrice,
|
|
||||||
formatUsdPrice,
|
|
||||||
formatUSDPriceWithCommas,
|
|
||||||
generateTweetForPurchase,
|
|
||||||
getSuccessfulImageSize,
|
|
||||||
parseTransactionResponse,
|
|
||||||
} from 'nft/utils'
|
|
||||||
import { formatAssetEventProperties } from 'nft/utils/formatEventProperties'
|
import { formatAssetEventProperties } from 'nft/utils/formatEventProperties'
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
||||||
|
|
||||||
import * as styles from './TransactionCompleteModal.css'
|
import * as styles from './TransactionCompleteModal.css'
|
||||||
@ -47,6 +41,7 @@ const UploadLink = styled.a`
|
|||||||
|
|
||||||
const TxCompleteModal = () => {
|
const TxCompleteModal = () => {
|
||||||
const ethUsdPrice = useNativeUsdPrice()
|
const ethUsdPrice = useNativeUsdPrice()
|
||||||
|
const { formatEther, formatNumberOrString } = useFormatter()
|
||||||
const [showUnavailable, setShowUnavailable] = useState(false)
|
const [showUnavailable, setShowUnavailable] = useState(false)
|
||||||
const txHash = useSendTransaction((state) => state.txHash)
|
const txHash = useSendTransaction((state) => state.txHash)
|
||||||
const purchasedWithErc20 = useSendTransaction((state) => state.purchasedWithErc20)
|
const purchasedWithErc20 = useSendTransaction((state) => state.purchasedWithErc20)
|
||||||
@ -107,7 +102,7 @@ const TxCompleteModal = () => {
|
|||||||
name={NFTEventName.NFT_BUY_BAG_SUCCEEDED}
|
name={NFTEventName.NFT_BUY_BAG_SUCCEEDED}
|
||||||
properties={{
|
properties={{
|
||||||
buy_quantity: nftsPurchased.length,
|
buy_quantity: nftsPurchased.length,
|
||||||
usd_value: parseFloat(formatEther(totalPurchaseValue)) * ethUsdPrice,
|
usd_value: parseFloat(ethersFormatEther(totalPurchaseValue)) * ethUsdPrice,
|
||||||
transaction_hash: txHash,
|
transaction_hash: txHash,
|
||||||
using_erc20: purchasedWithErc20,
|
using_erc20: purchasedWithErc20,
|
||||||
...formatAssetEventProperties(nftsPurchased),
|
...formatAssetEventProperties(nftsPurchased),
|
||||||
@ -168,7 +163,13 @@ const TxCompleteModal = () => {
|
|||||||
<Box marginRight="16">
|
<Box marginRight="16">
|
||||||
{nftsPurchased.length} NFT{nftsPurchased.length === 1 ? '' : 's'}
|
{nftsPurchased.length} NFT{nftsPurchased.length === 1 ? '' : 's'}
|
||||||
</Box>
|
</Box>
|
||||||
<Box>{formatEthPrice(totalPurchaseValue.toString())} ETH</Box>
|
<Box>
|
||||||
|
{formatEther({
|
||||||
|
input: totalPurchaseValue.toString(),
|
||||||
|
type: NumberType.NFTToken,
|
||||||
|
})}{' '}
|
||||||
|
ETH
|
||||||
|
</Box>
|
||||||
</Row>
|
</Row>
|
||||||
<a href={txHashUrl} target="_blank" rel="noreferrer" style={{ textDecoration: 'none' }}>
|
<a href={txHashUrl} target="_blank" rel="noreferrer" style={{ textDecoration: 'none' }}>
|
||||||
<Box color="neutral2" fontWeight="book">
|
<Box color="neutral2" fontWeight="book">
|
||||||
@ -205,7 +206,13 @@ const TxCompleteModal = () => {
|
|||||||
<p className={styles.subtitle}>Instant Refund</p>
|
<p className={styles.subtitle}>Instant Refund</p>
|
||||||
<p className={styles.interStd}>
|
<p className={styles.interStd}>
|
||||||
Uniswap returned{' '}
|
Uniswap returned{' '}
|
||||||
<span style={{ fontWeight: '535' }}>{formatEthPrice(totalRefundValue.toString())} ETH</span>{' '}
|
<span style={{ fontWeight: '535' }}>
|
||||||
|
{formatEther({
|
||||||
|
input: totalRefundValue.toString(),
|
||||||
|
type: NumberType.NFTToken,
|
||||||
|
})}{' '}
|
||||||
|
ETH
|
||||||
|
</span>{' '}
|
||||||
back to your wallet for unavailable items.
|
back to your wallet for unavailable items.
|
||||||
</p>
|
</p>
|
||||||
<Box
|
<Box
|
||||||
@ -217,9 +224,15 @@ const TxCompleteModal = () => {
|
|||||||
position={{ sm: 'absolute', md: 'static' }}
|
position={{ sm: 'absolute', md: 'static' }}
|
||||||
>
|
>
|
||||||
<p className={styles.totalEthCost} style={{ marginBottom: '2px' }}>
|
<p className={styles.totalEthCost} style={{ marginBottom: '2px' }}>
|
||||||
{formatEthPrice(totalRefundValue.toString())} ETH
|
{formatEther({
|
||||||
|
input: totalRefundValue.toString(),
|
||||||
|
type: NumberType.NFTToken,
|
||||||
|
})}{' '}
|
||||||
|
ETH
|
||||||
|
</p>
|
||||||
|
<p className={styles.totalUsdRefund}>
|
||||||
|
{formatNumberOrString({ input: totalUSDRefund, type: NumberType.FiatNFTToken })}
|
||||||
</p>
|
</p>
|
||||||
<p className={styles.totalUsdRefund}>{formatUSDPriceWithCommas(totalUSDRefund)}</p>
|
|
||||||
<p className={styles.totalEthCost} style={{ width: '100%' }}>
|
<p className={styles.totalEthCost} style={{ width: '100%' }}>
|
||||||
for {nftsNotPurchased.length} unavailable item
|
for {nftsNotPurchased.length} unavailable item
|
||||||
{nftsNotPurchased.length === 1 ? '' : 's'}.
|
{nftsNotPurchased.length === 1 ? '' : 's'}.
|
||||||
@ -280,8 +293,9 @@ const TxCompleteModal = () => {
|
|||||||
`Selected item${
|
`Selected item${
|
||||||
nftsPurchased.length === 1 ? ' is' : 's are'
|
nftsPurchased.length === 1 ? ' is' : 's are'
|
||||||
} no longer available. Uniswap instantly refunded you for this incomplete transaction. `}
|
} no longer available. Uniswap instantly refunded you for this incomplete transaction. `}
|
||||||
{formatUsdPrice(txFeeFiat)} was used for gas in attempt to complete this transaction. For support,
|
{formatNumberOrString({ input: txFeeFiat, type: NumberType.FiatNFTToken })} was used for gas in
|
||||||
please visit our <a href="https://discord.gg/FCfyBSbCU5">Discord</a>
|
attempt to complete this transaction. For support, please visit our{' '}
|
||||||
|
<a href="https://discord.gg/FCfyBSbCU5">Discord</a>
|
||||||
</p>
|
</p>
|
||||||
<Box className={styles.allUnavailableAssets}>
|
<Box className={styles.allUnavailableAssets}>
|
||||||
{nftsNotPurchased.length >= 3 && (
|
{nftsNotPurchased.length >= 3 && (
|
||||||
@ -324,9 +338,12 @@ const TxCompleteModal = () => {
|
|||||||
<Box flexWrap="wrap" marginTop="4">
|
<Box flexWrap="wrap" marginTop="4">
|
||||||
<Box marginLeft="4" width="full" display="flex">
|
<Box marginLeft="4" width="full" display="flex">
|
||||||
<p className={styles.totalEthCost} style={{ marginBottom: '2px' }}>
|
<p className={styles.totalEthCost} style={{ marginBottom: '2px' }}>
|
||||||
{formatEthPrice(
|
{formatEther({
|
||||||
asset.updatedPriceInfo ? asset.updatedPriceInfo.ETHPrice : asset.priceInfo.ETHPrice
|
input: asset.updatedPriceInfo
|
||||||
)}{' '}
|
? asset.updatedPriceInfo.ETHPrice
|
||||||
|
: asset.priceInfo.ETHPrice,
|
||||||
|
type: NumberType.NFTToken,
|
||||||
|
})}{' '}
|
||||||
ETH
|
ETH
|
||||||
</p>
|
</p>
|
||||||
</Box>
|
</Box>
|
||||||
@ -339,9 +356,15 @@ const TxCompleteModal = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
{showUnavailable && <Box className={styles.fullRefundOverflowFade} />}
|
{showUnavailable && <Box className={styles.fullRefundOverflowFade} />}
|
||||||
<p className={styles.totalEthCost} style={{ marginBottom: '2px' }}>
|
<p className={styles.totalEthCost} style={{ marginBottom: '2px' }}>
|
||||||
{formatEthPrice(totalRefundValue.toString())} ETH
|
{formatEther({
|
||||||
|
input: totalRefundValue.toString(),
|
||||||
|
type: NumberType.NFTToken,
|
||||||
|
})}{' '}
|
||||||
|
ETH
|
||||||
|
</p>
|
||||||
|
<p className={styles.totalUsdRefund}>
|
||||||
|
{formatNumberOrString({ input: totalUSDRefund, type: NumberType.FiatNFTToken })}
|
||||||
</p>
|
</p>
|
||||||
<p className={styles.totalUsdRefund}>{formatUSDPriceWithCommas(totalUSDRefund)}</p>
|
|
||||||
<Box className={styles.walletAddress} marginLeft="auto" marginRight="0">
|
<Box className={styles.walletAddress} marginLeft="auto" marginRight="0">
|
||||||
<a href={txHashUrl} target="_blank" rel="noreferrer">
|
<a href={txHashUrl} target="_blank" rel="noreferrer">
|
||||||
<Box className={styles.addressHash}>View on Etherscan</Box>
|
<Box className={styles.addressHash}>View on Etherscan</Box>
|
||||||
|
@ -4,11 +4,11 @@ import { LoadingBubble } from 'components/Tokens/loading'
|
|||||||
import { EventCell } from 'nft/components/collection/ActivityCells'
|
import { EventCell } from 'nft/components/collection/ActivityCells'
|
||||||
import { ActivityEvent } from 'nft/types'
|
import { ActivityEvent } from 'nft/types'
|
||||||
import { getMarketplaceIcon } from 'nft/utils'
|
import { getMarketplaceIcon } from 'nft/utils'
|
||||||
import { formatEth } from 'nft/utils/currency'
|
|
||||||
import { getTimeDifference } from 'nft/utils/date'
|
import { getTimeDifference } from 'nft/utils/date'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { shortenAddress } from 'utils'
|
import { shortenAddress } from 'utils'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
const TR = styled.tr`
|
const TR = styled.tr`
|
||||||
border-bottom: ${({ theme }) => `1px solid ${theme.surface3}`};
|
border-bottom: ${({ theme }) => `1px solid ${theme.surface3}`};
|
||||||
@ -148,12 +148,15 @@ export const LoadingAssetActivity = ({ rowCount }: { rowCount: number }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const AssetActivity = ({ events }: { events?: ActivityEvent[] }) => {
|
const AssetActivity = ({ events }: { events?: ActivityEvent[] }) => {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
return (
|
return (
|
||||||
<ActivityTable>
|
<ActivityTable>
|
||||||
{events &&
|
{events &&
|
||||||
events.map((event, index) => {
|
events.map((event, index) => {
|
||||||
const { eventTimestamp, eventType, fromAddress, marketplace, price, toAddress, transactionHash } = event
|
const { eventTimestamp, eventType, fromAddress, marketplace, price, toAddress, transactionHash } = event
|
||||||
const formattedPrice = price ? formatEth(parseFloat(price ?? '')) : null
|
const formattedPrice = price
|
||||||
|
? formatNumberOrString({ input: parseFloat(price), type: NumberType.NFTToken })
|
||||||
|
: null
|
||||||
if (!eventType) return null
|
if (!eventType) return null
|
||||||
return (
|
return (
|
||||||
<TR key={index}>
|
<TR key={index}>
|
||||||
|
@ -10,15 +10,14 @@ import { AssetPriceDetails } from 'nft/components/details/AssetPriceDetails'
|
|||||||
import { Center } from 'nft/components/Flex'
|
import { Center } from 'nft/components/Flex'
|
||||||
import { themeVars, vars } from 'nft/css/sprinkles.css'
|
import { themeVars, vars } from 'nft/css/sprinkles.css'
|
||||||
import { ActivityEventType, CollectionInfoForAsset, GenieAsset } from 'nft/types'
|
import { ActivityEventType, CollectionInfoForAsset, GenieAsset } from 'nft/types'
|
||||||
import { formatEth } from 'nft/utils/currency'
|
|
||||||
import { isAudio } from 'nft/utils/isAudio'
|
import { isAudio } from 'nft/utils/isAudio'
|
||||||
import { isVideo } from 'nft/utils/isVideo'
|
import { isVideo } from 'nft/utils/isVideo'
|
||||||
import { putCommas } from 'nft/utils/putCommas'
|
|
||||||
import { useCallback, useMemo, useReducer, useState } from 'react'
|
import { useCallback, useMemo, useReducer, useState } from 'react'
|
||||||
import InfiniteScroll from 'react-infinite-scroll-component'
|
import InfiniteScroll from 'react-infinite-scroll-component'
|
||||||
import { Link as RouterLink } from 'react-router-dom'
|
import { Link as RouterLink } from 'react-router-dom'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { shortenAddress } from 'utils/addresses'
|
import { shortenAddress } from 'utils/addresses'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import AssetActivity, { LoadingAssetActivity } from './AssetActivity'
|
import AssetActivity, { LoadingAssetActivity } from './AssetActivity'
|
||||||
import * as styles from './AssetDetails.css'
|
import * as styles from './AssetDetails.css'
|
||||||
@ -243,6 +242,7 @@ interface AssetDetailsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
|
export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
const [dominantColor] = useState<[number, number, number]>([0, 0, 0])
|
const [dominantColor] = useState<[number, number, number]>([0, 0, 0])
|
||||||
|
|
||||||
const { rarityProvider } = useMemo(
|
const { rarityProvider } = useMemo(
|
||||||
@ -281,7 +281,9 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const weiPrice = gqlPriceData?.[0]?.price
|
const weiPrice = gqlPriceData?.[0]?.price
|
||||||
const formattedPrice = weiPrice ? formatEth(parseFloat(weiPrice)) : undefined
|
const formattedPrice = weiPrice
|
||||||
|
? formatNumberOrString({ input: parseFloat(weiPrice), type: NumberType.NFTToken })
|
||||||
|
: undefined
|
||||||
|
|
||||||
const [activeFilters, filtersDispatch] = useReducer(reduceFilters, initialFilterState)
|
const [activeFilters, filtersDispatch] = useReducer(reduceFilters, initialFilterState)
|
||||||
const Filter = useCallback(
|
const Filter = useCallback(
|
||||||
@ -359,7 +361,9 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
|
|||||||
}
|
}
|
||||||
placement="top"
|
placement="top"
|
||||||
>
|
>
|
||||||
<RarityWrap>Rarity: {putCommas(rarity.score)}</RarityWrap>
|
<RarityWrap>
|
||||||
|
Rarity: {formatNumberOrString({ input: rarity.score, type: NumberType.WholeNumber })}
|
||||||
|
</RarityWrap>
|
||||||
</MouseoverTooltip>
|
</MouseoverTooltip>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,13 @@ import { useNftBalance } from 'graphql/data/nft/NftBalance'
|
|||||||
import { CancelListingIcon, VerifiedIcon } from 'nft/components/icons'
|
import { CancelListingIcon, VerifiedIcon } from 'nft/components/icons'
|
||||||
import { useBag, useNativeUsdPrice, useProfilePageState, useSellAsset, useUsdPriceofNftAsset } from 'nft/hooks'
|
import { useBag, useNativeUsdPrice, useProfilePageState, useSellAsset, useUsdPriceofNftAsset } from 'nft/hooks'
|
||||||
import { CollectionInfoForAsset, GenieAsset, ProfilePageStateType, WalletAsset } from 'nft/types'
|
import { CollectionInfoForAsset, GenieAsset, ProfilePageStateType, WalletAsset } from 'nft/types'
|
||||||
import {
|
import { generateTweetForAsset, getMarketplaceIcon, timeLeft } from 'nft/utils'
|
||||||
ethNumberStandardFormatter,
|
|
||||||
formatEthPrice,
|
|
||||||
generateTweetForAsset,
|
|
||||||
getMarketplaceIcon,
|
|
||||||
timeLeft,
|
|
||||||
} from 'nft/utils'
|
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import styled, { css, useTheme } from 'styled-components'
|
import styled, { css, useTheme } from 'styled-components'
|
||||||
import { ExternalLink, ThemedText } from 'theme/components'
|
import { ExternalLink, ThemedText } from 'theme/components'
|
||||||
import { shortenAddress } from 'utils/addresses'
|
import { shortenAddress } from 'utils/addresses'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
const TWITTER_WIDTH = 560
|
const TWITTER_WIDTH = 560
|
||||||
const TWITTER_HEIGHT = 480
|
const TWITTER_HEIGHT = 480
|
||||||
@ -213,6 +208,7 @@ const OwnerContainer = ({ asset }: { asset: WalletAsset }) => {
|
|||||||
const setSellPageState = useProfilePageState((state) => state.setProfilePageState)
|
const setSellPageState = useProfilePageState((state) => state.setProfilePageState)
|
||||||
const selectSellAsset = useSellAsset((state) => state.selectSellAsset)
|
const selectSellAsset = useSellAsset((state) => state.selectSellAsset)
|
||||||
const resetSellAssets = useSellAsset((state) => state.reset)
|
const resetSellAssets = useSellAsset((state) => state.reset)
|
||||||
|
const { formatEther, formatNumberOrString } = useFormatter()
|
||||||
|
|
||||||
const listing = asset.sellOrders && asset.sellOrders.length > 0 ? asset.sellOrders[0] : undefined
|
const listing = asset.sellOrders && asset.sellOrders.length > 0 ? asset.sellOrders[0] : undefined
|
||||||
const expirationDate = listing?.endAt ? new Date(listing.endAt) : undefined
|
const expirationDate = listing?.endAt ? new Date(listing.endAt) : undefined
|
||||||
@ -249,11 +245,15 @@ const OwnerContainer = ({ asset }: { asset: WalletAsset }) => {
|
|||||||
{listing ? (
|
{listing ? (
|
||||||
<>
|
<>
|
||||||
<ThemedText.MediumHeader fontSize="28px" lineHeight="36px">
|
<ThemedText.MediumHeader fontSize="28px" lineHeight="36px">
|
||||||
{formatEthPrice(asset.priceInfo?.ETHPrice)} ETH
|
{formatEther({
|
||||||
|
input: asset.priceInfo?.ETHPrice,
|
||||||
|
type: NumberType.NFTToken,
|
||||||
|
})}{' '}
|
||||||
|
ETH
|
||||||
</ThemedText.MediumHeader>
|
</ThemedText.MediumHeader>
|
||||||
{USDPrice && (
|
{USDPrice && (
|
||||||
<ThemedText.BodySecondary lineHeight="24px">
|
<ThemedText.BodySecondary lineHeight="24px">
|
||||||
{ethNumberStandardFormatter(USDPrice, true, true)}
|
{formatNumberOrString({ input: USDPrice, type: NumberType.FiatNFTToken })}
|
||||||
</ThemedText.BodySecondary>
|
</ThemedText.BodySecondary>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
@ -311,6 +311,7 @@ const NotForSale = ({ collectionName, collectionUrl }: { collectionName: string;
|
|||||||
|
|
||||||
export const AssetPriceDetails = ({ asset, collection }: AssetPriceDetailsProps) => {
|
export const AssetPriceDetails = ({ asset, collection }: AssetPriceDetailsProps) => {
|
||||||
const { account } = useWeb3React()
|
const { account } = useWeb3React()
|
||||||
|
const { formatEther, formatNumberOrString } = useFormatter()
|
||||||
|
|
||||||
const cheapestOrder = asset.sellorders && asset.sellorders.length > 0 ? asset.sellorders[0] : undefined
|
const cheapestOrder = asset.sellorders && asset.sellorders.length > 0 ? asset.sellorders[0] : undefined
|
||||||
const expirationDate = cheapestOrder?.endAt ? new Date(cheapestOrder.endAt) : undefined
|
const expirationDate = cheapestOrder?.endAt ? new Date(cheapestOrder.endAt) : undefined
|
||||||
@ -376,11 +377,11 @@ export const AssetPriceDetails = ({ asset, collection }: AssetPriceDetailsProps)
|
|||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
<PriceRow>
|
<PriceRow>
|
||||||
<ThemedText.MediumHeader fontSize="28px" lineHeight="36px">
|
<ThemedText.MediumHeader fontSize="28px" lineHeight="36px">
|
||||||
{formatEthPrice(asset.priceInfo.ETHPrice)} ETH
|
{formatEther({ input: asset.priceInfo.ETHPrice, type: NumberType.NFTToken })} ETH
|
||||||
</ThemedText.MediumHeader>
|
</ThemedText.MediumHeader>
|
||||||
{USDPrice && (
|
{USDPrice && (
|
||||||
<ThemedText.BodySecondary lineHeight="24px">
|
<ThemedText.BodySecondary lineHeight="24px">
|
||||||
{ethNumberStandardFormatter(USDPrice, true, true)}
|
{formatNumberOrString({ input: USDPrice, type: NumberType.FiatNFTToken })}
|
||||||
</ThemedText.BodySecondary>
|
</ThemedText.BodySecondary>
|
||||||
)}
|
)}
|
||||||
</PriceRow>
|
</PriceRow>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { OpacityHoverState } from 'components/Common'
|
import { OpacityHoverState } from 'components/Common'
|
||||||
import useCopyClipboard from 'hooks/useCopyClipboard'
|
import useCopyClipboard from 'hooks/useCopyClipboard'
|
||||||
import { CollectionInfoForAsset, GenieAsset } from 'nft/types'
|
import { CollectionInfoForAsset, GenieAsset } from 'nft/types'
|
||||||
import { putCommas } from 'nft/utils'
|
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { Copy } from 'react-feather'
|
import { Copy } from 'react-feather'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { shortenAddress } from 'utils'
|
import { shortenAddress } from 'utils'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
const Details = styled.div`
|
const Details = styled.div`
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -66,6 +66,7 @@ const GridItem = ({ header, body }: { header: string; body: React.ReactNode }) =
|
|||||||
const stringShortener = (text: string) => `${text.substring(0, 4)}...${text.substring(text.length - 4, text.length)}`
|
const stringShortener = (text: string) => `${text.substring(0, 4)}...${text.substring(text.length - 4, text.length)}`
|
||||||
|
|
||||||
const DetailsContainer = ({ asset, collection }: { asset: GenieAsset; collection: CollectionInfoForAsset }) => {
|
const DetailsContainer = ({ asset, collection }: { asset: GenieAsset; collection: CollectionInfoForAsset }) => {
|
||||||
|
const { formatNumber } = useFormatter()
|
||||||
const { address, tokenId, tokenType, creator } = asset
|
const { address, tokenId, tokenType, creator } = asset
|
||||||
const { totalSupply } = collection
|
const { totalSupply } = collection
|
||||||
|
|
||||||
@ -87,7 +88,10 @@ const DetailsContainer = ({ asset, collection }: { asset: GenieAsset; collection
|
|||||||
<GridItem header="Token ID" body={tokenId.length > 9 ? stringShortener(tokenId) : tokenId} />
|
<GridItem header="Token ID" body={tokenId.length > 9 ? stringShortener(tokenId) : tokenId} />
|
||||||
<GridItem header="Token standard" body={tokenType} />
|
<GridItem header="Token standard" body={tokenType} />
|
||||||
<GridItem header="Blockchain" body="Ethereum" />
|
<GridItem header="Blockchain" body="Ethereum" />
|
||||||
<GridItem header="Total supply" body={`${putCommas(totalSupply ?? 0)}`} />
|
<GridItem
|
||||||
|
header="Total supply"
|
||||||
|
body={`${formatNumber({ input: totalSupply ?? 0, type: NumberType.WholeNumber })}`}
|
||||||
|
/>
|
||||||
<GridItem
|
<GridItem
|
||||||
header="Creator"
|
header="Creator"
|
||||||
body={
|
body={
|
||||||
|
@ -3,7 +3,6 @@ import { LoadingBubble } from 'components/Tokens/loading'
|
|||||||
import { useCollection } from 'graphql/data/nft/Collection'
|
import { useCollection } from 'graphql/data/nft/Collection'
|
||||||
import { UniswapMagentaIcon, VerifiedIcon } from 'nft/components/icons'
|
import { UniswapMagentaIcon, VerifiedIcon } from 'nft/components/icons'
|
||||||
import { Markets, TrendingCollection } from 'nft/types'
|
import { Markets, TrendingCollection } from 'nft/types'
|
||||||
import { ethNumberStandardFormatter } from 'nft/utils'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components/text'
|
import { ThemedText } from 'theme/components/text'
|
||||||
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
@ -239,6 +238,7 @@ const MARKETS_ENUM_TO_NAME = {
|
|||||||
|
|
||||||
export const CarouselCard = ({ collection, onClick }: CarouselCardProps) => {
|
export const CarouselCard = ({ collection, onClick }: CarouselCardProps) => {
|
||||||
const { data: gqlCollection, loading } = useCollection(collection.address ?? '')
|
const { data: gqlCollection, loading } = useCollection(collection.address ?? '')
|
||||||
|
const { formatNumber } = useFormatter()
|
||||||
|
|
||||||
if (loading) return <LoadingCarouselCard />
|
if (loading) return <LoadingCarouselCard />
|
||||||
|
|
||||||
@ -257,7 +257,7 @@ export const CarouselCard = ({ collection, onClick }: CarouselCardProps) => {
|
|||||||
<TableElement>
|
<TableElement>
|
||||||
{collection.floor && (
|
{collection.floor && (
|
||||||
<ThemedText.SubHeaderSmall color="userThemeColor">
|
<ThemedText.SubHeaderSmall color="userThemeColor">
|
||||||
{ethNumberStandardFormatter(collection.floor)} ETH Floor
|
{formatNumber({ input: collection.floor, type: NumberType.NFTToken })} ETH Floor
|
||||||
</ThemedText.SubHeaderSmall>
|
</ThemedText.SubHeaderSmall>
|
||||||
)}
|
)}
|
||||||
</TableElement>
|
</TableElement>
|
||||||
|
@ -3,10 +3,10 @@ import { DeltaArrow } from 'components/Tokens/TokenDetails/Delta'
|
|||||||
import { VerifiedIcon } from 'nft/components/icons'
|
import { VerifiedIcon } from 'nft/components/icons'
|
||||||
import { useIsMobile } from 'nft/hooks'
|
import { useIsMobile } from 'nft/hooks'
|
||||||
import { Denomination } from 'nft/types'
|
import { Denomination } from 'nft/types'
|
||||||
import { ethNumberStandardFormatter, volumeFormatter } from 'nft/utils'
|
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import * as styles from './Cells.css'
|
import * as styles from './Cells.css'
|
||||||
|
|
||||||
@ -93,9 +93,12 @@ export const CollectionTitleCell = ({ value }: CellProps) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DiscreteNumberCell = ({ value }: CellProps) => (
|
export const DiscreteNumberCell = ({ value }: CellProps) => {
|
||||||
<span>{value.value ? volumeFormatter(value.value) : '-'}</span>
|
const { formatNumberOrString } = useFormatter()
|
||||||
)
|
return (
|
||||||
|
<span>{value.value ? formatNumberOrString({ input: value.value, type: NumberType.NFTCollectionStats }) : '-'}</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const getDenominatedValue = (denomination: Denomination, inWei: boolean, value?: number, usdPrice?: number) => {
|
const getDenominatedValue = (denomination: Denomination, inWei: boolean, value?: number, usdPrice?: number) => {
|
||||||
if (denomination === Denomination.ETH) return value
|
if (denomination === Denomination.ETH) return value
|
||||||
@ -113,12 +116,14 @@ export const EthCell = ({
|
|||||||
denomination: Denomination
|
denomination: Denomination
|
||||||
usdPrice?: number
|
usdPrice?: number
|
||||||
}) => {
|
}) => {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
const denominatedValue = getDenominatedValue(denomination, false, value, usdPrice)
|
const denominatedValue = getDenominatedValue(denomination, false, value, usdPrice)
|
||||||
const formattedValue = denominatedValue
|
const ethDenomination = denomination === Denomination.ETH
|
||||||
? denomination === Denomination.ETH
|
const formattedValue =
|
||||||
? ethNumberStandardFormatter(denominatedValue.toString(), false, true, false) + ' ETH'
|
formatNumberOrString({
|
||||||
: ethNumberStandardFormatter(denominatedValue, true, false, true)
|
input: denominatedValue,
|
||||||
: '-'
|
type: ethDenomination ? NumberType.NFTToken : NumberType.FiatTokenStats,
|
||||||
|
}) + (ethDenomination ? ' ETH' : '')
|
||||||
|
|
||||||
const isMobile = useIsMobile()
|
const isMobile = useIsMobile()
|
||||||
const TextComponent = isMobile ? ThemedText.BodySmall : ThemedText.BodyPrimary
|
const TextComponent = isMobile ? ThemedText.BodySmall : ThemedText.BodyPrimary
|
||||||
@ -141,17 +146,19 @@ export const VolumeCell = ({
|
|||||||
denomination: Denomination
|
denomination: Denomination
|
||||||
usdPrice?: number
|
usdPrice?: number
|
||||||
}) => {
|
}) => {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
const denominatedValue = getDenominatedValue(denomination, false, value, usdPrice)
|
const denominatedValue = getDenominatedValue(denomination, false, value, usdPrice)
|
||||||
|
const ethDenomination = denomination === Denomination.ETH
|
||||||
|
|
||||||
const formattedValue = denominatedValue
|
const formattedValue =
|
||||||
? denomination === Denomination.ETH
|
formatNumberOrString({
|
||||||
? ethNumberStandardFormatter(denominatedValue.toString(), false, false, true) + ' ETH'
|
input: denominatedValue,
|
||||||
: ethNumberStandardFormatter(denominatedValue, true, false, true)
|
type: ethDenomination ? NumberType.WholeNumber : NumberType.FiatTokenStats,
|
||||||
: '-'
|
}) + (ethDenomination ? ' ETH' : '')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EthContainer>
|
<EthContainer>
|
||||||
<ThemedText.BodyPrimary>{value ? formattedValue : '-'}</ThemedText.BodyPrimary>
|
<ThemedText.BodyPrimary>{formattedValue}</ThemedText.BodyPrimary>
|
||||||
</EthContainer>
|
</EthContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import { CollectionTableColumn, Denomination, TimePeriod, VolumeType } from 'nft
|
|||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
|
import { useFormatterLocales } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import CollectionTable from './CollectionTable'
|
import CollectionTable from './CollectionTable'
|
||||||
|
|
||||||
@ -84,6 +85,7 @@ function convertTimePeriodToHistoryDuration(timePeriod: TimePeriod): HistoryDura
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TrendingCollections = () => {
|
const TrendingCollections = () => {
|
||||||
|
const { formatterLocalCurrency } = useFormatterLocales()
|
||||||
const [timePeriod, setTimePeriod] = useState<TimePeriod>(TimePeriod.OneDay)
|
const [timePeriod, setTimePeriod] = useState<TimePeriod>(TimePeriod.OneDay)
|
||||||
const [isEthToggled, setEthToggled] = useState(true)
|
const [isEthToggled, setEthToggled] = useState(true)
|
||||||
|
|
||||||
@ -151,7 +153,7 @@ const TrendingCollections = () => {
|
|||||||
</Selector>
|
</Selector>
|
||||||
<Selector active={!isEthToggled}>
|
<Selector active={!isEthToggled}>
|
||||||
<StyledSelectorText lineHeight="20px" active={!isEthToggled}>
|
<StyledSelectorText lineHeight="20px" active={!isEthToggled}>
|
||||||
USD
|
{formatterLocalCurrency}
|
||||||
</StyledSelectorText>
|
</StyledSelectorText>
|
||||||
</Selector>
|
</Selector>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import { isNumber } from 'nft/utils/numbers'
|
|
||||||
import { FormEvent, forwardRef } from 'react'
|
import { FormEvent, forwardRef } from 'react'
|
||||||
|
|
||||||
import { Box, BoxProps } from '../Box'
|
import { Box, BoxProps } from '../Box'
|
||||||
|
|
||||||
|
const isNumber = (s: string): boolean => {
|
||||||
|
const reg = /^-?\d+\.?\d*$/
|
||||||
|
return reg.test(s) && !isNaN(parseFloat(s)) && isFinite(parseFloat(s))
|
||||||
|
}
|
||||||
|
|
||||||
export const Input = forwardRef<HTMLInputElement, BoxProps>((props, ref) => (
|
export const Input = forwardRef<HTMLInputElement, BoxProps>((props, ref) => (
|
||||||
<Box
|
<Box
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
@ -18,7 +18,6 @@ import { useIsMobile, useNFTList, useProfilePageState, useSellAsset } from 'nft/
|
|||||||
import { LIST_PAGE_MARGIN, LIST_PAGE_MARGIN_MOBILE } from 'nft/pages/profile/shared'
|
import { LIST_PAGE_MARGIN, LIST_PAGE_MARGIN_MOBILE } from 'nft/pages/profile/shared'
|
||||||
import { looksRareNonceFetcher } from 'nft/queries/looksRare'
|
import { looksRareNonceFetcher } from 'nft/queries/looksRare'
|
||||||
import { ProfilePageStateType } from 'nft/types'
|
import { ProfilePageStateType } from 'nft/types'
|
||||||
import { formatEth } from 'nft/utils'
|
|
||||||
import { ListingMarkets } from 'nft/utils/listNfts'
|
import { ListingMarkets } from 'nft/utils/listNfts'
|
||||||
import { useEffect, useMemo, useReducer, useState } from 'react'
|
import { useEffect, useMemo, useReducer, useState } from 'react'
|
||||||
import { ArrowLeft } from 'react-feather'
|
import { ArrowLeft } from 'react-feather'
|
||||||
@ -183,6 +182,7 @@ const EthValueWrapper = styled.span<{ totalEthListingValue: boolean }>`
|
|||||||
`
|
`
|
||||||
|
|
||||||
export const ListPage = () => {
|
export const ListPage = () => {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
const { setProfilePageState: setSellPageState } = useProfilePageState()
|
const { setProfilePageState: setSellPageState } = useProfilePageState()
|
||||||
const { provider, chainId } = useWeb3React()
|
const { provider, chainId } = useWeb3React()
|
||||||
const isMobile = useIsMobile()
|
const isMobile = useIsMobile()
|
||||||
@ -295,7 +295,10 @@ export const ListPage = () => {
|
|||||||
<ProceedsAndButtonWrapper>
|
<ProceedsAndButtonWrapper>
|
||||||
<ProceedsWrapper>
|
<ProceedsWrapper>
|
||||||
<EthValueWrapper totalEthListingValue={!!totalEthListingValue}>
|
<EthValueWrapper totalEthListingValue={!!totalEthListingValue}>
|
||||||
{totalEthListingValue > 0 ? formatEth(totalEthListingValue) : '-'} ETH
|
{totalEthListingValue > 0
|
||||||
|
? formatNumberOrString({ input: totalEthListingValue, type: NumberType.NFTToken })
|
||||||
|
: '-'}{' '}
|
||||||
|
ETH
|
||||||
</EthValueWrapper>
|
</EthValueWrapper>
|
||||||
{!!usdcValue && <UsdValue>{usdcAmount}</UsdValue>}
|
{!!usdcValue && <UsdValue>{usdcAmount}</UsdValue>}
|
||||||
</ProceedsWrapper>
|
</ProceedsWrapper>
|
||||||
|
@ -8,11 +8,11 @@ import { useSellAsset } from 'nft/hooks'
|
|||||||
import { useNativeUsdPrice } from 'nft/hooks/useUsdPrice'
|
import { useNativeUsdPrice } from 'nft/hooks/useUsdPrice'
|
||||||
import { ListingMarket, WalletAsset } from 'nft/types'
|
import { ListingMarket, WalletAsset } from 'nft/types'
|
||||||
import { getMarketplaceIcon } from 'nft/utils'
|
import { getMarketplaceIcon } from 'nft/utils'
|
||||||
import { formatEth, formatUsdPrice } from 'nft/utils/currency'
|
|
||||||
import { Dispatch, DispatchWithoutAction, useCallback, useEffect, useMemo, useReducer, useState } from 'react'
|
import { Dispatch, DispatchWithoutAction, useCallback, useEffect, useMemo, useReducer, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { BREAKPOINTS } from 'theme'
|
import { BREAKPOINTS } from 'theme'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import { PriceTextInput } from './PriceTextInput'
|
import { PriceTextInput } from './PriceTextInput'
|
||||||
import { RoyaltyTooltip } from './RoyaltyTooltip'
|
import { RoyaltyTooltip } from './RoyaltyTooltip'
|
||||||
@ -126,6 +126,7 @@ export const MarketplaceRow = ({
|
|||||||
toggleExpandMarketplaceRows,
|
toggleExpandMarketplaceRows,
|
||||||
rowHovered,
|
rowHovered,
|
||||||
}: MarketplaceRowProps) => {
|
}: MarketplaceRowProps) => {
|
||||||
|
const { formatNumberOrString, formatDelta } = useFormatter()
|
||||||
const setAssetListPrice = useSellAsset((state) => state.setAssetListPrice)
|
const setAssetListPrice = useSellAsset((state) => state.setAssetListPrice)
|
||||||
const removeAssetMarketplace = useSellAsset((state) => state.removeAssetMarketplace)
|
const removeAssetMarketplace = useSellAsset((state) => state.removeAssetMarketplace)
|
||||||
const [marketIconHovered, toggleMarketIconHovered] = useReducer((s) => !s, false)
|
const [marketIconHovered, toggleMarketIconHovered] = useReducer((s) => !s, false)
|
||||||
@ -184,12 +185,17 @@ export const MarketplaceRow = ({
|
|||||||
<Row onMouseEnter={toggleMarketRowHovered} onMouseLeave={toggleMarketRowHovered}>
|
<Row onMouseEnter={toggleMarketRowHovered} onMouseLeave={toggleMarketRowHovered}>
|
||||||
<FloorPriceInfo>
|
<FloorPriceInfo>
|
||||||
<ThemedText.BodyPrimary color="neutral2" lineHeight="24px">
|
<ThemedText.BodyPrimary color="neutral2" lineHeight="24px">
|
||||||
{asset.floorPrice ? `${asset.floorPrice.toFixed(3)} ETH` : '-'}
|
{formatNumberOrString({
|
||||||
|
input: asset.floorPrice,
|
||||||
|
type: NumberType.NFTToken,
|
||||||
|
}) + asset.floorPrice
|
||||||
|
? ' ETH'
|
||||||
|
: ''}
|
||||||
</ThemedText.BodyPrimary>
|
</ThemedText.BodyPrimary>
|
||||||
</FloorPriceInfo>
|
</FloorPriceInfo>
|
||||||
<LastPriceInfo>
|
<LastPriceInfo>
|
||||||
<ThemedText.BodyPrimary color="neutral2" lineHeight="24px">
|
<ThemedText.BodyPrimary color="neutral2" lineHeight="24px">
|
||||||
{asset.lastPrice ? `${asset.lastPrice.toFixed(3)} ETH` : '-'}
|
{asset.lastPrice ? `${formatNumberOrString({ input: asset.lastPrice, type: NumberType.NFTToken })} ETH` : '-'}
|
||||||
</ThemedText.BodyPrimary>
|
</ThemedText.BodyPrimary>
|
||||||
</LastPriceInfo>
|
</LastPriceInfo>
|
||||||
|
|
||||||
@ -235,7 +241,7 @@ export const MarketplaceRow = ({
|
|||||||
>
|
>
|
||||||
<FeeWrapper>
|
<FeeWrapper>
|
||||||
<ThemedText.BodyPrimary color="neutral2">
|
<ThemedText.BodyPrimary color="neutral2">
|
||||||
{fees > 0 ? `${fees.toFixed(2)}${selectedMarkets.length > 1 ? t`% max` : '%'}` : '--%'}
|
{fees > 0 ? `${formatDelta(fees)}${selectedMarkets.length > 1 ? t`max` : ''}` : '--%'}
|
||||||
</ThemedText.BodyPrimary>
|
</ThemedText.BodyPrimary>
|
||||||
</FeeWrapper>
|
</FeeWrapper>
|
||||||
</MouseoverTooltip>
|
</MouseoverTooltip>
|
||||||
@ -249,6 +255,7 @@ export const MarketplaceRow = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const EthPriceDisplay = ({ ethPrice = 0 }: { ethPrice?: number }) => {
|
const EthPriceDisplay = ({ ethPrice = 0 }: { ethPrice?: number }) => {
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
const ethUsdPrice = useNativeUsdPrice()
|
const ethUsdPrice = useNativeUsdPrice()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -256,8 +263,10 @@ const EthPriceDisplay = ({ ethPrice = 0 }: { ethPrice?: number }) => {
|
|||||||
<ThemedText.BodyPrimary lineHeight="24px" color={ethPrice ? 'neutral1' : 'neutral2'} textAlign="right">
|
<ThemedText.BodyPrimary lineHeight="24px" color={ethPrice ? 'neutral1' : 'neutral2'} textAlign="right">
|
||||||
{ethPrice !== 0 ? (
|
{ethPrice !== 0 ? (
|
||||||
<Column>
|
<Column>
|
||||||
<span>{formatEth(ethPrice)} ETH</span>
|
<span>{formatNumberOrString({ input: ethPrice, type: NumberType.NFTToken })} ETH</span>
|
||||||
<ThemedText.BodyPrimary color="neutral2">{formatUsdPrice(ethPrice * ethUsdPrice)}</ThemedText.BodyPrimary>
|
<ThemedText.BodyPrimary color="neutral2">
|
||||||
|
{formatNumberOrString({ input: ethPrice * ethUsdPrice, type: NumberType.FiatNFTToken })}
|
||||||
|
</ThemedText.BodyPrimary>
|
||||||
</Column>
|
</Column>
|
||||||
) : (
|
) : (
|
||||||
'- ETH'
|
'- ETH'
|
||||||
|
@ -10,6 +10,7 @@ import styled, { useTheme } from 'styled-components'
|
|||||||
import { BREAKPOINTS } from 'theme'
|
import { BREAKPOINTS } from 'theme'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
import { Z_INDEX } from 'theme/zIndex'
|
import { Z_INDEX } from 'theme/zIndex'
|
||||||
|
import { useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
const ModalWrapper = styled(Column)`
|
const ModalWrapper = styled(Column)`
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@ -82,6 +83,7 @@ export const BelowFloorWarningModal = ({
|
|||||||
startListing: () => void
|
startListing: () => void
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const { formatDelta } = useFormatter()
|
||||||
const clickContinue = (e: React.MouseEvent) => {
|
const clickContinue = (e: React.MouseEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
@ -103,10 +105,9 @@ export const BelowFloorWarningModal = ({
|
|||||||
<ThemedText.BodyPrimary textAlign="center">
|
<ThemedText.BodyPrimary textAlign="center">
|
||||||
<Plural
|
<Plural
|
||||||
value={listingsBelowFloor.length !== 1 ? 2 : 1}
|
value={listingsBelowFloor.length !== 1 ? 2 : 1}
|
||||||
_1={t`One NFT is listed ${(
|
_1={t`One NFT is listed ${formatDelta(
|
||||||
(1 - (listingsBelowFloor[0][1].price ?? 0) / (listingsBelowFloor[0][0].floorPrice ?? 0)) *
|
(1 - (listingsBelowFloor[0][1].price ?? 0) / (listingsBelowFloor[0][0].floorPrice ?? 0)) * 100
|
||||||
100
|
)} `}
|
||||||
).toFixed(0)}% `}
|
|
||||||
other={t`${listingsBelowFloor.length} NFTs are listed significantly `}
|
other={t`${listingsBelowFloor.length} NFTs are listed significantly `}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import useNativeCurrency from 'lib/hooks/useNativeCurrency'
|
|||||||
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
|
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
|
||||||
import { getTotalEthValue } from 'nft/components/profile/list/utils'
|
import { getTotalEthValue } from 'nft/components/profile/list/utils'
|
||||||
import { useSellAsset } from 'nft/hooks'
|
import { useSellAsset } from 'nft/hooks'
|
||||||
import { formatEth, generateTweetForList, pluralize } from 'nft/utils'
|
import { generateTweetForList, pluralize } from 'nft/utils'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { Twitter, X } from 'react-feather'
|
import { Twitter, X } from 'react-feather'
|
||||||
import styled, { css, useTheme } from 'styled-components'
|
import styled, { css, useTheme } from 'styled-components'
|
||||||
@ -77,6 +77,7 @@ const TweetRow = styled(Row)`
|
|||||||
|
|
||||||
export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => {
|
export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const { formatNumberOrString } = useFormatter()
|
||||||
const sellAssets = useSellAsset((state) => state.sellAssets)
|
const sellAssets = useSellAsset((state) => state.sellAssets)
|
||||||
const { chainId } = useWeb3React()
|
const { chainId } = useWeb3React()
|
||||||
const nativeCurrency = useNativeCurrency(chainId)
|
const nativeCurrency = useNativeCurrency(chainId)
|
||||||
@ -109,7 +110,9 @@ export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) =>
|
|||||||
<Trans>Proceeds if sold</Trans>
|
<Trans>Proceeds if sold</Trans>
|
||||||
</ThemedText.SubHeader>
|
</ThemedText.SubHeader>
|
||||||
<ProceedsColumn>
|
<ProceedsColumn>
|
||||||
<ThemedText.SubHeader>{formatEth(totalEthListingValue)} ETH</ThemedText.SubHeader>
|
<ThemedText.SubHeader>
|
||||||
|
{formatNumberOrString({ input: totalEthListingValue, type: NumberType.NFTToken })} ETH
|
||||||
|
</ThemedText.SubHeader>
|
||||||
{usdcValue && (
|
{usdcValue && (
|
||||||
<ThemedText.BodySmall lineHeight="20px" color="neutral2">
|
<ThemedText.BodySmall lineHeight="20px" color="neutral2">
|
||||||
{formatCurrencyAmount({
|
{formatCurrencyAmount({
|
||||||
|
@ -7,12 +7,12 @@ import { useUpdateInputAndWarnings } from 'nft/components/profile/list/utils'
|
|||||||
import { body } from 'nft/css/common.css'
|
import { body } from 'nft/css/common.css'
|
||||||
import { useSellAsset } from 'nft/hooks'
|
import { useSellAsset } from 'nft/hooks'
|
||||||
import { WalletAsset } from 'nft/types'
|
import { WalletAsset } from 'nft/types'
|
||||||
import { formatEth } from 'nft/utils/currency'
|
|
||||||
import { Dispatch, useRef, useState } from 'react'
|
import { Dispatch, useRef, useState } from 'react'
|
||||||
import { AlertTriangle, Link } from 'react-feather'
|
import { AlertTriangle, Link } from 'react-feather'
|
||||||
import styled, { useTheme } from 'styled-components'
|
import styled, { useTheme } from 'styled-components'
|
||||||
import { BREAKPOINTS } from 'theme'
|
import { BREAKPOINTS } from 'theme'
|
||||||
import { colors } from 'theme/colors'
|
import { colors } from 'theme/colors'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
import { WarningType } from './shared'
|
import { WarningType } from './shared'
|
||||||
|
|
||||||
@ -104,6 +104,7 @@ export const PriceTextInput = ({
|
|||||||
globalOverride,
|
globalOverride,
|
||||||
asset,
|
asset,
|
||||||
}: PriceTextInputProps) => {
|
}: PriceTextInputProps) => {
|
||||||
|
const { formatNumberOrString, formatDelta } = useFormatter()
|
||||||
const [warningType, setWarningType] = useState(WarningType.NONE)
|
const [warningType, setWarningType] = useState(WarningType.NONE)
|
||||||
const removeSellAsset = useSellAsset((state) => state.removeSellAsset)
|
const removeSellAsset = useSellAsset((state) => state.removeSellAsset)
|
||||||
const showResolveIssues = useSellAsset((state) => state.showResolveIssues)
|
const showResolveIssues = useSellAsset((state) => state.showResolveIssues)
|
||||||
@ -159,10 +160,14 @@ export const PriceTextInput = ({
|
|||||||
<WarningRow>
|
<WarningRow>
|
||||||
<AlertTriangle height={16} width={16} color={warningColor} />
|
<AlertTriangle height={16} width={16} color={warningColor} />
|
||||||
<span>
|
<span>
|
||||||
{warningType === WarningType.BELOW_FLOOR && `${percentBelowFloor.toFixed(0)}% `}
|
{warningType === WarningType.BELOW_FLOOR && `${formatDelta(percentBelowFloor)} `}
|
||||||
{getWarningMessage(warningType)}
|
{getWarningMessage(warningType)}
|
||||||
|
|
||||||
{warningType === WarningType.ALREADY_LISTED && `${formatEth(asset?.floor_sell_order_price ?? 0)} ETH`}
|
{warningType === WarningType.ALREADY_LISTED &&
|
||||||
|
`${formatNumberOrString({
|
||||||
|
input: asset?.floor_sell_order_price ?? 0,
|
||||||
|
type: NumberType.NFTToken,
|
||||||
|
})} ETH`}
|
||||||
</span>
|
</span>
|
||||||
<WarningAction
|
<WarningAction
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -3,9 +3,10 @@ import Column from 'components/Column'
|
|||||||
import Row from 'components/Row'
|
import Row from 'components/Row'
|
||||||
import { getRoyalty } from 'nft/components/profile/list/utils'
|
import { getRoyalty } from 'nft/components/profile/list/utils'
|
||||||
import { ListingMarket, WalletAsset } from 'nft/types'
|
import { ListingMarket, WalletAsset } from 'nft/types'
|
||||||
import { formatEth, getMarketplaceIcon } from 'nft/utils'
|
import { getMarketplaceIcon } from 'nft/utils'
|
||||||
import styled, { css } from 'styled-components'
|
import styled, { css } from 'styled-components'
|
||||||
import { ThemedText } from 'theme/components'
|
import { ThemedText } from 'theme/components'
|
||||||
|
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||||
|
|
||||||
const FeeWrap = styled(Row)`
|
const FeeWrap = styled(Row)`
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
@ -56,7 +57,8 @@ export const RoyaltyTooltip = ({
|
|||||||
asset: WalletAsset
|
asset: WalletAsset
|
||||||
fees?: number
|
fees?: number
|
||||||
}) => {
|
}) => {
|
||||||
const maxRoyalty = Math.max(...selectedMarkets.map((market) => getRoyalty(market, asset) ?? 0)).toFixed(2)
|
const { formatNumberOrString, formatDelta } = useFormatter()
|
||||||
|
const maxRoyalty = Math.max(...selectedMarkets.map((market) => getRoyalty(market, asset) ?? 0))
|
||||||
return (
|
return (
|
||||||
<RoyaltyContainer>
|
<RoyaltyContainer>
|
||||||
{selectedMarkets.map((market) => (
|
{selectedMarkets.map((market) => (
|
||||||
@ -68,7 +70,7 @@ export const RoyaltyTooltip = ({
|
|||||||
<Trans>fee</Trans>
|
<Trans>fee</Trans>
|
||||||
</ThemedText.BodySmall>
|
</ThemedText.BodySmall>
|
||||||
</Row>
|
</Row>
|
||||||
<FeePercent>{market.fee}%</FeePercent>
|
<FeePercent>{formatDelta(market.fee)}</FeePercent>
|
||||||
</FeeWrap>
|
</FeeWrap>
|
||||||
))}
|
))}
|
||||||
<FeeWrap>
|
<FeeWrap>
|
||||||
@ -85,7 +87,7 @@ export const RoyaltyTooltip = ({
|
|||||||
<Trans>Max fees</Trans>
|
<Trans>Max fees</Trans>
|
||||||
</ThemedText.BodySmall>
|
</ThemedText.BodySmall>
|
||||||
<ThemedText.BodySmall lineHeight="16px" color={fees ? 'neutral1' : 'neutral2'}>
|
<ThemedText.BodySmall lineHeight="16px" color={fees ? 'neutral1' : 'neutral2'}>
|
||||||
{fees ? formatEth(fees) : '-'} ETH
|
{fees ? formatNumberOrString({ input: fees, type: NumberType.NFTToken }) : '-'} ETH
|
||||||
</ThemedText.BodySmall>
|
</ThemedText.BodySmall>
|
||||||
</MaxFeeContainer>
|
</MaxFeeContainer>
|
||||||
</RoyaltyContainer>
|
</RoyaltyContainer>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Percent } from '@uniswap/sdk-core'
|
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { ClassicTrade } from 'state/routing/types'
|
import { ClassicTrade } from 'state/routing/types'
|
||||||
import { useTheme } from 'styled-components'
|
import { useTheme } from 'styled-components'
|
||||||
|
import { useFormatter } from 'utils/formatNumbers'
|
||||||
import { computeRealizedPriceImpact, getPriceImpactWarning } from 'utils/prices'
|
import { computeRealizedPriceImpact, getPriceImpactWarning } from 'utils/prices'
|
||||||
|
|
||||||
export interface PriceImpact {
|
export interface PriceImpact {
|
||||||
@ -16,6 +16,7 @@ interface PriceImpactSeverity {
|
|||||||
|
|
||||||
export function usePriceImpact(trade?: ClassicTrade): PriceImpact | undefined {
|
export function usePriceImpact(trade?: ClassicTrade): PriceImpact | undefined {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const { formatPercent } = useFormatter()
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const marketPriceImpact = trade ? computeRealizedPriceImpact(trade) : undefined
|
const marketPriceImpact = trade ? computeRealizedPriceImpact(trade) : undefined
|
||||||
@ -33,18 +34,8 @@ export function usePriceImpact(trade?: ClassicTrade): PriceImpact | undefined {
|
|||||||
type: priceImpactWarning,
|
type: priceImpactWarning,
|
||||||
color: warningColor,
|
color: warningColor,
|
||||||
},
|
},
|
||||||
displayPercentage: () => toHumanReadablePercent(marketPriceImpact),
|
displayPercentage: () => formatPercent(marketPriceImpact),
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}, [theme.critical, theme.deprecated_accentWarning, trade])
|
}, [formatPercent, theme.critical, theme.deprecated_accentWarning, trade])
|
||||||
}
|
|
||||||
|
|
||||||
function toHumanReadablePercent(priceImpact: Percent): string {
|
|
||||||
const sign = priceImpact.lessThan(0) ? '+' : ''
|
|
||||||
const exactFloat = (Number(priceImpact.numerator) / Number(priceImpact.denominator)) * 100
|
|
||||||
if (exactFloat < 0.005) {
|
|
||||||
return '0.00%'
|
|
||||||
}
|
|
||||||
const number = parseFloat(priceImpact.multiply(-1)?.toFixed(2))
|
|
||||||
return `${sign}${number}%`
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { parseEther } from 'ethers/lib/utils'
|
import { parseEther } from 'ethers/lib/utils'
|
||||||
import { ActivityEvent, GenieAsset } from 'nft/types'
|
import { ActivityEvent, GenieAsset } from 'nft/types'
|
||||||
|
|
||||||
import { formatEth } from './currency'
|
|
||||||
|
|
||||||
export const buildActivityAsset = (event: ActivityEvent, collectionName: string, ethPriceInUSD: number): GenieAsset => {
|
export const buildActivityAsset = (event: ActivityEvent, collectionName: string, ethPriceInUSD: number): GenieAsset => {
|
||||||
const assetUsdPrice = event.price ? formatEth(parseFloat(event.price) * ethPriceInUSD) : '0'
|
const assetUsdPrice = event.price ? parseFloat(event.price) * ethPriceInUSD : '0'
|
||||||
|
|
||||||
const weiPrice = event.price ? parseEther(event.price) : ''
|
const weiPrice = event.price ? parseEther(event.price) : ''
|
||||||
|
|
||||||
|
@ -1,74 +1,3 @@
|
|||||||
import { formatEther } from '@ethersproject/units'
|
|
||||||
|
|
||||||
export const formatUsdPrice = (price: number) => {
|
|
||||||
if (price > 1000000) {
|
|
||||||
return `$${(price / 1000000).toFixed(1)}M`
|
|
||||||
} else if (price > 1000) {
|
|
||||||
return `$${(price / 1000).toFixed(1)}K`
|
|
||||||
} else {
|
|
||||||
return `$${price.toFixed(2)}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const formatEth = (price: number) => {
|
|
||||||
if (price > 1000000) {
|
|
||||||
return `${Math.round(price / 1000000)}M`
|
|
||||||
} else if (price > 1000) {
|
|
||||||
return `${Math.round(price / 1000)}K`
|
|
||||||
} else if (price < 0.001) {
|
|
||||||
return '<0.001'
|
|
||||||
} else {
|
|
||||||
return `${Math.round(price * 1000 + Number.EPSILON) / 1000}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const formatUSDPriceWithCommas = (price: number) => {
|
|
||||||
return `$${Math.round(price)
|
|
||||||
.toString()
|
|
||||||
.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const formatEthPrice = (price: string | undefined) => {
|
|
||||||
if (!price) return 0
|
|
||||||
|
|
||||||
const formattedPrice = parseFloat(formatEther(String(price)))
|
|
||||||
return (
|
|
||||||
Math.round(formattedPrice * (formattedPrice >= 1 ? 100 : 1000) + Number.EPSILON) /
|
|
||||||
(formattedPrice >= 1 ? 100 : 1000)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ethNumberStandardFormatter = (
|
|
||||||
amount: string | number | undefined,
|
|
||||||
includeDollarSign = false,
|
|
||||||
removeZeroes = false,
|
|
||||||
roundToNearestWholeNumber = false
|
|
||||||
): string => {
|
|
||||||
if (!amount) return '-'
|
|
||||||
|
|
||||||
const amountInDecimals = parseFloat(amount.toString())
|
|
||||||
const conditionalDollarSign = includeDollarSign ? '$' : ''
|
|
||||||
|
|
||||||
if (amountInDecimals <= 0) return '-'
|
|
||||||
if (amountInDecimals < 0.0001) return `< ${conditionalDollarSign}0.00001`
|
|
||||||
if (amountInDecimals < 1) return `${conditionalDollarSign}${parseFloat(amountInDecimals.toFixed(3))}`
|
|
||||||
const formattedPrice = (
|
|
||||||
removeZeroes
|
|
||||||
? parseFloat(amountInDecimals.toFixed(2))
|
|
||||||
: roundToNearestWholeNumber
|
|
||||||
? Math.round(amountInDecimals)
|
|
||||||
: amountInDecimals.toFixed(2)
|
|
||||||
)
|
|
||||||
.toString()
|
|
||||||
.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
||||||
return conditionalDollarSign + formattedPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
export const formatWeiToDecimal = (amount: string, removeZeroes = false) => {
|
|
||||||
if (!amount) return '-'
|
|
||||||
return ethNumberStandardFormatter(formatEther(amount), false, removeZeroes, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent BigNumber overflow by properly handling scientific notation and comma delimited values
|
// prevent BigNumber overflow by properly handling scientific notation and comma delimited values
|
||||||
export function wrapScientificNotation(value: string | number): string {
|
export function wrapScientificNotation(value: string | number): string {
|
||||||
return parseFloat(value.toString())
|
return parseFloat(value.toString())
|
||||||
|
@ -10,21 +10,11 @@ export { blocklistedCollections } from './blocklist'
|
|||||||
export { buildNftTradeInputFromBagItems } from './buildSellObject'
|
export { buildNftTradeInputFromBagItems } from './buildSellObject'
|
||||||
export { calculateCardIndex, calculateFirstCardIndex, calculateRank } from './carousel'
|
export { calculateCardIndex, calculateFirstCardIndex, calculateRank } from './carousel'
|
||||||
export { isInSameMarketplaceCollection, isInSameSudoSwapPool } from './collection'
|
export { isInSameMarketplaceCollection, isInSameSudoSwapPool } from './collection'
|
||||||
export {
|
export { wrapScientificNotation } from './currency'
|
||||||
ethNumberStandardFormatter,
|
|
||||||
formatEth,
|
|
||||||
formatEthPrice,
|
|
||||||
formatUsdPrice,
|
|
||||||
formatUSDPriceWithCommas,
|
|
||||||
formatWeiToDecimal,
|
|
||||||
wrapScientificNotation,
|
|
||||||
} from './currency'
|
|
||||||
export { formatAssetEventProperties } from './formatEventProperties'
|
export { formatAssetEventProperties } from './formatEventProperties'
|
||||||
export { isAudio } from './isAudio'
|
export { isAudio } from './isAudio'
|
||||||
export { isVideo } from './isVideo'
|
export { isVideo } from './isVideo'
|
||||||
export { floorFormatter, volumeFormatter } from './numbers'
|
|
||||||
export { calcAvgGroupPoolPrice, calcPoolPrice, recalculateBagUsingPooledAssets } from './pooledAssets'
|
export { calcAvgGroupPoolPrice, calcPoolPrice, recalculateBagUsingPooledAssets } from './pooledAssets'
|
||||||
export { putCommas } from './putCommas'
|
|
||||||
export { pluralize, roundAndPluralize } from './roundAndPluralize'
|
export { pluralize, roundAndPluralize } from './roundAndPluralize'
|
||||||
export { timeLeft } from './time'
|
export { timeLeft } from './time'
|
||||||
export { getSuccessfulImageSize, parseTransactionResponse } from './transactionResponse'
|
export { getSuccessfulImageSize, parseTransactionResponse } from './transactionResponse'
|
||||||
|
@ -1,104 +1,3 @@
|
|||||||
import { DEFAULT_LOCALE } from 'constants/locales'
|
|
||||||
import numbro from 'numbro'
|
|
||||||
|
|
||||||
export const isNumber = (s: string): boolean => {
|
|
||||||
const reg = /^-?\d+\.?\d*$/
|
|
||||||
return reg.test(s) && !isNaN(parseFloat(s)) && isFinite(parseFloat(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
export const floorFormatter = (n: number): string => {
|
|
||||||
if (n === 0) return '0.00'
|
|
||||||
if (!n) return ''
|
|
||||||
if (n < 0.001) {
|
|
||||||
return '<0.001'
|
|
||||||
}
|
|
||||||
if (n >= 0.001 && n < 1) {
|
|
||||||
return `${parseFloat(n.toFixed(3)).toLocaleString(DEFAULT_LOCALE, {
|
|
||||||
minimumFractionDigits: 1,
|
|
||||||
maximumFractionDigits: 3,
|
|
||||||
})}`
|
|
||||||
}
|
|
||||||
if (n >= 1 && n < 1e6) {
|
|
||||||
return `${parseFloat(n.toPrecision(6)).toLocaleString(DEFAULT_LOCALE, {
|
|
||||||
minimumFractionDigits: 0,
|
|
||||||
maximumFractionDigits: 2,
|
|
||||||
})}`
|
|
||||||
}
|
|
||||||
if (n >= 1e6 && n < 1e15) {
|
|
||||||
return numbro(n)
|
|
||||||
.format({
|
|
||||||
average: true,
|
|
||||||
mantissa: 2,
|
|
||||||
optionalMantissa: true,
|
|
||||||
abbreviations: {
|
|
||||||
million: 'M',
|
|
||||||
billion: 'B',
|
|
||||||
trillion: 'T',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.toUpperCase()
|
|
||||||
}
|
|
||||||
if (n >= 1e15) {
|
|
||||||
return `${n.toExponential(3).replace(/(\.[0-9]*[1-9])0*|(\.0*)/, '$1')}`
|
|
||||||
}
|
|
||||||
return `${Number(n.toFixed(2)).toLocaleString(DEFAULT_LOCALE, { minimumFractionDigits: 2 })}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const volumeFormatter = (n: number): string => {
|
|
||||||
if (n === 0) return '0.00'
|
|
||||||
if (!n) return ''
|
|
||||||
if (n < 0.01) {
|
|
||||||
return '<0.01'
|
|
||||||
}
|
|
||||||
if (n >= 0.01 && n < 1) {
|
|
||||||
return `${parseFloat(n.toFixed(2)).toLocaleString(DEFAULT_LOCALE)}`
|
|
||||||
}
|
|
||||||
if (n >= 1 && n < 1000) {
|
|
||||||
return `${Number(Math.round(n).toLocaleString(DEFAULT_LOCALE))}`
|
|
||||||
}
|
|
||||||
if (n >= 1000) {
|
|
||||||
return numbro(n)
|
|
||||||
.format({
|
|
||||||
average: true,
|
|
||||||
mantissa: 1,
|
|
||||||
optionalMantissa: true,
|
|
||||||
abbreviations: {
|
|
||||||
thousand: 'K',
|
|
||||||
million: 'M',
|
|
||||||
billion: 'B',
|
|
||||||
trillion: 'T',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.toUpperCase()
|
|
||||||
}
|
|
||||||
return `${Number(n.toFixed(1)).toLocaleString(DEFAULT_LOCALE, { minimumFractionDigits: 1 })}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const quantityFormatter = (n: number): string => {
|
|
||||||
if (n === 0) return '0.00'
|
|
||||||
if (!n) return ''
|
|
||||||
if (n >= 1 && n < 1000) {
|
|
||||||
return `${Number(Math.round(n).toLocaleString(DEFAULT_LOCALE))}`
|
|
||||||
}
|
|
||||||
if (n >= 1000) {
|
|
||||||
return numbro(n)
|
|
||||||
.format({
|
|
||||||
average: true,
|
|
||||||
mantissa: 1,
|
|
||||||
thousandSeparated: true,
|
|
||||||
optionalMantissa: true,
|
|
||||||
abbreviations: {
|
|
||||||
thousand: 'K',
|
|
||||||
million: 'M',
|
|
||||||
billion: 'B',
|
|
||||||
trillion: 'T',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.toUpperCase()
|
|
||||||
}
|
|
||||||
return `${Number(n.toFixed(2)).toLocaleString(DEFAULT_LOCALE, { minimumFractionDigits: 2 })}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const roundWholePercentage = (n: number): string => {
|
export const roundWholePercentage = (n: number): string => {
|
||||||
if (n === 0) return '0'
|
if (n === 0) return '0'
|
||||||
if (!n) return ''
|
if (!n) return ''
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
export const putCommas = (value: number) => {
|
|
||||||
try {
|
|
||||||
if (!value) return value
|
|
||||||
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
||||||
} catch (err) {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,6 @@
|
|||||||
|
import { formatEther } from '@ethersproject/units'
|
||||||
import { BuyItem, GenieAsset, isPooledMarket, Markets, PriceInfo, RoutingItem, UpdatedGenieAsset } from 'nft/types'
|
import { BuyItem, GenieAsset, isPooledMarket, Markets, PriceInfo, RoutingItem, UpdatedGenieAsset } from 'nft/types'
|
||||||
import {
|
import { calcAvgGroupPoolPrice, isInSameMarketplaceCollection, isInSameSudoSwapPool } from 'nft/utils'
|
||||||
calcAvgGroupPoolPrice,
|
|
||||||
formatWeiToDecimal,
|
|
||||||
isInSameMarketplaceCollection,
|
|
||||||
isInSameSudoSwapPool,
|
|
||||||
} from 'nft/utils'
|
|
||||||
|
|
||||||
const isTheSame = (item: GenieAsset, routeAsset: BuyItem | PriceInfo) => {
|
const isTheSame = (item: GenieAsset, routeAsset: BuyItem | PriceInfo) => {
|
||||||
// if route asset has id, match by id
|
// if route asset has id, match by id
|
||||||
@ -21,7 +17,7 @@ const isTheSame = (item: GenieAsset, routeAsset: BuyItem | PriceInfo) => {
|
|||||||
|
|
||||||
const getPriceDiff = (oldPrice: string, newPrice: string): { hasPriceDiff: boolean; hasVisiblePriceDiff: boolean } => {
|
const getPriceDiff = (oldPrice: string, newPrice: string): { hasPriceDiff: boolean; hasVisiblePriceDiff: boolean } => {
|
||||||
const hasPriceDiff = oldPrice !== newPrice
|
const hasPriceDiff = oldPrice !== newPrice
|
||||||
const hasVisiblePriceDiff = formatWeiToDecimal(oldPrice) !== formatWeiToDecimal(newPrice)
|
const hasVisiblePriceDiff = formatEther(oldPrice) !== formatEther(newPrice)
|
||||||
|
|
||||||
return { hasPriceDiff, hasVisiblePriceDiff }
|
return { hasPriceDiff, hasVisiblePriceDiff }
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { formatEther as ethersFormatEther } from '@ethersproject/units'
|
||||||
import { Currency, CurrencyAmount, Percent, Price, Token } from '@uniswap/sdk-core'
|
import { Currency, CurrencyAmount, Percent, Price, Token } from '@uniswap/sdk-core'
|
||||||
import {
|
import {
|
||||||
DEFAULT_LOCAL_CURRENCY,
|
DEFAULT_LOCAL_CURRENCY,
|
||||||
@ -67,11 +68,23 @@ const THREE_DECIMALS_CURRENCY: NumberFormatOptions = {
|
|||||||
style: 'currency',
|
style: 'currency',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const THREE_DECIMALS_NO_TRAILING_ZEROS_CURRENCY: NumberFormatOptions = {
|
||||||
|
...THREE_DECIMALS_NO_TRAILING_ZEROS,
|
||||||
|
currency: 'USD',
|
||||||
|
style: 'currency',
|
||||||
|
}
|
||||||
|
|
||||||
const TWO_DECIMALS_NO_TRAILING_ZEROS: NumberFormatOptions = {
|
const TWO_DECIMALS_NO_TRAILING_ZEROS: NumberFormatOptions = {
|
||||||
notation: 'standard',
|
notation: 'standard',
|
||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TWO_DECIMALS_NO_TRAILING_ZEROS_CURRENCY: NumberFormatOptions = {
|
||||||
|
...TWO_DECIMALS_NO_TRAILING_ZEROS,
|
||||||
|
currency: 'USD',
|
||||||
|
style: 'currency',
|
||||||
|
}
|
||||||
|
|
||||||
const TWO_DECIMALS: NumberFormatOptions = {
|
const TWO_DECIMALS: NumberFormatOptions = {
|
||||||
notation: 'standard',
|
notation: 'standard',
|
||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
||||||
@ -97,6 +110,12 @@ const SHORTHAND_TWO_DECIMALS_NO_TRAILING_ZEROS: NumberFormatOptions = {
|
|||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SHORTHAND_TWO_DECIMALS_NO_TRAILING_ZEROS_CURRENCY: NumberFormatOptions = {
|
||||||
|
...SHORTHAND_TWO_DECIMALS_NO_TRAILING_ZEROS,
|
||||||
|
currency: 'USD',
|
||||||
|
style: 'currency',
|
||||||
|
}
|
||||||
|
|
||||||
const SHORTHAND_ONE_DECIMAL: NumberFormatOptions = {
|
const SHORTHAND_ONE_DECIMAL: NumberFormatOptions = {
|
||||||
notation: 'compact',
|
notation: 'compact',
|
||||||
minimumFractionDigits: 1,
|
minimumFractionDigits: 1,
|
||||||
@ -317,6 +336,42 @@ const ntfCollectionStatsFormatter: FormatterRule[] = [
|
|||||||
{ upperBound: Infinity, formatterOptions: SHORTHAND_ONE_DECIMAL },
|
{ upperBound: Infinity, formatterOptions: SHORTHAND_ONE_DECIMAL },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const nftTokenFormatter: FormatterRule[] = [
|
||||||
|
{ exact: 0, hardCodedInput: { hardcodedOutput: '-' }, formatterOptions: FIVE_DECIMALS_MAX_TWO_DECIMALS_MIN },
|
||||||
|
{
|
||||||
|
upperBound: 0.0001,
|
||||||
|
hardCodedInput: { input: 0.0001, prefix: '<' },
|
||||||
|
formatterOptions: FIVE_DECIMALS_MAX_TWO_DECIMALS_MIN,
|
||||||
|
},
|
||||||
|
{ upperBound: 1.0, formatterOptions: THREE_DECIMALS },
|
||||||
|
{ upperBound: 1000, formatterOptions: TWO_DECIMALS_NO_TRAILING_ZEROS },
|
||||||
|
{ upperBound: 1e15, formatterOptions: SHORTHAND_TWO_DECIMALS_NO_TRAILING_ZEROS },
|
||||||
|
{
|
||||||
|
upperBound: Infinity,
|
||||||
|
hardCodedInput: { input: 999_000_000_000_000, prefix: '>' },
|
||||||
|
formatterOptions: SHORTHAND_TWO_DECIMALS_NO_TRAILING_ZEROS,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const fiatNftTokenFormatter: FormatterRule[] = [
|
||||||
|
{ exact: 0, hardCodedInput: { hardcodedOutput: '-' }, formatterOptions: NO_DECIMALS },
|
||||||
|
{
|
||||||
|
upperBound: 0.0001,
|
||||||
|
hardCodedInput: { input: 0.0001, prefix: '<' },
|
||||||
|
formatterOptions: ONE_SIG_FIG_CURRENCY,
|
||||||
|
},
|
||||||
|
{ upperBound: 1.0, formatterOptions: THREE_DECIMALS_NO_TRAILING_ZEROS_CURRENCY },
|
||||||
|
{ upperBound: 1000, formatterOptions: TWO_DECIMALS_NO_TRAILING_ZEROS_CURRENCY },
|
||||||
|
{ upperBound: 1e15, formatterOptions: SHORTHAND_TWO_DECIMALS_NO_TRAILING_ZEROS_CURRENCY },
|
||||||
|
{
|
||||||
|
upperBound: Infinity,
|
||||||
|
hardCodedInput: { input: 999_000_000_000_000, prefix: '>' },
|
||||||
|
formatterOptions: SHORTHAND_TWO_DECIMALS_NO_TRAILING_ZEROS_CURRENCY,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const wholeNumberFormatter: FormatterRule[] = [{ upperBound: Infinity, formatterOptions: NO_DECIMALS }]
|
||||||
|
|
||||||
export enum NumberType {
|
export enum NumberType {
|
||||||
// used for token quantities in non-transaction contexts (e.g. portfolio balances)
|
// used for token quantities in non-transaction contexts (e.g. portfolio balances)
|
||||||
TokenNonTx = 'token-non-tx',
|
TokenNonTx = 'token-non-tx',
|
||||||
@ -360,6 +415,15 @@ export enum NumberType {
|
|||||||
|
|
||||||
// nft floor price with trailing zeros
|
// nft floor price with trailing zeros
|
||||||
NFTTokenFloorPriceTrailingZeros = 'nft-token-floor-price-trailing-zeros',
|
NFTTokenFloorPriceTrailingZeros = 'nft-token-floor-price-trailing-zeros',
|
||||||
|
|
||||||
|
// nft token price in currency
|
||||||
|
NFTToken = 'nft-token',
|
||||||
|
|
||||||
|
// nft token price in local fiat currency
|
||||||
|
FiatNFTToken = 'fiat-nft-token',
|
||||||
|
|
||||||
|
// whole number formatting
|
||||||
|
WholeNumber = 'whole-number',
|
||||||
}
|
}
|
||||||
|
|
||||||
type FormatterType = NumberType | FormatterRule[]
|
type FormatterType = NumberType | FormatterRule[]
|
||||||
@ -378,6 +442,9 @@ const TYPE_TO_FORMATTER_RULES = {
|
|||||||
[NumberType.NFTTokenFloorPrice]: ntfTokenFloorPriceFormatter,
|
[NumberType.NFTTokenFloorPrice]: ntfTokenFloorPriceFormatter,
|
||||||
[NumberType.NFTTokenFloorPriceTrailingZeros]: ntfTokenFloorPriceFormatterTrailingZeros,
|
[NumberType.NFTTokenFloorPriceTrailingZeros]: ntfTokenFloorPriceFormatterTrailingZeros,
|
||||||
[NumberType.NFTCollectionStats]: ntfCollectionStatsFormatter,
|
[NumberType.NFTCollectionStats]: ntfCollectionStatsFormatter,
|
||||||
|
[NumberType.NFTToken]: nftTokenFormatter,
|
||||||
|
[NumberType.FiatNFTToken]: fiatNftTokenFormatter,
|
||||||
|
[NumberType.WholeNumber]: wholeNumberFormatter,
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFormatterRule(input: number, type: FormatterType, conversionRate?: number): FormatterRule {
|
function getFormatterRule(input: number, type: FormatterType, conversionRate?: number): FormatterRule {
|
||||||
@ -563,6 +630,18 @@ function formatNumberOrString({
|
|||||||
return formatNumber({ input, type, locale, localCurrency, conversionRate })
|
return formatNumber({ input, type, locale, localCurrency, conversionRate })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FormatEtherOptions {
|
||||||
|
input: Nullish<number | string>
|
||||||
|
type: FormatterType
|
||||||
|
locale?: SupportedLocale
|
||||||
|
localCurrency?: SupportedLocalCurrency
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatEther({ input, type, locale, localCurrency }: FormatEtherOptions) {
|
||||||
|
if (input === null || input === undefined) return '-'
|
||||||
|
return formatNumber({ input: parseFloat(ethersFormatEther(input.toString())), type, locale, localCurrency })
|
||||||
|
}
|
||||||
|
|
||||||
interface FormatFiatPriceOptions {
|
interface FormatFiatPriceOptions {
|
||||||
price: Nullish<number | string>
|
price: Nullish<number | string>
|
||||||
type?: FormatterType
|
type?: FormatterType
|
||||||
@ -733,9 +812,20 @@ export function useFormatter() {
|
|||||||
[formatterLocale]
|
[formatterLocale]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const formatEtherwithLocales = useCallback(
|
||||||
|
(options: Omit<FormatEtherOptions, LocalesType>) =>
|
||||||
|
formatEther({
|
||||||
|
...options,
|
||||||
|
locale: formatterLocale,
|
||||||
|
localCurrency: currencyToFormatWith,
|
||||||
|
}),
|
||||||
|
[currencyToFormatWith, formatterLocale]
|
||||||
|
)
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
formatCurrencyAmount: formatCurrencyAmountWithLocales,
|
formatCurrencyAmount: formatCurrencyAmountWithLocales,
|
||||||
|
formatEther: formatEtherwithLocales,
|
||||||
formatFiatPrice: formatFiatPriceWithLocales,
|
formatFiatPrice: formatFiatPriceWithLocales,
|
||||||
formatNumber: formatNumberWithLocales,
|
formatNumber: formatNumberWithLocales,
|
||||||
formatNumberOrString: formatNumberOrStringWithLocales,
|
formatNumberOrString: formatNumberOrStringWithLocales,
|
||||||
@ -747,6 +837,7 @@ export function useFormatter() {
|
|||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
formatCurrencyAmountWithLocales,
|
formatCurrencyAmountWithLocales,
|
||||||
|
formatEtherwithLocales,
|
||||||
formatFiatPriceWithLocales,
|
formatFiatPriceWithLocales,
|
||||||
formatNumberOrStringWithLocales,
|
formatNumberOrStringWithLocales,
|
||||||
formatNumberWithLocales,
|
formatNumberWithLocales,
|
||||||
|
Loading…
Reference in New Issue
Block a user