import { faGasPump, faHand } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { useBids } from '@reservoir0x/reservoir-kit-ui' import { AcceptBid } from 'components/buttons' import CancelBid from 'components/buttons/CancelBid' import EditBid from 'components/buttons/EditBid' import LoadingSpinner from 'components/common/LoadingSpinner' import { Box, Button, Flex, FormatCryptoCurrency, TableRow, Text, Tooltip, } from 'components/primitives' import { ChainContext } from 'context/ChainContextProvider' import { useENSResolver, useMarketplaceChain, useTimeSince } from 'hooks' import Link from 'next/link' import { FC, useContext, useEffect, useRef, useState } from 'react' import { MutatorCallback } from 'swr' import { useIntersectionObserver } from 'usehooks-ts' import { formatDollar } from 'utils/numbers' import { OnlyUserOrdersToggle } from './OnlyUserOrdersToggle' import { zeroAddress } from 'viem' type Props = { address?: string token: Parameters['0']['token'] is1155: boolean isOwner: boolean } export const OffersTable: FC = ({ token, address, is1155, isOwner }) => { const loadMoreRef = useRef(null) const loadMoreObserver = useIntersectionObserver(loadMoreRef, {}) const [userOnly, setUserOnly] = useState(false) let bidsQuery: Parameters['0'] = { maker: userOnly ? address : undefined, token: token, includeCriteriaMetadata: true, includeRawData: true, sortBy: 'price', } const { chain } = useContext(ChainContext) if (chain.community) { bidsQuery.community = chain.community } const { data: offers, fetchNextPage, mutate, isValidating, isFetchingPage, isLoading, } = useBids(bidsQuery, { revalidateFirstPage: true }) const { data: userOffers } = useBids({ ...bidsQuery, maker: address }) const userHasOffers = userOffers.length > 0 useEffect(() => { const isVisible = !!loadMoreObserver?.isIntersecting if (isVisible) { fetchNextPage() } }, [loadMoreObserver?.isIntersecting]) return ( <> {!isValidating && !isFetchingPage && offers && offers.length === 0 ? ( No offers made yet ) : ( {address && userHasOffers ? ( setUserOnly(checked)} /> ) : null} {offers.map((offer, i) => { return ( ) })} )} {isValidating && ( )} ) } type OfferTableRowProps = { offer: ReturnType['data'][0] tokenString: Parameters['0']['token'] is1155: boolean isOwner: boolean address?: string mutate?: MutatorCallback } const OfferTableRow: FC = ({ offer, tokenString, is1155, isOwner, address, mutate, }) => { const { displayName: fromDisplayName } = useENSResolver(offer.maker) const { reservoirBaseUrl } = useMarketplaceChain() const expiration = useTimeSince(offer?.expiration) const expirationText = expiration ? `Expires ${expiration}` : null const isUserOffer = address?.toLowerCase() === offer.maker.toLowerCase() const isOracleOrder = offer?.isNativeOffChainCancellable const contract = tokenString?.split(':')[0] const tokenId = tokenString?.split(':')[1] const offerSourceName = offer?.source?.name const offerSourceDomain = offer?.source?.domain const offerSourceLogo = `${reservoirBaseUrl}/redirect/sources/${ offerSourceDomain || offerSourceName }/logo/v2` return ( Net Amount } > {offer.price?.amount?.usd ? ( {formatDollar(offer.price?.amount?.usd)} ) : null} from {offer.maker && offer.maker !== zeroAddress ? ( {fromDisplayName} ) : ( - )} {/* Owner and not user offer */} {isOwner && !isUserOffer ? ( Accept } buttonProps={{ color: 'primary' }} buttonCss={{ fontSize: 14, px: '$4', py: '$2', minHeight: 36 }} /> ) : null} {/* Not Owner and is user offer, owner of erc 1155 and is your offer */} {(!isOwner && isUserOffer) || (isOwner && is1155 && isUserOffer) ? ( <> {isOracleOrder ? ( Edit} buttonCss={{ fontSize: 14, px: '$4', py: '$2', minHeight: 36, minWidth: 80, justifyContent: 'center', }} mutate={mutate} /> ) : null} {!isOracleOrder ? ( Cancelling this order requires gas. } > ) : ( )} } /> ) : null} {expirationText} ) }