refactor: remove graphql flag and default to gql endpoints (#5151)
* remove graphql flag and old endpoints * remove unused queries * deprecate old sell order type * better null checks * merge conflict
This commit is contained in:
parent
37d2603406
commit
dbf5c63ece
@ -1,6 +1,5 @@
|
|||||||
import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags'
|
import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags'
|
||||||
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
|
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
|
||||||
import { NftGraphQlVariant, useNftGraphQlFlag } from 'featureFlags/flags/nftGraphQl'
|
|
||||||
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
|
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
|
||||||
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
|
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
|
||||||
import { Children, PropsWithChildren, ReactElement, ReactNode, useCallback, useState } from 'react'
|
import { Children, PropsWithChildren, ReactElement, ReactNode, useCallback, useState } from 'react'
|
||||||
@ -205,12 +204,6 @@ export default function FeatureFlagModal() {
|
|||||||
</Header>
|
</Header>
|
||||||
<FeatureFlagGroup name="Phase 1">
|
<FeatureFlagGroup name="Phase 1">
|
||||||
<FeatureFlagOption variant={NftVariant} value={useNftFlag()} featureFlag={FeatureFlag.nft} label="NFTs" />
|
<FeatureFlagOption variant={NftVariant} value={useNftFlag()} featureFlag={FeatureFlag.nft} label="NFTs" />
|
||||||
<FeatureFlagOption
|
|
||||||
variant={NftGraphQlVariant}
|
|
||||||
value={useNftGraphQlFlag()}
|
|
||||||
featureFlag={FeatureFlag.nftGraphQl}
|
|
||||||
label="NFT GraphQL Endpoints"
|
|
||||||
/>
|
|
||||||
</FeatureFlagGroup>
|
</FeatureFlagGroup>
|
||||||
<FeatureFlagGroup name="Debug">
|
<FeatureFlagGroup name="Debug">
|
||||||
<FeatureFlagOption
|
<FeatureFlagOption
|
||||||
|
@ -3,5 +3,4 @@ export enum FeatureFlag {
|
|||||||
nft = 'nfts',
|
nft = 'nfts',
|
||||||
traceJsonRpc = 'traceJsonRpc',
|
traceJsonRpc = 'traceJsonRpc',
|
||||||
multiNetworkBalances = 'multiNetworkBalances',
|
multiNetworkBalances = 'multiNetworkBalances',
|
||||||
nftGraphQl = 'nftGraphQl',
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
|
|
||||||
|
|
||||||
export function useNftGraphQlFlag(): BaseVariant {
|
|
||||||
return useBaseFlag(FeatureFlag.nftGraphQl)
|
|
||||||
}
|
|
||||||
|
|
||||||
export { BaseVariant as NftGraphQlVariant }
|
|
@ -4,7 +4,6 @@ import { TraceEvent } from 'analytics/TraceEvent'
|
|||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { loadingAnimation } from 'components/Loader/styled'
|
import { loadingAnimation } from 'components/Loader/styled'
|
||||||
import { parseEther } from 'ethers/lib/utils'
|
import { parseEther } from 'ethers/lib/utils'
|
||||||
import { NftGraphQlVariant, useNftGraphQlFlag } from 'featureFlags/flags/nftGraphQl'
|
|
||||||
import { NftAssetTraitInput, NftMarketplace } from 'graphql/data/nft/__generated__/AssetQuery.graphql'
|
import { NftAssetTraitInput, NftMarketplace } from 'graphql/data/nft/__generated__/AssetQuery.graphql'
|
||||||
import { useAssetsQuery } from 'graphql/data/nft/Asset'
|
import { useAssetsQuery } from 'graphql/data/nft/Asset'
|
||||||
import useDebounce from 'hooks/useDebounce'
|
import useDebounce from 'hooks/useDebounce'
|
||||||
@ -30,7 +29,6 @@ import {
|
|||||||
} from 'nft/hooks'
|
} from 'nft/hooks'
|
||||||
import { useIsCollectionLoading } from 'nft/hooks/useIsCollectionLoading'
|
import { useIsCollectionLoading } from 'nft/hooks/useIsCollectionLoading'
|
||||||
import { usePriceRange } from 'nft/hooks/usePriceRange'
|
import { usePriceRange } from 'nft/hooks/usePriceRange'
|
||||||
import { AssetsFetcher } from 'nft/queries'
|
|
||||||
import { DropDownOption, GenieCollection, TokenType, UniformHeight, UniformHeights } from 'nft/types'
|
import { DropDownOption, GenieCollection, TokenType, UniformHeight, UniformHeights } from 'nft/types'
|
||||||
import { getRarityStatus } from 'nft/utils/asset'
|
import { getRarityStatus } from 'nft/utils/asset'
|
||||||
import { pluralize } from 'nft/utils/roundAndPluralize'
|
import { pluralize } from 'nft/utils/roundAndPluralize'
|
||||||
@ -38,7 +36,6 @@ import { scrollToTop } from 'nft/utils/scrollToTop'
|
|||||||
import { applyFiltersFromURL, syncLocalFiltersWithURL } from 'nft/utils/urlParams'
|
import { applyFiltersFromURL, syncLocalFiltersWithURL } from 'nft/utils/urlParams'
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import InfiniteScroll from 'react-infinite-scroll-component'
|
import InfiniteScroll from 'react-infinite-scroll-component'
|
||||||
import { useInfiniteQuery } from 'react-query'
|
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { ThemedText } from 'theme'
|
import { ThemedText } from 'theme'
|
||||||
@ -223,7 +220,6 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
|||||||
const reset = useCollectionFilters((state) => state.reset)
|
const reset = useCollectionFilters((state) => state.reset)
|
||||||
const setMin = useCollectionFilters((state) => state.setMinPrice)
|
const setMin = useCollectionFilters((state) => state.setMinPrice)
|
||||||
const setMax = useCollectionFilters((state) => state.setMaxPrice)
|
const setMax = useCollectionFilters((state) => state.setMaxPrice)
|
||||||
const isNftGraphQl = useNftGraphQlFlag() === NftGraphQlVariant.Enabled
|
|
||||||
|
|
||||||
const toggleBag = useBag((state) => state.toggleBag)
|
const toggleBag = useBag((state) => state.toggleBag)
|
||||||
const bagExpanded = useBag((state) => state.bagExpanded)
|
const bagExpanded = useBag((state) => state.bagExpanded)
|
||||||
@ -235,75 +231,12 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
|||||||
const [sweepIsOpen, setSweepOpen] = useState(false)
|
const [sweepIsOpen, setSweepOpen] = useState(false)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: collectionAssets,
|
assets: collectionNfts,
|
||||||
isSuccess: AssetsFetchSuccess,
|
|
||||||
isLoading,
|
|
||||||
fetchNextPage,
|
|
||||||
hasNextPage,
|
|
||||||
} = useInfiniteQuery(
|
|
||||||
[
|
|
||||||
'collectionNfts',
|
|
||||||
{
|
|
||||||
traits,
|
|
||||||
contractAddress,
|
|
||||||
markets,
|
|
||||||
notForSale: !buyNow,
|
|
||||||
sortBy,
|
|
||||||
debouncedMinPrice,
|
|
||||||
debouncedMaxPrice,
|
|
||||||
searchText: debouncedSearchByNameText,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
async ({ pageParam = 0 }) => {
|
|
||||||
let sort = undefined
|
|
||||||
switch (sortBy) {
|
|
||||||
case SortBy.HighToLow: {
|
|
||||||
sort = { currentEthPrice: 'desc' }
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case SortBy.RareToCommon: {
|
|
||||||
sort = { 'rarity.providers.0.rank': 1 }
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case SortBy.CommonToRare: {
|
|
||||||
sort = { 'rarity.providers.0.rank': -1 }
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
return await AssetsFetcher({
|
|
||||||
contractAddress,
|
|
||||||
sort,
|
|
||||||
markets,
|
|
||||||
notForSale: !buyNow,
|
|
||||||
searchText: debouncedSearchByNameText,
|
|
||||||
pageParam,
|
|
||||||
traits,
|
|
||||||
price: {
|
|
||||||
low: debouncedMinPrice,
|
|
||||||
high: debouncedMaxPrice,
|
|
||||||
symbol: 'ETH',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
getNextPageParam: (lastPage, pages) => {
|
|
||||||
return lastPage?.flat().length === DEFAULT_ASSET_QUERY_AMOUNT ? pages.length : null
|
|
||||||
},
|
|
||||||
refetchOnReconnect: false,
|
|
||||||
refetchOnWindowFocus: false,
|
|
||||||
refetchOnMount: false,
|
|
||||||
refetchInterval: 5000,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const {
|
|
||||||
assets: nftQueryAssets,
|
|
||||||
loadNext,
|
loadNext,
|
||||||
hasNext,
|
hasNext,
|
||||||
isLoadingNext,
|
isLoadingNext,
|
||||||
} = useAssetsQuery(
|
} = useAssetsQuery(
|
||||||
isNftGraphQl ? contractAddress : '',
|
contractAddress,
|
||||||
SortByQueries[sortBy].field,
|
SortByQueries[sortBy].field,
|
||||||
SortByQueries[sortBy].asc,
|
SortByQueries[sortBy].asc,
|
||||||
{
|
{
|
||||||
@ -328,23 +261,9 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
|||||||
const oldStateRef = useRef<CollectionFilters | null>(null)
|
const oldStateRef = useRef<CollectionFilters | null>(null)
|
||||||
const isMobile = useIsMobile()
|
const isMobile = useIsMobile()
|
||||||
|
|
||||||
const collectionNfts = useMemo(() => {
|
|
||||||
if (
|
|
||||||
(isNftGraphQl && !nftQueryAssets && !isLoadingNext) ||
|
|
||||||
(!isNftGraphQl && !collectionAssets) ||
|
|
||||||
!AssetsFetchSuccess
|
|
||||||
)
|
|
||||||
return undefined
|
|
||||||
|
|
||||||
return isNftGraphQl ? nftQueryAssets : collectionAssets?.pages.flat()
|
|
||||||
}, [AssetsFetchSuccess, collectionAssets, isLoadingNext, isNftGraphQl, nftQueryAssets])
|
|
||||||
|
|
||||||
const wrappedLoadingState = isNftGraphQl ? isLoadingNext : isLoading
|
|
||||||
const wrappedHasNext = isNftGraphQl ? hasNext : hasNextPage ?? false
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsCollectionNftsLoading(wrappedLoadingState)
|
setIsCollectionNftsLoading(isLoadingNext)
|
||||||
}, [wrappedLoadingState, setIsCollectionNftsLoading])
|
}, [isLoadingNext, setIsCollectionNftsLoading])
|
||||||
|
|
||||||
const hasRarity = getRarityStatus(rarityStatusCache, collectionStats?.address, collectionNfts)
|
const hasRarity = getRarityStatus(rarityStatusCache, collectionStats?.address, collectionNfts)
|
||||||
|
|
||||||
@ -508,9 +427,6 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
|||||||
<CollectionSearch />
|
<CollectionSearch />
|
||||||
</ActionsSubContainer>
|
</ActionsSubContainer>
|
||||||
{!hasErc1155s ? (
|
{!hasErc1155s ? (
|
||||||
isLoading ? (
|
|
||||||
<LoadingButton />
|
|
||||||
) : (
|
|
||||||
<SweepButton
|
<SweepButton
|
||||||
toggled={sweepIsOpen}
|
toggled={sweepIsOpen}
|
||||||
disabled={!buyNow}
|
disabled={!buyNow}
|
||||||
@ -529,7 +445,6 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
|||||||
Sweep
|
Sweep
|
||||||
</SweepText>
|
</SweepText>
|
||||||
</SweepButton>
|
</SweepButton>
|
||||||
)
|
|
||||||
) : null}
|
) : null}
|
||||||
</ActionsContainer>
|
</ActionsContainer>
|
||||||
<Sweep
|
<Sweep
|
||||||
@ -593,12 +508,12 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
|||||||
</Box>
|
</Box>
|
||||||
</AnimatedBox>
|
</AnimatedBox>
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
next={() => (isNftGraphQl ? loadNext(DEFAULT_ASSET_QUERY_AMOUNT) : fetchNextPage())}
|
next={() => loadNext(DEFAULT_ASSET_QUERY_AMOUNT)}
|
||||||
hasMore={wrappedHasNext}
|
hasMore={hasNext}
|
||||||
loader={wrappedHasNext && hasNfts ? loadingAssets : null}
|
loader={hasNext && hasNfts ? loadingAssets : null}
|
||||||
dataLength={collectionNfts?.length ?? 0}
|
dataLength={collectionNfts?.length ?? 0}
|
||||||
style={{ overflow: 'unset' }}
|
style={{ overflow: 'unset' }}
|
||||||
className={hasNfts || wrappedLoadingState ? styles.assetList : undefined}
|
className={hasNfts || isLoadingNext ? styles.assetList : undefined}
|
||||||
>
|
>
|
||||||
{hasNfts ? (
|
{hasNfts ? (
|
||||||
Nfts
|
Nfts
|
||||||
@ -617,10 +532,8 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
|||||||
</Box>
|
</Box>
|
||||||
</EmptyCollectionWrapper>
|
</EmptyCollectionWrapper>
|
||||||
</Center>
|
</Center>
|
||||||
) : isNftGraphQl ? (
|
|
||||||
<CollectionNftsLoading />
|
|
||||||
) : (
|
) : (
|
||||||
loadingAssets
|
<CollectionNftsLoading />
|
||||||
)}
|
)}
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
</>
|
</>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { getDeltaArrow } from 'components/Tokens/TokenDetails/PriceChart'
|
import { getDeltaArrow } from 'components/Tokens/TokenDetails/PriceChart'
|
||||||
import { NftGraphQlVariant, useNftGraphQlFlag } from 'featureFlags/flags/nftGraphQl'
|
|
||||||
import { Box, BoxProps } from 'nft/components/Box'
|
import { Box, BoxProps } from 'nft/components/Box'
|
||||||
import { Column, Row } from 'nft/components/Flex'
|
import { Column, Row } from 'nft/components/Flex'
|
||||||
import { Marquee } from 'nft/components/layout/Marquee'
|
import { Marquee } from 'nft/components/layout/Marquee'
|
||||||
@ -266,14 +265,11 @@ 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 isNftGraphQl = useNftGraphQlFlag() === NftGraphQlVariant.Enabled
|
const uniqueOwnersPercentage = stats?.stats?.total_supply
|
||||||
const uniqueOwnersPercentage =
|
|
||||||
stats.stats && 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 ? quantityFormatter(stats.stats.total_supply ?? 0) : 0
|
||||||
const listedPercentageStr =
|
const listedPercentageStr = stats?.stats?.total_supply
|
||||||
stats.stats && 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)
|
||||||
@ -282,15 +278,8 @@ const StatsRow = ({ stats, isMobile, ...props }: { stats: GenieCollection; isMob
|
|||||||
const totalVolumeStr = volumeFormatter(stats.stats?.total_volume ?? 0)
|
const totalVolumeStr = volumeFormatter(stats.stats?.total_volume ?? 0)
|
||||||
const floorPriceStr = floorFormatter(stats.stats?.floor_price ?? 0)
|
const floorPriceStr = floorFormatter(stats.stats?.floor_price ?? 0)
|
||||||
// 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
|
||||||
// TODO: remove feature flag gated logic when graphql migration is complete
|
const floorChangeStr = Math.round(Math.abs(stats?.stats?.one_day_floor_change ?? 0))
|
||||||
const floorChangeStr =
|
const arrow = stats?.stats?.one_day_floor_change ? getDeltaArrow(stats.stats.one_day_floor_change) : undefined
|
||||||
stats.stats && stats.stats.one_day_floor_change
|
|
||||||
? Math.round(Math.abs(stats.stats.one_day_floor_change) * (isNftGraphQl ? 1 : 100))
|
|
||||||
: 0
|
|
||||||
const arrow =
|
|
||||||
stats.stats && stats.stats.one_day_floor_change !== undefined
|
|
||||||
? getDeltaArrow(stats.stats.one_day_floor_change)
|
|
||||||
: null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row gap={{ sm: '36', md: '60' }} {...props}>
|
<Row gap={{ sm: '36', md: '60' }} {...props}>
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import { sendAnalyticsEvent } from 'analytics'
|
import { sendAnalyticsEvent } from 'analytics'
|
||||||
import { EventName, FilterTypes } from 'analytics/constants'
|
import { EventName, FilterTypes } from 'analytics/constants'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { NftGraphQlVariant, useNftGraphQlFlag } from 'featureFlags/flags/nftGraphQl'
|
|
||||||
import { Box } from 'nft/components/Box'
|
import { Box } from 'nft/components/Box'
|
||||||
import * as styles from 'nft/components/collection/Filters.css'
|
import * as styles from 'nft/components/collection/Filters.css'
|
||||||
import { Column, Row } from 'nft/components/Flex'
|
import { Column, Row } from 'nft/components/Flex'
|
||||||
import { ChevronUpIcon } from 'nft/components/icons'
|
import { ChevronUpIcon } from 'nft/components/icons'
|
||||||
import { subheadSmall } from 'nft/css/common.css'
|
import { subheadSmall } from 'nft/css/common.css'
|
||||||
import { useCollectionFilters } from 'nft/hooks/useCollectionFilters'
|
import { useCollectionFilters } from 'nft/hooks/useCollectionFilters'
|
||||||
import { useTraitsOpen } from 'nft/hooks/useTraitsOpen'
|
import { TraitPosition, useTraitsOpen } from 'nft/hooks/useTraitsOpen'
|
||||||
import { TraitPosition } from 'nft/hooks/useTraitsOpen'
|
|
||||||
import { FormEvent, useEffect, useMemo, useReducer, useState } from 'react'
|
import { FormEvent, useEffect, useMemo, useReducer, useState } from 'react'
|
||||||
|
|
||||||
import { Checkbox } from '../layout/Checkbox'
|
import { Checkbox } from '../layout/Checkbox'
|
||||||
@ -87,8 +85,6 @@ const MarketplaceItem = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const GRAPHQL_MARKETS = ['cryptopunks', 'sudoswap']
|
|
||||||
|
|
||||||
export const MarketplaceSelect = () => {
|
export const MarketplaceSelect = () => {
|
||||||
const {
|
const {
|
||||||
addMarket,
|
addMarket,
|
||||||
@ -104,13 +100,10 @@ export const MarketplaceSelect = () => {
|
|||||||
|
|
||||||
const [isOpen, setOpen] = useState(!!selectedMarkets.length)
|
const [isOpen, setOpen] = useState(!!selectedMarkets.length)
|
||||||
const setTraitsOpen = useTraitsOpen((state) => state.setTraitsOpen)
|
const setTraitsOpen = useTraitsOpen((state) => state.setTraitsOpen)
|
||||||
const isNftGraphQl = useNftGraphQlFlag() === NftGraphQlVariant.Enabled
|
|
||||||
|
|
||||||
const MarketplaceItems = useMemo(
|
const MarketplaceItems = useMemo(
|
||||||
() =>
|
() =>
|
||||||
Object.entries(MARKETPLACE_ITEMS)
|
Object.entries(MARKETPLACE_ITEMS).map(([value, title]) => (
|
||||||
.filter(([value]) => isNftGraphQl || !GRAPHQL_MARKETS.includes(value))
|
|
||||||
.map(([value, title]) => (
|
|
||||||
<MarketplaceItem
|
<MarketplaceItem
|
||||||
key={value}
|
key={value}
|
||||||
title={title}
|
title={title}
|
||||||
@ -119,7 +112,7 @@ export const MarketplaceSelect = () => {
|
|||||||
{...{ addMarket, removeMarket, isMarketSelected: selectedMarkets.includes(value) }}
|
{...{ addMarket, removeMarket, isMarketSelected: selectedMarkets.includes(value) }}
|
||||||
/>
|
/>
|
||||||
)),
|
)),
|
||||||
[addMarket, isNftGraphQl, marketCount, removeMarket, selectedMarkets]
|
[addMarket, marketCount, removeMarket, selectedMarkets]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -7,13 +7,7 @@ import { AssetPriceDetails } from 'nft/components/details/AssetPriceDetails'
|
|||||||
import { Center } from 'nft/components/Flex'
|
import { Center } from 'nft/components/Flex'
|
||||||
import { VerifiedIcon } from 'nft/components/icons'
|
import { VerifiedIcon } from 'nft/components/icons'
|
||||||
import { ActivityFetcher } from 'nft/queries/genie/ActivityFetcher'
|
import { ActivityFetcher } from 'nft/queries/genie/ActivityFetcher'
|
||||||
import {
|
import { ActivityEventResponse, ActivityEventType, CollectionInfoForAsset, GenieAsset } from 'nft/types'
|
||||||
ActivityEventResponse,
|
|
||||||
ActivityEventType,
|
|
||||||
CollectionInfoForAsset,
|
|
||||||
GenieAsset,
|
|
||||||
GenieCollection,
|
|
||||||
} from 'nft/types'
|
|
||||||
import { shortenAddress } from 'nft/utils/address'
|
import { shortenAddress } from 'nft/utils/address'
|
||||||
import { formatEthPrice } from 'nft/utils/currency'
|
import { formatEthPrice } from 'nft/utils/currency'
|
||||||
import { isAudio } from 'nft/utils/isAudio'
|
import { isAudio } from 'nft/utils/isAudio'
|
||||||
@ -281,10 +275,9 @@ enum MediaType {
|
|||||||
interface AssetDetailsProps {
|
interface AssetDetailsProps {
|
||||||
asset: GenieAsset
|
asset: GenieAsset
|
||||||
collection: CollectionInfoForAsset
|
collection: CollectionInfoForAsset
|
||||||
collectionStats: GenieCollection | undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AssetDetails = ({ asset, collection, collectionStats }: AssetDetailsProps) => {
|
export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
|
||||||
const [dominantColor] = useState<[number, number, number]>([0, 0, 0])
|
const [dominantColor] = useState<[number, number, number]>([0, 0, 0])
|
||||||
|
|
||||||
const { rarityProvider } = useMemo(
|
const { rarityProvider } = useMemo(
|
||||||
@ -405,12 +398,6 @@ export const AssetDetails = ({ asset, collection, collectionStats }: AssetDetail
|
|||||||
[isSuccess, eventsData]
|
[isSuccess, eventsData]
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: remove after switching to graphql
|
|
||||||
const externalUrl = collection.externalUrl ?? collectionStats?.externalUrl
|
|
||||||
const twitterUrl = collection.twitterUrl ?? collectionStats?.twitterUrl
|
|
||||||
const discordUrl = collection.discordUrl ?? collectionStats?.discordUrl
|
|
||||||
const isVerified = collection.isVerified ?? collectionStats?.isVerified
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column>
|
<Column>
|
||||||
<MediaContainer>
|
<MediaContainer>
|
||||||
@ -429,7 +416,7 @@ export const AssetDetails = ({ asset, collection, collectionStats }: AssetDetail
|
|||||||
</MediaContainer>
|
</MediaContainer>
|
||||||
<DefaultLink to={`/nfts/collection/${asset.address}`}>
|
<DefaultLink to={`/nfts/collection/${asset.address}`}>
|
||||||
<CollectionHeader>
|
<CollectionHeader>
|
||||||
{collection.collectionName} {isVerified && <VerifiedIcon />}
|
{collection.collectionName} {collection.isVerified && <VerifiedIcon />}
|
||||||
</CollectionHeader>
|
</CollectionHeader>
|
||||||
</DefaultLink>
|
</DefaultLink>
|
||||||
|
|
||||||
@ -449,9 +436,7 @@ export const AssetDetails = ({ asset, collection, collectionStats }: AssetDetail
|
|||||||
<img src={rarityProviderLogo} alt="cardLogo" width={16} />
|
<img src={rarityProviderLogo} alt="cardLogo" width={16} />
|
||||||
</HoverImageContainer>
|
</HoverImageContainer>
|
||||||
<ContainerText>
|
<ContainerText>
|
||||||
{collectionStats?.rarityVerified
|
{`Ranking by ${rarity.provider === 'Genie' ? fallbackProvider : rarity.provider}`}
|
||||||
? `Verified by ${collectionStats?.name}`
|
|
||||||
: `Ranking by ${rarity.provider === 'Genie' ? fallbackProvider : rarity.provider}`}
|
|
||||||
</ContainerText>
|
</ContainerText>
|
||||||
</HoverContainer>
|
</HoverContainer>
|
||||||
}
|
}
|
||||||
@ -514,9 +499,9 @@ export const AssetDetails = ({ asset, collection, collectionStats }: AssetDetail
|
|||||||
|
|
||||||
<DescriptionText>{collection.collectionDescription}</DescriptionText>
|
<DescriptionText>{collection.collectionDescription}</DescriptionText>
|
||||||
<SocialsContainer>
|
<SocialsContainer>
|
||||||
{externalUrl && <Resource name="Website" link={`${externalUrl}`} />}
|
{collection.externalUrl && <Resource name="Website" link={`${collection.externalUrl}`} />}
|
||||||
{twitterUrl && <Resource name="Twitter" link={`https://twitter.com/${twitterUrl}`} />}
|
{collection.twitterUrl && <Resource name="Twitter" link={`https://twitter.com/${collection.twitterUrl}`} />}
|
||||||
{discordUrl && <Resource name="Discord" link={discordUrl} />}
|
{collection.discordUrl && <Resource name="Discord" link={collection.discordUrl} />}
|
||||||
</SocialsContainer>
|
</SocialsContainer>
|
||||||
</>
|
</>
|
||||||
</InfoContainer>
|
</InfoContainer>
|
||||||
|
@ -2,7 +2,7 @@ import { useWeb3React } from '@web3-react/core'
|
|||||||
import useCopyClipboard from 'hooks/useCopyClipboard'
|
import useCopyClipboard from 'hooks/useCopyClipboard'
|
||||||
import { CancelListingIcon, MinusIcon, PlusIcon } from 'nft/components/icons'
|
import { CancelListingIcon, MinusIcon, PlusIcon } from 'nft/components/icons'
|
||||||
import { useBag } from 'nft/hooks'
|
import { useBag } from 'nft/hooks'
|
||||||
import { CollectionInfoForAsset, Deprecated_SellOrder, GenieAsset, SellOrder, TokenType } from 'nft/types'
|
import { CollectionInfoForAsset, GenieAsset, TokenType } from 'nft/types'
|
||||||
import { ethNumberStandardFormatter, formatEthPrice, getMarketplaceIcon, timeLeft, useUsdPrice } from 'nft/utils'
|
import { ethNumberStandardFormatter, formatEthPrice, getMarketplaceIcon, timeLeft, useUsdPrice } from 'nft/utils'
|
||||||
import { shortenAddress } from 'nft/utils/address'
|
import { shortenAddress } from 'nft/utils/address'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
@ -203,9 +203,7 @@ const OwnerInformationContainer = styled.div`
|
|||||||
export const OwnerContainer = ({ asset }: { asset: GenieAsset }) => {
|
export const OwnerContainer = ({ asset }: { asset: GenieAsset }) => {
|
||||||
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 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
|
const expirationDate = cheapestOrder ? new Date(cheapestOrder.endAt) : undefined
|
||||||
? new Date((cheapestOrder as Deprecated_SellOrder).orderClosingDate ?? (cheapestOrder as SellOrder).endAt)
|
|
||||||
: undefined
|
|
||||||
const USDPrice = useUsdPrice(asset)
|
const USDPrice = useUsdPrice(asset)
|
||||||
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@ -288,9 +286,7 @@ export const AssetPriceDetails = ({ asset, collection }: AssetPriceDetailsProps)
|
|||||||
const { account } = useWeb3React()
|
const { account } = useWeb3React()
|
||||||
|
|
||||||
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
|
const expirationDate = cheapestOrder ? new Date(cheapestOrder.endAt) : undefined
|
||||||
? new Date((cheapestOrder as Deprecated_SellOrder).orderClosingDate ?? (cheapestOrder as SellOrder).endAt)
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const itemsInBag = useBag((s) => s.itemsInBag)
|
const itemsInBag = useBag((s) => s.itemsInBag)
|
||||||
const addAssetsToBag = useBag((s) => s.addAssetsToBag)
|
const addAssetsToBag = useBag((s) => s.addAssetsToBag)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { NftGraphQlVariant, useNftGraphQlFlag } from 'featureFlags/flags/nftGraphQl'
|
|
||||||
import { useNftBalanceQuery } from 'graphql/data/nft/NftBalance'
|
import { useNftBalanceQuery } from 'graphql/data/nft/NftBalance'
|
||||||
import { AnimatedBox, Box } from 'nft/components/Box'
|
import { AnimatedBox, Box } from 'nft/components/Box'
|
||||||
import { assetList } from 'nft/components/collection/CollectionNfts.css'
|
import { assetList } from 'nft/components/collection/CollectionNfts.css'
|
||||||
@ -18,11 +17,11 @@ import {
|
|||||||
useWalletCollections,
|
useWalletCollections,
|
||||||
} from 'nft/hooks'
|
} from 'nft/hooks'
|
||||||
import { ScreenBreakpointsPaddings } from 'nft/pages/collection/index.css'
|
import { ScreenBreakpointsPaddings } from 'nft/pages/collection/index.css'
|
||||||
import { fetchWalletAssets, OSCollectionsFetcher } from 'nft/queries'
|
import { OSCollectionsFetcher } from 'nft/queries'
|
||||||
import { ProfilePageStateType, WalletAsset, WalletCollection } from 'nft/types'
|
import { ProfilePageStateType, WalletAsset, WalletCollection } from 'nft/types'
|
||||||
import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react'
|
import { Dispatch, SetStateAction, useCallback, useEffect, useState } from 'react'
|
||||||
import InfiniteScroll from 'react-infinite-scroll-component'
|
import InfiniteScroll from 'react-infinite-scroll-component'
|
||||||
import { useInfiniteQuery, useQuery } from 'react-query'
|
import { useQuery } from 'react-query'
|
||||||
import { useSpring } from 'react-spring'
|
import { useSpring } from 'react-spring'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import shallow from 'zustand/shallow'
|
import shallow from 'zustand/shallow'
|
||||||
@ -30,7 +29,6 @@ import shallow from 'zustand/shallow'
|
|||||||
import { EmptyWalletContent } from './EmptyWalletContent'
|
import { EmptyWalletContent } from './EmptyWalletContent'
|
||||||
import { ProfileAccountDetails } from './ProfileAccountDetails'
|
import { ProfileAccountDetails } from './ProfileAccountDetails'
|
||||||
import * as styles from './ProfilePage.css'
|
import * as styles from './ProfilePage.css'
|
||||||
import { ProfileBodyLoadingSkeleton } from './ProfilePageLoadingSkeleton'
|
|
||||||
import { WalletAssetDisplay } from './WalletAssetDisplay'
|
import { WalletAssetDisplay } from './WalletAssetDisplay'
|
||||||
|
|
||||||
const SellModeButton = styled.button<{ active: boolean }>`
|
const SellModeButton = styled.button<{ active: boolean }>`
|
||||||
@ -65,12 +63,8 @@ export const ProfilePage = () => {
|
|||||||
const collectionFilters = useWalletCollections((state) => state.collectionFilters)
|
const collectionFilters = useWalletCollections((state) => state.collectionFilters)
|
||||||
const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters)
|
const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters)
|
||||||
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
|
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
|
||||||
const walletAssets = useWalletCollections((state) => state.walletAssets)
|
|
||||||
const setWalletAssets = useWalletCollections((state) => state.setWalletAssets)
|
|
||||||
const setDisplayAssets = useWalletCollections((state) => state.setDisplayAssets)
|
|
||||||
const walletCollections = useWalletCollections((state) => state.walletCollections)
|
const walletCollections = useWalletCollections((state) => state.walletCollections)
|
||||||
const setWalletCollections = useWalletCollections((state) => state.setWalletCollections)
|
const setWalletCollections = useWalletCollections((state) => state.setWalletCollections)
|
||||||
const listFilter = useWalletCollections((state) => state.listFilter)
|
|
||||||
const { isSellMode, resetSellAssets, setIsSellMode } = useSellAsset(
|
const { isSellMode, resetSellAssets, setIsSellMode } = useSellAsset(
|
||||||
({ isSellMode, reset, setIsSellMode }) => ({
|
({ isSellMode, reset, setIsSellMode }) => ({
|
||||||
isSellMode,
|
isSellMode,
|
||||||
@ -85,7 +79,6 @@ export const ProfilePage = () => {
|
|||||||
const setSellPageState = useProfilePageState((state) => state.setProfilePageState)
|
const setSellPageState = useProfilePageState((state) => state.setProfilePageState)
|
||||||
const [isFiltersExpanded, setFiltersExpanded] = useFiltersExpanded()
|
const [isFiltersExpanded, setFiltersExpanded] = useFiltersExpanded()
|
||||||
const isMobile = useIsMobile()
|
const isMobile = useIsMobile()
|
||||||
const isNftGraphQl = useNftGraphQlFlag() === NftGraphQlVariant.Enabled
|
|
||||||
|
|
||||||
const handleSellModeClick = useCallback(() => {
|
const handleSellModeClick = useCallback(() => {
|
||||||
resetSellAssets()
|
resetSellAssets()
|
||||||
@ -93,7 +86,7 @@ export const ProfilePage = () => {
|
|||||||
setBagExpanded({ bagExpanded: !isSellMode })
|
setBagExpanded({ bagExpanded: !isSellMode })
|
||||||
}, [isSellMode, resetSellAssets, setBagExpanded, setIsSellMode])
|
}, [isSellMode, resetSellAssets, setBagExpanded, setIsSellMode])
|
||||||
|
|
||||||
const { data: ownerCollections, isLoading: collectionsAreLoading } = useQuery(
|
const { data: ownerCollections } = useQuery(
|
||||||
['ownerCollections', address],
|
['ownerCollections', address],
|
||||||
() => OSCollectionsFetcher({ params: { asset_owner: address, offset: '0', limit: '300' } }),
|
() => OSCollectionsFetcher({ params: { asset_owner: address, offset: '0', limit: '300' } }),
|
||||||
{
|
{
|
||||||
@ -102,49 +95,10 @@ export const ProfilePage = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: ownerAssetsData,
|
walletAssets: ownerAssets,
|
||||||
fetchNextPage,
|
|
||||||
hasNextPage,
|
|
||||||
isSuccess,
|
|
||||||
isLoading: assetsAreLoading,
|
|
||||||
} = useInfiniteQuery(
|
|
||||||
['ownerAssets', address, collectionFilters],
|
|
||||||
async ({ pageParam = 0 }) => {
|
|
||||||
return await fetchWalletAssets({
|
|
||||||
ownerAddress: address ?? '',
|
|
||||||
collectionAddresses: collectionFilters,
|
|
||||||
pageParam,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
getNextPageParam: (lastPage, pages) => {
|
|
||||||
return lastPage?.flat().length === DEFAULT_WALLET_ASSET_QUERY_AMOUNT ? pages.length : null
|
|
||||||
},
|
|
||||||
refetchOnWindowFocus: false,
|
|
||||||
refetchOnMount: false,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const anyQueryIsLoading = collectionsAreLoading || assetsAreLoading
|
|
||||||
|
|
||||||
const {
|
|
||||||
walletAssets: gqlWalletAssets,
|
|
||||||
loadNext,
|
loadNext,
|
||||||
hasNext,
|
hasNext,
|
||||||
} = useNftBalanceQuery(isNftGraphQl ? address : '', collectionFilters, DEFAULT_WALLET_ASSET_QUERY_AMOUNT)
|
} = useNftBalanceQuery(address, collectionFilters, DEFAULT_WALLET_ASSET_QUERY_AMOUNT)
|
||||||
|
|
||||||
const ownerAssets = useMemo(
|
|
||||||
() => (isNftGraphQl ? gqlWalletAssets : isSuccess ? ownerAssetsData?.pages.flat() : []),
|
|
||||||
[isNftGraphQl, gqlWalletAssets, isSuccess, ownerAssetsData]
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
!isNftGraphQl && setWalletAssets(ownerAssets?.flat() ?? [])
|
|
||||||
}, [ownerAssets, setWalletAssets, isNftGraphQl])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
!isNftGraphQl && setDisplayAssets(walletAssets, listFilter)
|
|
||||||
}, [walletAssets, listFilter, setDisplayAssets, isNftGraphQl])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ownerCollections && setWalletCollections(ownerCollections)
|
ownerCollections && setWalletCollections(ownerCollections)
|
||||||
@ -156,9 +110,7 @@ export const ProfilePage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ProfilePageColumn width="full" paddingTop={{ sm: `${PADDING}`, md: '40' }}>
|
<ProfilePageColumn width="full" paddingTop={{ sm: `${PADDING}`, md: '40' }}>
|
||||||
{anyQueryIsLoading && !isNftGraphQl ? (
|
{ownerAssets?.length === 0 ? (
|
||||||
<ProfileBodyLoadingSkeleton />
|
|
||||||
) : ownerAssets?.length === 0 ? (
|
|
||||||
<EmptyWalletContent />
|
<EmptyWalletContent />
|
||||||
) : (
|
) : (
|
||||||
<Row alignItems="flex-start" position="relative">
|
<Row alignItems="flex-start" position="relative">
|
||||||
@ -200,8 +152,8 @@ export const ProfilePage = () => {
|
|||||||
/>
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
next={() => (isNftGraphQl ? loadNext(DEFAULT_WALLET_ASSET_QUERY_AMOUNT) : fetchNextPage())}
|
next={() => loadNext(DEFAULT_WALLET_ASSET_QUERY_AMOUNT)}
|
||||||
hasMore={isNftGraphQl ? hasNext : hasNextPage ?? false}
|
hasMore={hasNext}
|
||||||
loader={
|
loader={
|
||||||
<Center>
|
<Center>
|
||||||
<LoadingSparkle />
|
<LoadingSparkle />
|
||||||
@ -270,19 +222,12 @@ export const ProfilePage = () => {
|
|||||||
|
|
||||||
const SelectAllButton = ({ ownerAssets }: { ownerAssets: WalletAsset[] }) => {
|
const SelectAllButton = ({ ownerAssets }: { ownerAssets: WalletAsset[] }) => {
|
||||||
const [isAllSelected, setIsAllSelected] = useState(false)
|
const [isAllSelected, setIsAllSelected] = useState(false)
|
||||||
const displayAssets = useWalletCollections((state) => state.displayAssets)
|
|
||||||
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 isNftGraphQl = useNftGraphQlFlag() === NftGraphQlVariant.Enabled
|
|
||||||
|
|
||||||
const allAssets = useMemo(
|
|
||||||
() => (isNftGraphQl ? ownerAssets : displayAssets),
|
|
||||||
[isNftGraphQl, ownerAssets, displayAssets]
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isAllSelected) {
|
if (isAllSelected) {
|
||||||
allAssets.forEach((asset) => selectSellAsset(asset))
|
ownerAssets.forEach((asset) => selectSellAsset(asset))
|
||||||
} else {
|
} else {
|
||||||
resetSellAssets()
|
resetSellAssets()
|
||||||
}
|
}
|
||||||
|
@ -283,16 +283,6 @@ const borderWidth = ['0px', '0.5px', '1px', '1.5px', '2px', '3px', '4px']
|
|||||||
|
|
||||||
const borderStyle = ['none', 'solid'] as const
|
const borderStyle = ['none', 'solid'] as const
|
||||||
|
|
||||||
// TODO: remove when code is done being ported over
|
|
||||||
// I'm leaving this here as a reference of the old breakpoints while we port over the new code
|
|
||||||
// tabletSm: 656,
|
|
||||||
// tablet: 708,
|
|
||||||
// tabletL: 784,
|
|
||||||
// tabletXl: 830,
|
|
||||||
// desktop: 948,
|
|
||||||
// desktopL: 1030,
|
|
||||||
// desktopXl: 1260,
|
|
||||||
|
|
||||||
export const breakpoints = {
|
export const breakpoints = {
|
||||||
sm: 640,
|
sm: 640,
|
||||||
md: 768,
|
md: 768,
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
import { PageName } from 'analytics/constants'
|
import { PageName } from 'analytics/constants'
|
||||||
import { Trace } from 'analytics/Trace'
|
import { Trace } from 'analytics/Trace'
|
||||||
import { NftGraphQlVariant, useNftGraphQlFlag } from 'featureFlags/flags/nftGraphQl'
|
|
||||||
import { useDetailsQuery } from 'graphql/data/nft/Details'
|
import { useDetailsQuery } from 'graphql/data/nft/Details'
|
||||||
import { AssetDetails } from 'nft/components/details/AssetDetails'
|
import { AssetDetails } from 'nft/components/details/AssetDetails'
|
||||||
import { AssetPriceDetails } from 'nft/components/details/AssetPriceDetails'
|
import { AssetPriceDetails } from 'nft/components/details/AssetPriceDetails'
|
||||||
import { fetchSingleAsset } from 'nft/queries'
|
|
||||||
import { CollectionStatsFetcher } from 'nft/queries'
|
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useQuery } from 'react-query'
|
|
||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
|
|
||||||
@ -41,28 +37,9 @@ const AssetPriceDetailsContainer = styled.div`
|
|||||||
|
|
||||||
const Asset = () => {
|
const Asset = () => {
|
||||||
const { tokenId = '', contractAddress = '' } = useParams()
|
const { tokenId = '', contractAddress = '' } = useParams()
|
||||||
const isNftGraphQl = useNftGraphQlFlag() === NftGraphQlVariant.Enabled
|
const data = useDetailsQuery(contractAddress, tokenId)
|
||||||
|
|
||||||
const { data } = useQuery(
|
const [asset, collection] = useMemo(() => data ?? [], [data])
|
||||||
['assetDetail', contractAddress, tokenId],
|
|
||||||
() => fetchSingleAsset({ contractAddress, tokenId }),
|
|
||||||
{
|
|
||||||
refetchOnWindowFocus: false,
|
|
||||||
refetchOnMount: false,
|
|
||||||
refetchOnReconnect: false,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const gqlData = useDetailsQuery(contractAddress, tokenId)
|
|
||||||
|
|
||||||
const asset = useMemo(() => (isNftGraphQl ? gqlData && gqlData[0] : data && data[0]), [data, gqlData, isNftGraphQl])
|
|
||||||
const collection = useMemo(
|
|
||||||
() => (isNftGraphQl ? gqlData && gqlData[1] : data && data[1]),
|
|
||||||
[data, gqlData, isNftGraphQl]
|
|
||||||
)
|
|
||||||
|
|
||||||
const { data: collectionStats } = useQuery(['collectionStats', contractAddress], () =>
|
|
||||||
CollectionStatsFetcher(contractAddress)
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -73,7 +50,7 @@ const Asset = () => {
|
|||||||
>
|
>
|
||||||
{asset && collection ? (
|
{asset && collection ? (
|
||||||
<AssetContainer>
|
<AssetContainer>
|
||||||
<AssetDetails collection={collection} asset={asset} collectionStats={collectionStats} />
|
<AssetDetails collection={collection} asset={asset} />
|
||||||
<AssetPriceDetailsContainer>
|
<AssetPriceDetailsContainer>
|
||||||
<AssetPriceDetails collection={collection} asset={asset} />
|
<AssetPriceDetails collection={collection} asset={asset} />
|
||||||
</AssetPriceDetailsContainer>
|
</AssetPriceDetailsContainer>
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import { useWeb3React } from '@web3-react/core'
|
import { useWeb3React } from '@web3-react/core'
|
||||||
import { PageName } from 'analytics/constants'
|
import { PageName } from 'analytics/constants'
|
||||||
import { Trace } from 'analytics/Trace'
|
import { Trace } from 'analytics/Trace'
|
||||||
import { NftGraphQlVariant, useNftGraphQlFlag } from 'featureFlags/flags/nftGraphQl'
|
|
||||||
import { useCollectionQuery } from 'graphql/data/nft/Collection'
|
import { useCollectionQuery } from 'graphql/data/nft/Collection'
|
||||||
import { MobileHoverBag } from 'nft/components/bag/MobileHoverBag'
|
import { MobileHoverBag } from 'nft/components/bag/MobileHoverBag'
|
||||||
import { AnimatedBox, Box } from 'nft/components/Box'
|
import { AnimatedBox, Box } from 'nft/components/Box'
|
||||||
import { Activity, ActivitySwitcher, CollectionNfts, CollectionStats, Filters } from 'nft/components/collection'
|
import { Activity, ActivitySwitcher, CollectionNfts, CollectionStats, Filters } from 'nft/components/collection'
|
||||||
import { CollectionNftsAndMenuLoading } from 'nft/components/collection/CollectionNfts'
|
import { CollectionNftsAndMenuLoading } from 'nft/components/collection/CollectionNfts'
|
||||||
import { Column, Row } from 'nft/components/Flex'
|
import { Column, Row } from 'nft/components/Flex'
|
||||||
import { useBag, useCollectionFilters, useFiltersExpanded, useIsCollectionLoading, useIsMobile } from 'nft/hooks'
|
import { useBag, useCollectionFilters, useFiltersExpanded, useIsMobile } from 'nft/hooks'
|
||||||
import * as styles from 'nft/pages/collection/index.css'
|
import * as styles from 'nft/pages/collection/index.css'
|
||||||
import { CollectionStatsFetcher } from 'nft/queries'
|
|
||||||
import { GenieCollection } from 'nft/types'
|
import { GenieCollection } from 'nft/types'
|
||||||
import { Suspense, useEffect, useMemo } from 'react'
|
import { Suspense, useEffect } from 'react'
|
||||||
import { useQuery } from 'react-query'
|
|
||||||
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||||
import { useSpring } from 'react-spring'
|
import { useSpring } from 'react-spring'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
@ -35,7 +32,6 @@ const CollectionDisplaySection = styled(Row)`
|
|||||||
|
|
||||||
const Collection = () => {
|
const Collection = () => {
|
||||||
const { contractAddress } = useParams()
|
const { contractAddress } = useParams()
|
||||||
const setIsCollectionStatsLoading = useIsCollectionLoading((state) => state.setIsCollectionStatsLoading)
|
|
||||||
|
|
||||||
const isMobile = useIsMobile()
|
const isMobile = useIsMobile()
|
||||||
const [isFiltersExpanded, setFiltersExpanded] = useFiltersExpanded()
|
const [isFiltersExpanded, setFiltersExpanded] = useFiltersExpanded()
|
||||||
@ -44,23 +40,9 @@ const Collection = () => {
|
|||||||
const isActivityToggled = pathname.includes('/activity')
|
const isActivityToggled = pathname.includes('/activity')
|
||||||
const setMarketCount = useCollectionFilters((state) => state.setMarketCount)
|
const setMarketCount = useCollectionFilters((state) => state.setMarketCount)
|
||||||
const isBagExpanded = useBag((state) => state.bagExpanded)
|
const isBagExpanded = useBag((state) => state.bagExpanded)
|
||||||
const isNftGraphQl = useNftGraphQlFlag() === NftGraphQlVariant.Enabled
|
|
||||||
const { chainId } = useWeb3React()
|
const { chainId } = useWeb3React()
|
||||||
|
|
||||||
const { data: queryCollection, isLoading } = useQuery(['collectionStats', contractAddress], () =>
|
const collectionStats = useCollectionQuery(contractAddress as string)
|
||||||
CollectionStatsFetcher(contractAddress as string)
|
|
||||||
)
|
|
||||||
|
|
||||||
const gqlCollection = useCollectionQuery(contractAddress as string)
|
|
||||||
|
|
||||||
const collectionStats = useMemo(
|
|
||||||
() => (isNftGraphQl ? gqlCollection : queryCollection),
|
|
||||||
[isNftGraphQl, gqlCollection, queryCollection]
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsCollectionStatsLoading(isLoading)
|
|
||||||
}, [isLoading, setIsCollectionStatsLoading])
|
|
||||||
|
|
||||||
const { gridX, gridWidthOffset } = useSpring({
|
const { gridX, gridWidthOffset } = useSpring({
|
||||||
gridX: isFiltersExpanded ? FILTER_WIDTH : 0,
|
gridX: isFiltersExpanded ? FILTER_WIDTH : 0,
|
||||||
@ -100,9 +82,6 @@ const Collection = () => {
|
|||||||
{' '}
|
{' '}
|
||||||
<Box width="full" height="276">
|
<Box width="full" height="276">
|
||||||
<Box width="full" height="276">
|
<Box width="full" height="276">
|
||||||
{isLoading ? (
|
|
||||||
<CollectionBannerLoading />
|
|
||||||
) : (
|
|
||||||
<Box
|
<Box
|
||||||
as={collectionStats?.bannerImageUrl ? 'img' : 'div'}
|
as={collectionStats?.bannerImageUrl ? 'img' : 'div'}
|
||||||
height="full"
|
height="full"
|
||||||
@ -112,14 +91,13 @@ const Collection = () => {
|
|||||||
? `${collectionStats.bannerImageUrl}?w=${window.innerWidth}`
|
? `${collectionStats.bannerImageUrl}?w=${window.innerWidth}`
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
className={isLoading ? styles.loadingBanner : styles.bannerImage}
|
className={styles.bannerImage}
|
||||||
background="none"
|
background="none"
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<CollectionDescriptionSection>
|
<CollectionDescriptionSection>
|
||||||
{(isLoading || collectionStats !== undefined) && (
|
{collectionStats && (
|
||||||
<CollectionStats stats={collectionStats || ({} as GenieCollection)} isMobile={isMobile} />
|
<CollectionStats stats={collectionStats || ({} as GenieCollection)} isMobile={isMobile} />
|
||||||
)}
|
)}
|
||||||
<div id="nft-anchor" />
|
<div id="nft-anchor" />
|
||||||
@ -153,7 +131,7 @@ const Collection = () => {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: contractAddress &&
|
: contractAddress &&
|
||||||
(isLoading || collectionStats !== undefined) && (
|
collectionStats && (
|
||||||
<Suspense fallback={<CollectionNftsAndMenuLoading />}>
|
<Suspense fallback={<CollectionNftsAndMenuLoading />}>
|
||||||
<CollectionNfts
|
<CollectionNfts
|
||||||
collectionStats={collectionStats || ({} as GenieCollection)}
|
collectionStats={collectionStats || ({} as GenieCollection)}
|
||||||
@ -167,7 +145,7 @@ const Collection = () => {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
// TODO: Put no collection asset page here
|
// TODO: Put no collection asset page here
|
||||||
!isLoading && <div className={styles.noCollectionAssets}>No collection assets exist at this address</div>
|
<div className={styles.noCollectionAssets}>No collection assets exist at this address</div>
|
||||||
)}
|
)}
|
||||||
</Column>
|
</Column>
|
||||||
</Trace>
|
</Trace>
|
||||||
|
@ -1,126 +0,0 @@
|
|||||||
import { parseEther } from '@ethersproject/units'
|
|
||||||
|
|
||||||
import { Trait } from '../../hooks/useCollectionFilters'
|
|
||||||
import { AssetPayload, CollectionSort, GenieAsset } from '../../types'
|
|
||||||
|
|
||||||
export const formatTraits = (traits: Trait[]) => {
|
|
||||||
const traitObj: Record<string, string[]> = {}
|
|
||||||
const nonMetaTraits = traits.filter((el) => el.trait_type !== 'Number of traits')
|
|
||||||
for (const trait of nonMetaTraits) {
|
|
||||||
if (!traitObj[trait.trait_type]) traitObj[trait.trait_type] = [trait.trait_value]
|
|
||||||
else traitObj[trait.trait_type].push(trait.trait_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return traitObj
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatPrice = (x: number | string) => parseEther(x.toString()).toString()
|
|
||||||
|
|
||||||
export const AssetsFetcher = async ({
|
|
||||||
contractAddress,
|
|
||||||
tokenId,
|
|
||||||
sort,
|
|
||||||
markets,
|
|
||||||
price,
|
|
||||||
rarityRange,
|
|
||||||
traits,
|
|
||||||
searchText,
|
|
||||||
notForSale,
|
|
||||||
pageParam,
|
|
||||||
}: {
|
|
||||||
contractAddress: string
|
|
||||||
tokenId?: string
|
|
||||||
offset?: number
|
|
||||||
sort?: CollectionSort
|
|
||||||
markets?: string[]
|
|
||||||
price?: { high?: number | string; low?: number | string; symbol: string }
|
|
||||||
rarityRange?: Record<string, unknown>
|
|
||||||
traits?: Trait[]
|
|
||||||
searchText?: string
|
|
||||||
notForSale?: boolean
|
|
||||||
pageParam: number
|
|
||||||
}): Promise<GenieAsset[] | undefined> => {
|
|
||||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/assets`
|
|
||||||
const payload: AssetPayload = {
|
|
||||||
filters: {
|
|
||||||
address: contractAddress.toLowerCase(),
|
|
||||||
traits: {},
|
|
||||||
searchText,
|
|
||||||
notForSale,
|
|
||||||
tokenId,
|
|
||||||
...rarityRange,
|
|
||||||
},
|
|
||||||
fields: {
|
|
||||||
address: 1,
|
|
||||||
name: 1,
|
|
||||||
id: 1,
|
|
||||||
imageUrl: 1,
|
|
||||||
currentPrice: 1,
|
|
||||||
currentUsdPrice: 1,
|
|
||||||
paymentToken: 1,
|
|
||||||
animationUrl: 1,
|
|
||||||
notForSale: 1,
|
|
||||||
rarity: 1,
|
|
||||||
tokenId: 1,
|
|
||||||
},
|
|
||||||
limit: 25,
|
|
||||||
offset: pageParam * 25,
|
|
||||||
}
|
|
||||||
if (sort) {
|
|
||||||
payload.sort = sort
|
|
||||||
}
|
|
||||||
if (markets) {
|
|
||||||
payload.markets = markets
|
|
||||||
}
|
|
||||||
const numberOfTraits = traits?.filter((trait) => trait.trait_type === 'Number of traits')
|
|
||||||
if (numberOfTraits) {
|
|
||||||
payload.filters.numTraits = numberOfTraits.map((el) => ({ traitCount: el.trait_value }))
|
|
||||||
}
|
|
||||||
if (traits) {
|
|
||||||
payload.filters.traits = formatTraits(traits)
|
|
||||||
}
|
|
||||||
|
|
||||||
const low = price?.low ? parseFloat(formatPrice(price.low)) : undefined
|
|
||||||
const high = price?.high ? parseFloat(formatPrice(price.high)) : undefined
|
|
||||||
|
|
||||||
// Only consider sending eth price filters when searching
|
|
||||||
// across listed assets
|
|
||||||
if (!notForSale) {
|
|
||||||
if (low || high) {
|
|
||||||
payload.filters.currentEthPrice = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (low && payload.filters.currentEthPrice) {
|
|
||||||
payload.filters.currentEthPrice.$gte = low
|
|
||||||
}
|
|
||||||
|
|
||||||
if (high && payload.filters.currentEthPrice) {
|
|
||||||
payload.filters.currentEthPrice.$lte = high
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const r = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
|
||||||
})
|
|
||||||
const data = await r.json()
|
|
||||||
// Unfortunately have to include totalCount into each element. The fetcher
|
|
||||||
// for swr infinite must return an array.
|
|
||||||
for (const x of data.data) {
|
|
||||||
x.totalCount = data.totalCount
|
|
||||||
x.numTraitsByAmount = data.numTraitsByAmount
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uncomment the lines belo if you want to simulate a delay
|
|
||||||
// await (async () => await new Promise((resolve) => setTimeout(resolve, 50000)))();
|
|
||||||
|
|
||||||
return data.data
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
import { isAddress } from '@ethersproject/address'
|
|
||||||
import { groupBy } from 'nft/utils/groupBy'
|
|
||||||
|
|
||||||
import { GenieCollection } from '../../types'
|
|
||||||
|
|
||||||
export const CollectionStatsFetcher = async (addressOrName: string, recursive = false): Promise<GenieCollection> => {
|
|
||||||
const isName = !isAddress(addressOrName.toLowerCase())
|
|
||||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/collections`
|
|
||||||
|
|
||||||
if (!isName && !recursive) {
|
|
||||||
try {
|
|
||||||
return await CollectionStatsFetcher(addressOrName.toLowerCase(), true)
|
|
||||||
} catch {
|
|
||||||
// Handle Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const filters = isName
|
|
||||||
? {
|
|
||||||
$or: [{ name: { $regex: addressOrName, $options: 'i' } }],
|
|
||||||
}
|
|
||||||
: { address: addressOrName }
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
filters,
|
|
||||||
limit: isName ? 6 : 1,
|
|
||||||
fields: isName
|
|
||||||
? {
|
|
||||||
name: 1,
|
|
||||||
imageUrl: 1,
|
|
||||||
address: 1,
|
|
||||||
stats: 1,
|
|
||||||
floorPrice: 1,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
traits: 1,
|
|
||||||
stats: 1,
|
|
||||||
'indexingStats.openSea': 1,
|
|
||||||
imageUrl: 1,
|
|
||||||
bannerImageUrl: 1,
|
|
||||||
twitter: 1,
|
|
||||||
externalUrl: 1,
|
|
||||||
instagram: 1,
|
|
||||||
discordUrl: 1,
|
|
||||||
marketplaceCount: 1,
|
|
||||||
floorPrice: 1,
|
|
||||||
},
|
|
||||||
offset: 0,
|
|
||||||
}
|
|
||||||
const r = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
|
||||||
})
|
|
||||||
|
|
||||||
const data = await r.json()
|
|
||||||
const collections = data?.data.map((collection: Record<string, unknown>) => {
|
|
||||||
// @ts-ignore
|
|
||||||
collection.stats.floor_price = collection.floorPrice
|
|
||||||
|
|
||||||
return {
|
|
||||||
...collection,
|
|
||||||
traits: collection.traits && groupBy(collection.traits as unknown[], 'trait_type'),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return collections[0]
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
import { GenieCollection } from '../../types'
|
|
||||||
|
|
||||||
export const fetchMultipleCollectionStats = async ({
|
|
||||||
addresses,
|
|
||||||
}: {
|
|
||||||
addresses: string[]
|
|
||||||
}): Promise<GenieCollection[]> => {
|
|
||||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/searchCollections`
|
|
||||||
const filters = {
|
|
||||||
address: { $in: addresses },
|
|
||||||
}
|
|
||||||
const payload = {
|
|
||||||
filters,
|
|
||||||
fields: {
|
|
||||||
stats: 1,
|
|
||||||
imageUrl: 1,
|
|
||||||
address: 1,
|
|
||||||
name: 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const r = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
|
||||||
})
|
|
||||||
const data = await r.json()
|
|
||||||
return data.data
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
import { CollectionInfoForAsset, GenieAsset } from '../../types'
|
|
||||||
|
|
||||||
interface ReponseTrait {
|
|
||||||
trait_type: string
|
|
||||||
value: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetchSingleAsset = async ({
|
|
||||||
contractAddress,
|
|
||||||
tokenId,
|
|
||||||
}: {
|
|
||||||
contractAddress: string
|
|
||||||
tokenId?: string
|
|
||||||
}): Promise<[GenieAsset, CollectionInfoForAsset]> => {
|
|
||||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/assetDetails?address=${contractAddress}&tokenId=${tokenId}`
|
|
||||||
const r = await fetch(url)
|
|
||||||
const data = await r.json()
|
|
||||||
const asset = data.asset[0]
|
|
||||||
|
|
||||||
asset.traits = asset.traits.map((trait: ReponseTrait) => ({ trait_type: trait.trait_type, trait_value: trait.value }))
|
|
||||||
|
|
||||||
return [asset, data.collection]
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
import { parseEther } from '@ethersproject/units'
|
|
||||||
import { Trait } from 'nft/hooks/useCollectionFilters'
|
|
||||||
import { AssetPayload, GenieAsset } from 'nft/types'
|
|
||||||
|
|
||||||
import { formatTraits } from './AssetsFetcher'
|
|
||||||
|
|
||||||
const formatPrice = (x: number | string) => parseEther(x.toString()).toString()
|
|
||||||
|
|
||||||
export const fetchSweep = async ({
|
|
||||||
contractAddress,
|
|
||||||
markets,
|
|
||||||
price,
|
|
||||||
rarityRange,
|
|
||||||
traits,
|
|
||||||
}: {
|
|
||||||
contractAddress: string
|
|
||||||
markets?: string[]
|
|
||||||
price?: { high?: number | string; low?: number | string; symbol: string }
|
|
||||||
rarityRange?: Record<string, unknown>
|
|
||||||
traits?: Trait[]
|
|
||||||
}): Promise<GenieAsset[]> => {
|
|
||||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/assets`
|
|
||||||
const payload: AssetPayload = {
|
|
||||||
filters: {
|
|
||||||
address: contractAddress.toLowerCase(),
|
|
||||||
traits: {},
|
|
||||||
...rarityRange,
|
|
||||||
},
|
|
||||||
fields: {
|
|
||||||
address: 1,
|
|
||||||
name: 1,
|
|
||||||
id: 1,
|
|
||||||
imageUrl: 1,
|
|
||||||
currentPrice: 1,
|
|
||||||
currentUsdPrice: 1,
|
|
||||||
paymentToken: 1,
|
|
||||||
animationUrl: 1,
|
|
||||||
notForSale: 1,
|
|
||||||
rarity: 1,
|
|
||||||
tokenId: 1,
|
|
||||||
},
|
|
||||||
limit: 50,
|
|
||||||
offset: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (markets) {
|
|
||||||
payload.markets = markets
|
|
||||||
}
|
|
||||||
|
|
||||||
if (traits) {
|
|
||||||
payload.filters.traits = formatTraits(traits)
|
|
||||||
}
|
|
||||||
|
|
||||||
const low = price?.low ? parseFloat(formatPrice(price.low)) : undefined
|
|
||||||
const high = price?.high ? parseFloat(formatPrice(price.high)) : undefined
|
|
||||||
|
|
||||||
if (low || high) {
|
|
||||||
payload.filters.currentEthPrice = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (low && payload.filters.currentEthPrice) {
|
|
||||||
payload.filters.currentEthPrice.$gte = low
|
|
||||||
}
|
|
||||||
|
|
||||||
if (high && payload.filters.currentEthPrice) {
|
|
||||||
payload.filters.currentEthPrice.$lte = high
|
|
||||||
}
|
|
||||||
|
|
||||||
const r = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
|
||||||
})
|
|
||||||
const data = await r.json()
|
|
||||||
|
|
||||||
return data.data
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
import { TransactionsResponse } from '../../types'
|
|
||||||
|
|
||||||
export const fetchTransactions = async (payload: { sweep?: boolean }): Promise<TransactionsResponse[]> => {
|
|
||||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/transactions`
|
|
||||||
|
|
||||||
const r = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
|
||||||
})
|
|
||||||
|
|
||||||
const data = (await r.json()) as TransactionsResponse[]
|
|
||||||
|
|
||||||
return data.filter(
|
|
||||||
(x) => x.bannerImage && (payload.sweep ? x.nftCount >= 3 && Math.floor(x.ethValue / 10 ** 18) >= 1 : true)
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
import { BigNumber } from '@ethersproject/bignumber'
|
|
||||||
import { formatEther } from '@ethersproject/units'
|
|
||||||
|
|
||||||
import { WalletAsset } from '../../types'
|
|
||||||
|
|
||||||
const getEthPrice = (price: any) => {
|
|
||||||
if (price.toString().includes('e')) {
|
|
||||||
return BigNumber.from(10).pow(price.toString().split('e+')[1]).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.round(price).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetchWalletAssets = async ({
|
|
||||||
ownerAddress,
|
|
||||||
collectionAddresses,
|
|
||||||
pageParam,
|
|
||||||
}: {
|
|
||||||
ownerAddress: string
|
|
||||||
collectionAddresses?: string[]
|
|
||||||
pageParam: number
|
|
||||||
}): Promise<WalletAsset[]> => {
|
|
||||||
const collectionAddressesString = collectionAddresses
|
|
||||||
? collectionAddresses.reduce((str, collectionAddress) => str + `&assetContractAddresses=${collectionAddress}`, '')
|
|
||||||
: ''
|
|
||||||
const url = `${
|
|
||||||
process.env.REACT_APP_GENIE_V3_API_URL
|
|
||||||
}/walletAssets?address=${ownerAddress}${collectionAddressesString}&limit=25&offset=${pageParam * 25}`
|
|
||||||
|
|
||||||
const r = await fetch(url, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const data = await r.json()
|
|
||||||
return data.data.assets.map((asset: any) => {
|
|
||||||
return {
|
|
||||||
...asset,
|
|
||||||
collectionIsVerified: asset.asset_contract.isVerified,
|
|
||||||
lastPrice: asset.last_sale.total_price && formatEther(asset.last_sale.total_price),
|
|
||||||
floorPrice: asset.collection?.floorPrice,
|
|
||||||
creatorPercentage: parseFloat(asset.asset_contract.dev_seller_fee_basis_points) / 10000,
|
|
||||||
date_acquired: asset.last_sale ? asset.last_sale.event_timestamp : asset.asset_contract.created_date,
|
|
||||||
listing_date: asset.sellOrders.length
|
|
||||||
? Math.max
|
|
||||||
.apply(
|
|
||||||
null,
|
|
||||||
asset.sellOrders.map(function (order: any) {
|
|
||||||
return new Date(order.orderCreatedDate)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.toString()
|
|
||||||
: null,
|
|
||||||
floor_sell_order_price: asset?.sellOrders?.length
|
|
||||||
? Math.min(
|
|
||||||
...asset.sellOrders.map((order: any) => {
|
|
||||||
return parseFloat(formatEther(getEthPrice(order.ethPrice)))
|
|
||||||
})
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,15 +1,7 @@
|
|||||||
export * from './ActivityFetcher'
|
export * from './ActivityFetcher'
|
||||||
export * from './AssetsFetcher'
|
|
||||||
export * from './CollectionPreviewFetcher'
|
export * from './CollectionPreviewFetcher'
|
||||||
export * from './CollectionStatsFetcher'
|
|
||||||
export * from './logListing'
|
export * from './logListing'
|
||||||
export * from './LooksRareRewardsFetcher'
|
export * from './LooksRareRewardsFetcher'
|
||||||
export * from './MultipleCollectionStatsFetcher'
|
|
||||||
export * from './RouteFetcher'
|
export * from './RouteFetcher'
|
||||||
export * from './SearchCollectionsFetcher'
|
export * from './SearchCollectionsFetcher'
|
||||||
export * from './SingleAssetFetcher'
|
|
||||||
export * from './SweepFetcher'
|
|
||||||
export * from './TransactionsFetcher'
|
|
||||||
export * from './TrendingCollectionsFetcher'
|
export * from './TrendingCollectionsFetcher'
|
||||||
export * from './triggerPriceUpdatesForCollection'
|
|
||||||
export * from './WalletAssetsFetcher'
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
export const triggerPriceUpdatesForCollection = async (address: string) => {
|
|
||||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/collections/refresh`
|
|
||||||
const r = await fetch(url, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
address,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
return r.json()
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import { Deprecated_SellOrder, SellOrder } from '../sell'
|
import { SellOrder } from '../sell'
|
||||||
|
|
||||||
export interface OpenSeaCollection {
|
export interface OpenSeaCollection {
|
||||||
name: string
|
name: string
|
||||||
@ -88,7 +88,7 @@ export interface GenieAsset {
|
|||||||
name?: string
|
name?: string
|
||||||
priceInfo: PriceInfo
|
priceInfo: PriceInfo
|
||||||
susFlag?: boolean
|
susFlag?: boolean
|
||||||
sellorders?: Deprecated_SellOrder[] | SellOrder[] // TODO remove Deprecated_SellOrder when full migration to GraphQL is complete
|
sellorders?: SellOrder[]
|
||||||
smallImageUrl?: string
|
smallImageUrl?: string
|
||||||
tokenId: string
|
tokenId: string
|
||||||
tokenType: TokenType
|
tokenType: TokenType
|
||||||
|
@ -12,24 +12,6 @@ export interface ListingWarning {
|
|||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Deprecated_SellOrder {
|
|
||||||
assetId: string
|
|
||||||
ethPrice: number
|
|
||||||
basePrice: number
|
|
||||||
baseCurrency: string
|
|
||||||
baseCurrencyDecimal: number
|
|
||||||
orderCreatedDate: string
|
|
||||||
orderClosingDate: string
|
|
||||||
quantity: number
|
|
||||||
timestamp: string
|
|
||||||
marketplace: string
|
|
||||||
marketplaceUrl: string
|
|
||||||
orderHash: string
|
|
||||||
ammFeePercent?: number
|
|
||||||
ethReserves?: number
|
|
||||||
tokenReserves?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SellOrder {
|
export interface SellOrder {
|
||||||
address: string
|
address: string
|
||||||
createdAt: number
|
createdAt: number
|
||||||
@ -78,7 +60,7 @@ export interface WalletAsset {
|
|||||||
creatorPercentage: number
|
creatorPercentage: number
|
||||||
listing_date: string
|
listing_date: string
|
||||||
date_acquired: string
|
date_acquired: string
|
||||||
sellOrders: Deprecated_SellOrder[] | SellOrder[] // TODO remove Deprecated_SellOrder when full migration to GraphQL is complete
|
sellOrders: SellOrder[]
|
||||||
floor_sell_order_price: number
|
floor_sell_order_price: number
|
||||||
// Used for creating new listings
|
// Used for creating new listings
|
||||||
expirationTime?: number
|
expirationTime?: number
|
||||||
|
@ -1,13 +1,5 @@
|
|||||||
import { BigNumber } from '@ethersproject/bignumber'
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
import {
|
import { BagItem, BagItemStatus, GenieAsset, Markets, UpdatedGenieAsset } from 'nft/types'
|
||||||
BagItem,
|
|
||||||
BagItemStatus,
|
|
||||||
Deprecated_SellOrder,
|
|
||||||
GenieAsset,
|
|
||||||
Markets,
|
|
||||||
SellOrder,
|
|
||||||
UpdatedGenieAsset,
|
|
||||||
} from 'nft/types'
|
|
||||||
|
|
||||||
// TODO: a lot of the below typecasting logic can be simplified when GraphQL migration is complete
|
// TODO: a lot of the below typecasting logic can be simplified when GraphQL migration is complete
|
||||||
export const calcPoolPrice = (asset: GenieAsset, position = 0) => {
|
export const calcPoolPrice = (asset: GenieAsset, position = 0) => {
|
||||||
@ -15,11 +7,7 @@ export const calcPoolPrice = (asset: GenieAsset, position = 0) => {
|
|||||||
let marginalBuy: BigNumber = BigNumber.from(0)
|
let marginalBuy: BigNumber = BigNumber.from(0)
|
||||||
if (!asset.sellorders) return ''
|
if (!asset.sellorders) return ''
|
||||||
|
|
||||||
const nft =
|
const nft = asset.sellorders[0].protocolParameters
|
||||||
(asset.sellorders[0] as Deprecated_SellOrder).ammFeePercent === undefined
|
|
||||||
? (asset.sellorders[0] as SellOrder).protocolParameters
|
|
||||||
: (asset.sellorders[0] as Deprecated_SellOrder)
|
|
||||||
|
|
||||||
const decimals = BigNumber.from(1).mul(10).pow(18)
|
const decimals = BigNumber.from(1).mul(10).pow(18)
|
||||||
const ammFee = nft?.ammFeePercent ? (100 + (nft.ammFeePercent as number)) * 100 : 110 * 100
|
const ammFee = nft?.ammFeePercent ? (100 + (nft.ammFeePercent as number)) * 100 : 110 * 100
|
||||||
|
|
||||||
@ -42,8 +30,6 @@ export const calcPoolPrice = (asset: GenieAsset, position = 0) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ethReserves = BigNumber.from(
|
const ethReserves = BigNumber.from(
|
||||||
(
|
|
||||||
(nft?.ethReserves as number) ??
|
|
||||||
(
|
(
|
||||||
nft as Record<
|
nft as Record<
|
||||||
string,
|
string,
|
||||||
@ -51,12 +37,9 @@ export const calcPoolPrice = (asset: GenieAsset, position = 0) => {
|
|||||||
ethReserves: number
|
ethReserves: number
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
)?.poolMetadata?.ethReserves
|
)?.poolMetadata?.ethReserves?.toLocaleString('fullwide', { useGrouping: false }) ?? 1
|
||||||
)?.toLocaleString('fullwide', { useGrouping: false }) ?? 1
|
|
||||||
)
|
)
|
||||||
const tokenReserves = BigNumber.from(
|
const tokenReserves = BigNumber.from(
|
||||||
(
|
|
||||||
(nft?.tokenReserves as number) ??
|
|
||||||
(
|
(
|
||||||
nft as Record<
|
nft as Record<
|
||||||
string,
|
string,
|
||||||
@ -64,8 +47,7 @@ export const calcPoolPrice = (asset: GenieAsset, position = 0) => {
|
|||||||
tokenReserves: number
|
tokenReserves: number
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
)?.poolMetadata?.tokenReserves
|
)?.poolMetadata?.tokenReserves?.toLocaleString('fullwide', { useGrouping: false }) ?? 1
|
||||||
)?.toLocaleString('fullwide', { useGrouping: false }) ?? 1
|
|
||||||
)
|
)
|
||||||
const numerator = ethReserves.mul(amountToBuy).mul(1000)
|
const numerator = ethReserves.mul(amountToBuy).mul(1000)
|
||||||
const denominator = tokenReserves.sub(amountToBuy).mul(997)
|
const denominator = tokenReserves.sub(amountToBuy).mul(997)
|
||||||
|
Loading…
Reference in New Issue
Block a user