Commit d9113fb6 authored by Jack Short's avatar Jack Short Committed by GitHub

feat: adding suspicious and pooled asset icons to cards + rarity (#4686)

* adding pooled assets and suspicious assets icons

* adding rarity

* better way to get states
parent 5dc0df21
...@@ -136,6 +136,24 @@ export const erc1155MinusButton = style([ ...@@ -136,6 +136,24 @@ export const erc1155MinusButton = style([
}, },
]) ])
export const rarityInfo = style([
sprinkles({
display: 'flex',
borderRadius: '4',
height: '16',
color: 'blackBlue',
background: 'lightGrayButton',
fontSize: '10',
fontWeight: 'semibold',
paddingX: '4',
}),
{
lineHeight: '12px',
letterSpacing: '0.04em',
backdropFilter: 'blur(6px)',
},
])
export const playbackSwitch = style([ export const playbackSwitch = style([
sprinkles({ sprinkles({
position: 'absolute', position: 'absolute',
......
import clsx from 'clsx' import clsx from 'clsx'
import Column from 'components/Column' import Column from 'components/Column'
import { MouseoverTooltip } from 'components/Tooltip'
import { Box } from 'nft/components/Box' import { Box } from 'nft/components/Box'
import * as styles from 'nft/components/collection/Card.css'
import { Row } from 'nft/components/Flex' import { Row } from 'nft/components/Flex'
import { MinusIconLarge, PauseButtonIcon, PlayButtonIcon, PlusIconLarge } from 'nft/components/icons' import {
MinusIconLarge,
PauseButtonIcon,
PlayButtonIcon,
PlusIconLarge,
PoolIcon,
RarityVerifiedIcon,
SuspiciousIcon20,
} from 'nft/components/icons'
import { body, subheadSmall } from 'nft/css/common.css' import { body, subheadSmall } from 'nft/css/common.css'
import { themeVars, vars } from 'nft/css/sprinkles.css' import { themeVars, vars } from 'nft/css/sprinkles.css'
import { useIsMobile } from 'nft/hooks' import { useIsMobile } from 'nft/hooks'
import { GenieAsset, UniformHeight, UniformHeights } from 'nft/types' import { GenieAsset, Rarity, UniformHeight, UniformHeights } from 'nft/types'
import { fallbackProvider, putCommas } from 'nft/utils'
import { import {
createContext, createContext,
MouseEvent, MouseEvent,
...@@ -20,6 +29,8 @@ import { ...@@ -20,6 +29,8 @@ import {
useState, useState,
} from 'react' } from 'react'
import * as styles from './Card.css'
/* -------- ASSET CONTEXT -------- */ /* -------- ASSET CONTEXT -------- */
export interface CardContextProps { export interface CardContextProps {
asset: GenieAsset asset: GenieAsset
...@@ -107,7 +118,6 @@ const Image = ({ uniformHeight, setUniformHeight }: ImageProps) => { ...@@ -107,7 +118,6 @@ const Image = ({ uniformHeight, setUniformHeight }: ImageProps) => {
<Box display="flex" overflow="hidden"> <Box display="flex" overflow="hidden">
<Box <Box
as={'img'} as={'img'}
alt={asset.name || asset.tokenId}
width="full" width="full"
style={{ style={{
aspectRatio: uniformHeight === UniformHeights.notUniform ? '1' : 'auto', aspectRatio: uniformHeight === UniformHeights.notUniform ? '1' : 'auto',
...@@ -385,7 +395,11 @@ const SecondaryRow = ({ children }: { children: ReactNode }) => ( ...@@ -385,7 +395,11 @@ const SecondaryRow = ({ children }: { children: ReactNode }) => (
</Row> </Row>
) )
const SecondaryDetails = ({ children }: { children: ReactNode }) => <Row>{children}</Row> const SecondaryDetails = ({ children }: { children: ReactNode }) => (
<Row overflow="hidden" whiteSpace="nowrap">
{children}
</Row>
)
const SecondaryInfo = ({ children }: { children: ReactNode }) => { const SecondaryInfo = ({ children }: { children: ReactNode }) => {
return ( return (
...@@ -517,6 +531,78 @@ const MarketplaceIcon = ({ marketplace }: { marketplace: string }) => { ...@@ -517,6 +531,78 @@ const MarketplaceIcon = ({ marketplace }: { marketplace: string }) => {
) )
} }
/* -------- RANKING CARD -------- */
interface RankingProps {
rarity: Rarity
provider: { url?: string; rank: number }
rarityVerified: boolean
rarityLogo?: string
}
const Ranking = ({ rarity, provider, rarityVerified, rarityLogo }: RankingProps) => {
const { asset } = useCardContext()
return (
<MouseoverTooltip
text={
<Row>
<Box display="flex" marginRight="4">
<img src={rarityLogo} alt="cardLogo" width={16} />
</Box>
<Box width="full" fontSize="14">
{rarityVerified
? `Verified by ${asset.collectionName}`
: `Ranking by ${rarity.primaryProvider === 'Genie' ? fallbackProvider : rarity.primaryProvider}`}
</Box>
</Row>
}
placement="top"
>
<Box className={styles.rarityInfo}>
<Box paddingTop="2" paddingBottom="2" display="flex">
{putCommas(provider.rank)}
</Box>
<Box display="flex" height="16">
{rarityVerified ? <RarityVerifiedIcon /> : null}
</Box>
</Box>
</MouseoverTooltip>
)
}
const Suspicious = () => {
return (
<MouseoverTooltip
text={
<Box fontSize="14">
Reported for suspicious activity
<br />
on Opensea
</Box>
}
placement="top"
>
<Box display="flex" flexShrink="0" marginLeft="2">
<SuspiciousIcon20 width="20" height="20" />
</Box>
</MouseoverTooltip>
)
}
const Pool = () => {
return (
<MouseoverTooltip
text={<Box fontSize="14">This item is part of an NFT liquidity pool. Price increases as supply decreases.</Box>}
placement="top"
>
<Box display="flex" flexShrink="0" marginLeft="4" color="darkGray">
<PoolIcon width="20" height="20" />
</Box>
</MouseoverTooltip>
)
}
interface NoContentContainerProps { interface NoContentContainerProps {
uniformHeight: UniformHeight uniformHeight: UniformHeight
} }
...@@ -578,12 +664,15 @@ export { ...@@ -578,12 +664,15 @@ export {
Image, Image,
InfoContainer, InfoContainer,
MarketplaceIcon, MarketplaceIcon,
Pool,
PrimaryDetails, PrimaryDetails,
PrimaryInfo, PrimaryInfo,
PrimaryRow, PrimaryRow,
Ranking,
SecondaryDetails, SecondaryDetails,
SecondaryInfo, SecondaryInfo,
SecondaryRow, SecondaryRow,
Suspicious,
TertiaryInfo, TertiaryInfo,
Video, Video,
} }
import { BigNumber } from '@ethersproject/bignumber' import { BigNumber } from '@ethersproject/bignumber'
import { useBag } from 'nft/hooks' import { useBag } from 'nft/hooks'
import { GenieAsset, UniformHeight } from 'nft/types' import { GenieAsset, Markets, UniformHeight } from 'nft/types'
import { formatWeiToDecimal } from 'nft/utils/currency' import { formatWeiToDecimal, isAudio, isVideo, rarityProviderLogo } from 'nft/utils'
import { isAudio } from 'nft/utils/isAudio'
import { isVideo } from 'nft/utils/isVideo'
import { MouseEvent, useMemo } from 'react' import { MouseEvent, useMemo } from 'react'
import * as Card from './Card' import * as Card from './Card'
...@@ -21,6 +19,7 @@ interface CollectionAssetProps { ...@@ -21,6 +19,7 @@ interface CollectionAssetProps {
setUniformHeight: (u: UniformHeight) => void setUniformHeight: (u: UniformHeight) => void
mediaShouldBePlaying: boolean mediaShouldBePlaying: boolean
setCurrentTokenPlayingMedia: (tokenId: string | undefined) => void setCurrentTokenPlayingMedia: (tokenId: string | undefined) => void
rarityVerified?: boolean
} }
export const CollectionAsset = ({ export const CollectionAsset = ({
...@@ -30,14 +29,13 @@ export const CollectionAsset = ({ ...@@ -30,14 +29,13 @@ export const CollectionAsset = ({
setUniformHeight, setUniformHeight,
mediaShouldBePlaying, mediaShouldBePlaying,
setCurrentTokenPlayingMedia, setCurrentTokenPlayingMedia,
rarityVerified,
}: CollectionAssetProps) => { }: CollectionAssetProps) => {
const { addAssetToBag, removeAssetFromBag, itemsInBag, bagExpanded, toggleBag } = useBag((state) => ({ const addAssetToBag = useBag((state) => state.addAssetToBag)
addAssetToBag: state.addAssetToBag, const removeAssetFromBag = useBag((state) => state.removeAssetFromBag)
removeAssetFromBag: state.removeAssetFromBag, const itemsInBag = useBag((state) => state.itemsInBag)
itemsInBag: state.itemsInBag, const bagExpanded = useBag((state) => state.bagExpanded)
bagExpanded: state.bagExpanded, const toggleBag = useBag((state) => state.toggleBag)
toggleBag: state.toggleBag,
}))
const { quantity, isSelected } = useMemo(() => { const { quantity, isSelected } = useMemo(() => {
return { return {
...@@ -67,6 +65,13 @@ export const CollectionAsset = ({ ...@@ -67,6 +65,13 @@ export const CollectionAsset = ({
} }
}, [asset]) }, [asset])
const { provider, rarityLogo } = useMemo(() => {
return {
provider: asset.rarity?.providers.find(({ provider: _provider }) => _provider === asset.rarity?.primaryProvider),
rarityLogo: rarityProviderLogo[asset.rarity?.primaryProvider ?? 0] ?? '',
}
}, [asset])
return ( return (
<Card.Container asset={asset} selected={isSelected}> <Card.Container asset={asset} selected={isSelected}>
{assetMediaType === AssetMediaType.Image ? ( {assetMediaType === AssetMediaType.Image ? (
...@@ -91,13 +96,23 @@ export const CollectionAsset = ({ ...@@ -91,13 +96,23 @@ export const CollectionAsset = ({
<Card.PrimaryRow> <Card.PrimaryRow>
<Card.PrimaryDetails> <Card.PrimaryDetails>
<Card.PrimaryInfo>{asset.name ? asset.name : `#${asset.tokenId}`}</Card.PrimaryInfo> <Card.PrimaryInfo>{asset.name ? asset.name : `#${asset.tokenId}`}</Card.PrimaryInfo>
{asset.openseaSusFlag && <Card.Suspicious />}
</Card.PrimaryDetails> </Card.PrimaryDetails>
{asset.rarity && provider && provider.rank && (
<Card.Ranking
rarity={asset.rarity}
provider={provider}
rarityVerified={!!rarityVerified}
rarityLogo={rarityLogo}
/>
)}
</Card.PrimaryRow> </Card.PrimaryRow>
<Card.SecondaryRow> <Card.SecondaryRow>
<Card.SecondaryDetails> <Card.SecondaryDetails>
<Card.SecondaryInfo> <Card.SecondaryInfo>
{notForSale ? '' : `${formatWeiToDecimal(asset.currentEthPrice)} ETH`} {notForSale ? '' : `${formatWeiToDecimal(asset.currentEthPrice)} ETH`}
</Card.SecondaryInfo> </Card.SecondaryInfo>
{(asset.marketplace === Markets.NFTX || asset.marketplace === Markets.NFT20) && <Card.Pool />}
</Card.SecondaryDetails> </Card.SecondaryDetails>
{asset.tokenType !== 'ERC1155' && asset.marketplace && ( {asset.tokenType !== 'ERC1155' && asset.marketplace && (
<Card.MarketplaceIcon marketplace={asset.marketplace} /> <Card.MarketplaceIcon marketplace={asset.marketplace} />
......
...@@ -16,9 +16,10 @@ import { useInfiniteQuery } from 'react-query' ...@@ -16,9 +16,10 @@ import { useInfiniteQuery } from 'react-query'
interface CollectionNftsProps { interface CollectionNftsProps {
contractAddress: string contractAddress: string
rarityVerified?: boolean
} }
export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => { export const CollectionNfts = ({ contractAddress, rarityVerified }: CollectionNftsProps) => {
const traits = useCollectionFilters((state) => state.traits) const traits = useCollectionFilters((state) => state.traits)
const minPrice = useCollectionFilters((state) => state.minPrice) const minPrice = useCollectionFilters((state) => state.minPrice)
const maxPrice = useCollectionFilters((state) => state.maxPrice) const maxPrice = useCollectionFilters((state) => state.maxPrice)
...@@ -127,6 +128,7 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => { ...@@ -127,6 +128,7 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => {
setUniformHeight={setUniformHeight} setUniformHeight={setUniformHeight}
mediaShouldBePlaying={asset.tokenId === currentTokenPlayingMedia} mediaShouldBePlaying={asset.tokenId === currentTokenPlayingMedia}
setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia} setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia}
rarityVerified={rarityVerified}
/> />
) : null ) : null
})} })}
......
...@@ -596,7 +596,7 @@ export const ShoppingCartIcon = (props: SVGProps) => ( ...@@ -596,7 +596,7 @@ export const ShoppingCartIcon = (props: SVGProps) => (
/> />
</svg> </svg>
) )
export const RarityVerified = () => ( export const RarityVerifiedIcon = () => (
<svg width="17" height="17" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="17" height="17" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <path
d="M4.5686 3.53439C4.74662 3.33093 5.0038 3.21423 5.27414 3.21423L10.1451 3.21423C10.4154 3.21423 10.6726 3.33093 10.8506 3.53438L13.0437 6.04077C13.3654 6.40839 13.3509 6.96139 13.0104 7.31163L8.38181 12.0724C8.01367 12.4511 7.40558 12.4511 7.03744 12.0724L2.40887 7.31163C2.06836 6.96139 2.05385 6.40839 2.37552 6.04077L4.5686 3.53439Z" d="M4.5686 3.53439C4.74662 3.33093 5.0038 3.21423 5.27414 3.21423L10.1451 3.21423C10.4154 3.21423 10.6726 3.33093 10.8506 3.53438L13.0437 6.04077C13.3654 6.40839 13.3509 6.96139 13.0104 7.31163L8.38181 12.0724C8.01367 12.4511 7.40558 12.4511 7.03744 12.0724L2.40887 7.31163C2.06836 6.96139 2.05385 6.40839 2.37552 6.04077L4.5686 3.53439Z"
......
...@@ -74,7 +74,9 @@ const Collection = () => { ...@@ -74,7 +74,9 @@ const Collection = () => {
width: gridWidthOffset.interpolate((x) => `calc(100% - ${x as number}px)`), width: gridWidthOffset.interpolate((x) => `calc(100% - ${x as number}px)`),
}} }}
> >
{contractAddress && <CollectionNfts contractAddress={contractAddress} />} {contractAddress && (
<CollectionNfts contractAddress={contractAddress} rarityVerified={collectionStats?.rarityVerified} />
)}
</AnimatedBox> </AnimatedBox>
</Row> </Row>
</Column> </Column>
......
...@@ -2,4 +2,8 @@ export * from './buildActivityAsset' ...@@ -2,4 +2,8 @@ export * from './buildActivityAsset'
export * from './buildSellObject' export * from './buildSellObject'
export * from './calcPoolPrice' export * from './calcPoolPrice'
export * from './currency' export * from './currency'
export * from './isAudio'
export * from './isVideo'
export * from './listNfts' export * from './listNfts'
export * from './putCommas'
export * from './rarity'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment