Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
37 changed files
with
1,884 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { useActiveAuctions } from 'src/hooks/api/auctions'; | ||
import { getUrlParams } from 'src/utils/getUrlParams'; | ||
import IpfsImage from '../IpfsImage/IpfsImage'; | ||
import { useWallet } from '@meshsdk/react'; | ||
import { WalletApp } from 'hydra-auction-offchain'; | ||
import { getIsSeller } from 'src/utils/auctionState'; | ||
import { useWalletAddress } from 'src/hooks/api/user'; | ||
import AuctionDetailSeller from './AuctionDetailSeller'; | ||
import AuctionDetailBidder from './AuctionDetailBidder'; | ||
import { getAuctionAssetUnit } from 'src/utils/auction'; | ||
import AuctionSubDetail from './AuctionSubDetail'; | ||
import { useAssetMetadata } from 'src/hooks/api/assets'; | ||
import { useCleanupAuction } from 'src/hooks/api/cleanup'; | ||
import { Button } from '../shadcn/Button'; | ||
import { removeLocalStorageItem } from 'src/utils/localStorage'; | ||
|
||
const MOCK_NFT_TITLE = 'My NFT'; | ||
|
||
// TODO: Claims and cleanup components are always showing, we will implement the conditions when the APIs are ready | ||
export default function AuctionDetail() { | ||
// TODO: Display some badge if the user is already a bidder, and for the state of the auction | ||
|
||
// Use url params to get the auctionId | ||
const urlParams = getUrlParams(); | ||
const auctionId = urlParams.get('auctionId') || ''; | ||
const { name: walletName, wallet, connected } = useWallet(); | ||
const walletApp: WalletApp = walletName as WalletApp; | ||
const { data: auctions, isLoading, isError } = useActiveAuctions(walletApp); | ||
const { data: walletAddress } = useWalletAddress(wallet, connected); | ||
|
||
// With auctionId we find the auction details from the queryAuctions cache | ||
const auctionInfo = auctions?.find( | ||
(auction) => auction.auctionId === auctionId | ||
); | ||
const assetUnit = getAuctionAssetUnit(auctionInfo); | ||
|
||
const cleanupAuction = useCleanupAuction(walletApp); | ||
|
||
const { data: assetMetadata } = useAssetMetadata(assetUnit); | ||
|
||
if (isLoading) return <div>Loading...</div>; | ||
if (isError) return <div>Error getting auction...</div>; | ||
if (!auctionInfo) return <div>Error finding auction...</div>; | ||
if (!walletAddress || !walletName) return <div>Wallet not valid</div>; | ||
|
||
// Identifying if we are the seller or a bidder of this auction | ||
const isSeller = getIsSeller(walletAddress, auctionInfo); | ||
console.log({ auctionInfo }); | ||
|
||
console.log({ isSeller }); | ||
const handleCleanupAuction = () => { | ||
cleanupAuction.mutate(auctionInfo); | ||
}; | ||
|
||
return ( | ||
<div className="grid lg:grid-cols-2 gap-3"> | ||
<div className="flex justify-center items-center mb-6"> | ||
<IpfsImage assetUnit={assetUnit} /> | ||
</div> | ||
<div className="flex flex-col items-center gap-10"> | ||
<div className="text-title2 font-semibold mb-6"> | ||
{assetMetadata?.name ? assetMetadata.name : MOCK_NFT_TITLE} | ||
</div> | ||
{/* NOTE: If you want to make testing easier, just show both bidder and seller auction details without any conditions */} | ||
{isSeller ? ( | ||
<div className="w-full"> | ||
<AuctionDetailSeller | ||
walletApp={walletApp} | ||
auctionInfo={auctionInfo} | ||
/> | ||
</div> | ||
) : ( | ||
<AuctionDetailBidder | ||
walletApp={walletApp} | ||
walletAddress={walletAddress} | ||
auctionInfo={auctionInfo} | ||
/> | ||
)} | ||
|
||
<Button onClick={handleCleanupAuction} className="w-full"> | ||
Cleanup | ||
</Button> | ||
|
||
<AuctionSubDetail | ||
description={assetMetadata?.description} | ||
auctionInfo={auctionInfo} | ||
/> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import { useQueryClient } from '@tanstack/react-query'; | ||
import { useActiveAuctions } from '../../hooks/api/auctions'; | ||
import AuctionCard from '../AuctionCard/AuctionCard'; | ||
import { useWallet } from '@meshsdk/react'; | ||
import { AuctionInfo, WalletApp } from 'hydra-auction-offchain'; | ||
|
||
import { useEffect, useState } from 'react'; | ||
import { | ||
METADATA_QUERY_KEY, | ||
getAndStoreAssetMetadata, | ||
} from 'src/hooks/api/assets'; | ||
import { getLocalStorageItem } from 'src/utils/localStorage'; | ||
import { getAuctionAssetUnit } from 'src/utils/auction'; | ||
import { useWalletAddress } from 'src/hooks/api/user'; | ||
import { | ||
AuctionListSortState, | ||
auctionListFilterOptions, | ||
} from 'src/utils/auctionState'; | ||
import { DropDown } from '../DropDown/DropDown'; | ||
|
||
export default function AuctionList() { | ||
const { name: walletName, wallet, connected } = useWallet(); | ||
const { data: walletAddress } = useWalletAddress(wallet, connected); | ||
const walletApp: WalletApp = walletName as WalletApp; | ||
const { data: auctions } = useActiveAuctions(walletApp); | ||
|
||
const queryClient = useQueryClient(); | ||
|
||
const localMetadata = getLocalStorageItem('metadata'); | ||
|
||
console.log({ walletApp }); | ||
console.log({ auctions }); | ||
console.log({ localMetadata }); | ||
|
||
const [auctionsWithImage, setAuctionsWithImage] = useState< | ||
AuctionInfo[] | null | ||
>([]); | ||
|
||
const [filteredAuctions, setFilteredAuctions] = useState< | ||
AuctionInfo[] | undefined | ||
>([]); | ||
|
||
const [activeFilter, setActiveFilter] = useState<AuctionListSortState>( | ||
AuctionListSortState.ALL | ||
); | ||
|
||
const fetchAndFilterAuctionsByImage = async (auctions: AuctionInfo[]) => { | ||
const filteredAuctions = await Promise.all( | ||
auctions.map(async (auction) => { | ||
const assetUnit = getAuctionAssetUnit(auction); | ||
|
||
await queryClient.prefetchQuery({ | ||
queryKey: [METADATA_QUERY_KEY, assetUnit], | ||
queryFn: async () => await getAndStoreAssetMetadata(assetUnit), | ||
}); | ||
|
||
const nftHasImage: any = queryClient.getQueryData([ | ||
METADATA_QUERY_KEY, | ||
assetUnit, | ||
]); | ||
|
||
return nftHasImage?.image !== undefined ? auction : null; | ||
}) | ||
); | ||
|
||
// Auto sorted to most recently started auctions | ||
return filteredAuctions | ||
.filter(Boolean) | ||
?.sort( | ||
(a: AuctionInfo | null, b: AuctionInfo | null) => | ||
Number(b?.auctionTerms.biddingStart) - | ||
Number(a?.auctionTerms.biddingStart) | ||
); | ||
}; | ||
|
||
useEffect(() => { | ||
async function getAuctionsWithImage(auctions: AuctionInfo[]) { | ||
const filteredAuctionsByImage = await fetchAndFilterAuctionsByImage( | ||
auctions | ||
); | ||
setAuctionsWithImage(filteredAuctionsByImage as AuctionInfo[]); | ||
} | ||
if (auctions) { | ||
getAuctionsWithImage(auctions); | ||
} | ||
}, [auctions]); | ||
|
||
useEffect(() => { | ||
if (auctionsWithImage) { | ||
switch (activeFilter) { | ||
case AuctionListSortState.ALL: | ||
setFilteredAuctions(auctionsWithImage); | ||
break; | ||
case AuctionListSortState.SELLER: | ||
setFilteredAuctions( | ||
auctionsWithImage?.filter( | ||
(auction) => auction.auctionTerms.sellerAddress === walletAddress | ||
) | ||
); | ||
break; | ||
case AuctionListSortState.NOT_SELLER: | ||
setFilteredAuctions( | ||
auctionsWithImage?.filter( | ||
(auction) => auction.auctionTerms.sellerAddress !== walletAddress | ||
) | ||
); | ||
break; | ||
default: | ||
setFilteredAuctions(auctionsWithImage); | ||
} | ||
} | ||
}, [activeFilter, auctions, auctionsWithImage]); | ||
|
||
return ( | ||
<> | ||
<div className="flex flex-col justify-center items-center"> | ||
<h1 className="text-title1 text-center mb-3">Query Auctions</h1> | ||
<hr className="border-b border-gray-400 w-32 mb-4" /> | ||
</div> | ||
<div> | ||
<div className="flex items-center gap-2 justify-between p-2 font-semibold"> | ||
<div>{filteredAuctions?.length || 0} Auctions</div> | ||
<DropDown | ||
onChange={(index) => { | ||
setActiveFilter(auctionListFilterOptions[index].accessor); | ||
}} | ||
options={auctionListFilterOptions} | ||
title="Filter Auctions" | ||
/> | ||
</div> | ||
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-4"> | ||
{filteredAuctions?.map((auctionInfo, index) => ( | ||
<AuctionCard | ||
key={`${auctionInfo.auctionId}_${index}`} | ||
auctionInfo={auctionInfo} | ||
/> | ||
))} | ||
</div> | ||
</div> | ||
</> | ||
); | ||
} |
Oops, something went wrong.