diff --git a/components/HomeSection/Featured.gql b/components/HomeSection/Featured.gql deleted file mode 100644 index f019e3ef..00000000 --- a/components/HomeSection/Featured.gql +++ /dev/null @@ -1,108 +0,0 @@ -query FetchFeaturedAssets( - $assetFilter: [AssetFilter!]! - $salesFilter: [OfferOpenSaleFilter!]! - $now: Datetime! - $address: Address -) { - assets(filter: { quantity: { greaterThan: "0" }, and: $assetFilter }) { - nodes { - id - chainId - collectionAddress - tokenId - name - collection { - chainId - address - name - standard - mintType - } - image - imageMimetype - animationUrl - animationMimetype - quantity - creator { - address - name - image - verification { - status - } - } - owned: ownership(ownerAddress: $address) { - quantity - } - ownerships( - orderBy: [ - QUANTITY_DESC - ACCOUNT_BY_OWNER_ADDRESS__NAME_ASC - OWNER_ADDRESS_ASC - ] - first: 5 - ) { - totalCount - nodes { - ownerAddress - quantity - owner { - address - name - image - verification { - status - } - } - } - } - bestBid { - unitPrice - amount - currency { - image - name - id - decimals - symbol - } - } - } - } - sales: offerOpenSales( - orderBy: [UNIT_PRICE_IN_REF_ASC, CREATED_AT_ASC] - filter: { expiredAt: { greaterThan: $now }, and: $salesFilter } # TODO: implement pagination. when implementing pagination, find a way to get availableQuantity of all sales - ) { - nodes { - id - chainId - collectionAddress - tokenId - unitPrice - availableQuantity - expiredAt - currency { - image - name - id - decimals - symbol - } - maker { - image - address - name - verification { - status - } - } - } - } - currencies(orderBy: CREATED_AT_ASC, filter: { address: { isNull: false } }) { - # keep only non-native currency. Cannot create bid with native currency. - nodes { - chainId - image - } - } -} diff --git a/components/HomeSection/Featured.tsx b/components/HomeSection/Featured.tsx index 42bedbe6..141becdc 100644 --- a/components/HomeSection/Featured.tsx +++ b/components/HomeSection/Featured.tsx @@ -1,25 +1,9 @@ -import { - Box, - Flex, - SimpleGrid, - Skeleton, - SkeletonText, - Spacer, - Stack, -} from '@chakra-ui/react' -import { FC, useCallback, useMemo } from 'react' +import { Flex } from '@chakra-ui/react' +import { FC, useMemo } from 'react' import invariant from 'ts-invariant' -import { - AssetFilter, - OfferOpenSaleFilter, - useFetchFeaturedAssetsQuery, -} from '../../graphql' -import useAccount from '../../hooks/useAccount' import useEnvironment from '../../hooks/useEnvironment' -import useHandleQueryError from '../../hooks/useHandleQueryError' -import { useOrderByKey } from '../../hooks/useOrderByKey' import Slider from '../Slider/Slider' -import TokenHeader from '../Token/Header' +import TokenHeader from './FeaturedToken' type Props = { date: Date @@ -27,90 +11,33 @@ type Props = { const FeaturedHomeSection: FC = ({ date }) => { const { FEATURED_TOKEN } = useEnvironment() - const { address } = useAccount() - const idFilters = { - or: FEATURED_TOKEN.map((x) => x.split('-')).map( - ([chainId, collectionAddress, tokenId]) => { - invariant( - chainId !== undefined && - collectionAddress !== undefined && - tokenId !== undefined, - 'invalid feature token', - ) - return { - collectionAddress: { equalTo: collectionAddress.toLowerCase() }, - chainId: { equalTo: parseInt(chainId, 10) }, - tokenId: { equalTo: tokenId }, - } - }, - ), - } - const featureAssetsQuery = useFetchFeaturedAssetsQuery({ - variables: { - assetFilter: idFilters as AssetFilter, - salesFilter: idFilters as OfferOpenSaleFilter, - now: date, - address: address || '', - }, - skip: !FEATURED_TOKEN.length, - }) - useHandleQueryError(featureAssetsQuery) - const currencies = featureAssetsQuery.data?.currencies?.nodes - const sales = featureAssetsQuery.data?.sales?.nodes - - const featured = useOrderByKey( - FEATURED_TOKEN, - featureAssetsQuery.data?.assets?.nodes, - (asset) => asset.id, + const featuredAssets = useMemo( + () => + FEATURED_TOKEN.map((x) => x.split('-')).map( + ([chainId, collectionAddress, tokenId], index) => { + invariant( + chainId !== undefined && + collectionAddress !== undefined && + tokenId !== undefined, + 'invalid feature token', + ) + return ( + + ) + }, + ), + [FEATURED_TOKEN, date], ) - const reloadInfo = useCallback(async () => { - void featureAssetsQuery.refetch() - }, [featureAssetsQuery]) - - const featuredAssets = useMemo(() => { - if (!featured || !currencies || !sales) return undefined - return featured.map((asset) => { - const salesOfAsset = sales.filter( - (sale) => - sale.chainId === asset.chainId && - sale.collectionAddress === asset.collectionAddress && - sale.tokenId === asset.tokenId, - ) - return ( - - ) - }) - }, [featured, currencies, sales, reloadInfo]) - - if (!FEATURED_TOKEN.length) return null - if (!featuredAssets) - return ( - - - - - - - - - - - - - - - ) - if (featuredAssets.length === 0) return null - if (featuredAssets.length === 1) return
{featuredAssets}
+ if (FEATURED_TOKEN.length === 0) return null + if (FEATURED_TOKEN.length === 1) return
{featuredAssets}
return (
{featuredAssets} diff --git a/components/HomeSection/FeaturedToken.gql b/components/HomeSection/FeaturedToken.gql new file mode 100644 index 00000000..019e05da --- /dev/null +++ b/components/HomeSection/FeaturedToken.gql @@ -0,0 +1,126 @@ +query FetchFeaturedToken( + $chainId: Int! + $collectionAddress: Address! + $tokenId: String! + $now: Datetime! + $address: Address +) { + asset( + chainId: $chainId + collectionAddress: $collectionAddress + tokenId: $tokenId + ) { + id + chainId + collectionAddress + tokenId + name + collection { + chainId + address + name + standard + mintType + } + image + imageMimetype + animationUrl + animationMimetype + quantity + creator { + address + name + image + verification { + status + } + } + owned: ownership(ownerAddress: $address) { + quantity + } + bestBid { + unitPrice + amount + currency { + image + name + id + decimals + symbol + } + } + } + ownerships( + filter: { + chainId: { equalTo: $chainId } + collectionAddress: { equalTo: $collectionAddress } + tokenId: { equalTo: $tokenId } + } + orderBy: [ + QUANTITY_DESC + ACCOUNT_BY_OWNER_ADDRESS__NAME_ASC + OWNER_ADDRESS_ASC + ] + first: 5 + ) { + totalCount + nodes { + ownerAddress + quantity + owner { + address + name + image + verification { + status + } + } + } + } + sales: offerOpenSales( + orderBy: [UNIT_PRICE_IN_REF_ASC, CREATED_AT_ASC] + filter: { + chainId: { equalTo: $chainId } + collectionAddress: { equalTo: $collectionAddress } + tokenId: { equalTo: $tokenId } + expiredAt: { greaterThan: $now } + } # TODO: implement pagination. when implementing pagination, find a way to get availableQuantity of all sales + ) { + nodes { + id + chainId + collectionAddress + tokenId + unitPrice + availableQuantity + expiredAt + currency { + image + name + id + decimals + symbol + } + maker { + image + address + name + verification { + status + } + } + } + } + currencies( + orderBy: CREATED_AT_ASC + filter: { + chainId: { equalTo: $chainId } + address: { isNull: false } # keep only non-native currency. Cannot create bid with native currency. + } + ) { + nodes { + chainId + image + } + } +} diff --git a/components/HomeSection/FeaturedToken.tsx b/components/HomeSection/FeaturedToken.tsx new file mode 100644 index 00000000..ab2d3a34 --- /dev/null +++ b/components/HomeSection/FeaturedToken.tsx @@ -0,0 +1,139 @@ +import { + AspectRatio, + Box, + Flex, + Heading, + SimpleGrid, + Skeleton, + Stack, +} from '@chakra-ui/react' +import { FC, useCallback } from 'react' +import { useFetchFeaturedTokenQuery } from '../../graphql' +import useAccount from '../../hooks/useAccount' +import useCart from '../../hooks/useCart' +import useDetectAssetMedia from '../../hooks/useDetectAssetMedia' +import useHandleQueryError from '../../hooks/useHandleQueryError' +import Link from '../Link/Link' +import SaleDetail from '../Sales/Detail' +import SkeletonProperty from '../Skeleton/Property' +import TokenMedia from '../Token/Media' +import TokenMetadata from '../Token/Metadata' + +export type Props = { + date: Date + chainId: number + collectionAddress: string + tokenId: string +} + +const FeaturedToken: FC = ({ + date, + chainId, + collectionAddress, + tokenId, +}) => { + const { address } = useAccount() + + const fetchFeaturedTokenQuery = useFetchFeaturedTokenQuery({ + variables: { + chainId, + collectionAddress, + tokenId, + now: date, + address: address || '', + }, + }) + useHandleQueryError(fetchFeaturedTokenQuery) + const asset = fetchFeaturedTokenQuery.data?.asset + const sales = fetchFeaturedTokenQuery.data?.sales?.nodes + const currencies = fetchFeaturedTokenQuery.data?.currencies?.nodes + const ownerships = fetchFeaturedTokenQuery.data?.ownerships + + const media = useDetectAssetMedia(asset) + + const refresh = useCallback(async () => { + await fetchFeaturedTokenQuery.refetch({ + now: new Date(), + }) + }, [fetchFeaturedTokenQuery]) + + useCart({ onCheckout: fetchFeaturedTokenQuery.refetch }) + + return ( + + + + + {!asset ? ( + + ) : ( + + )} + + + + + + + {!asset ? ( + + ) : ( + + {asset.collection.name} + + )} + + + {!asset ? : asset.name} + + + + {!asset || !sales || !ownerships ? ( + + ) : ( + + )} + + {!asset || !sales || !currencies ? ( + <> + + + + ) : ( + + )} + + + ) +} + +export default FeaturedToken diff --git a/components/Token/Header.tsx b/components/Token/Header.tsx deleted file mode 100644 index c37a1439..00000000 --- a/components/Token/Header.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { - AspectRatio, - Box, - Flex, - Heading, - SimpleGrid, - Stack, -} from '@chakra-ui/react' -import { FC, useMemo } from 'react' -import { FetchFeaturedAssetsQuery } from '../../graphql' -import useDetectAssetMedia from '../../hooks/useDetectAssetMedia' -import Link from '../Link/Link' -import SaleDetail, { Props as SaleDetailProps } from '../Sales/Detail' -import TokenMedia from '../Token/Media' -import TokenMetadata, { Props as TokenMetadataProps } from '../Token/Metadata' - -export type Props = { - asset: NonNullable['nodes'][0] - sales: TokenMetadataProps['sales'] & SaleDetailProps['sales'] - currencies: { - chainId: number - image: string - }[] - isHomepage: boolean - onOfferCanceled: (id: string) => Promise -} - -const TokenHeader: FC = ({ - asset, - sales, - currencies, - isHomepage, - onOfferCanceled, -}) => { - const media = useDetectAssetMedia(asset) - - const chainCurrencies = useMemo( - () => - currencies.filter( - (currency) => currency.chainId === asset.collection.chainId, - ), - [currencies, asset], - ) - - return ( - - - - - - - - - - - {asset.collection.name && ( - - - {asset.collection.name} - - - )} - - {asset.name} - - - - - - - ) -} - -export default TokenHeader diff --git a/pages/tokens/[id]/index.gql b/pages/tokens/[id]/index.gql index f363a2ea..e748aa3c 100644 --- a/pages/tokens/[id]/index.gql +++ b/pages/tokens/[id]/index.gql @@ -152,7 +152,10 @@ query FetchAsset( } currencies( orderBy: CREATED_AT_ASC - filter: { chainId: { equalTo: $chainId }, address: { isNull: false } } + filter: { + chainId: { equalTo: $chainId } + address: { isNull: false } # keep only non-native currency. Cannot create bid with native currency. + } ) { nodes { id diff --git a/pages/tokens/[id]/index.tsx b/pages/tokens/[id]/index.tsx index a56b893c..398c71c6 100644 --- a/pages/tokens/[id]/index.tsx +++ b/pages/tokens/[id]/index.tsx @@ -85,8 +85,9 @@ const DetailPage: NextPage = ({ now: nowProp }) => { }, }) const asset = data?.asset - const sales = data?.sales - const bids = data?.bids + const sales = data?.sales?.nodes + const bids = data?.bids?.nodes + const currencies = data?.currencies?.nodes const ownerships = data?.ownerships const media = useDetectAssetMedia(asset) @@ -233,11 +234,12 @@ const DetailPage: NextPage = ({ now: nowProp }) => { ) : ( )} - {!asset || !sales || !data?.currencies?.nodes ? ( + + {!asset || !sales || !currencies ? ( <> @@ -245,8 +247,8 @@ const DetailPage: NextPage = ({ now: nowProp }) => { ) : ( @@ -391,7 +393,7 @@ const DetailPage: NextPage = ({ now: nowProp }) => { {(!query.filter || query.filter === AssetTabs.bids) && (