Skip to content

Commit

Permalink
Fix file casing
Browse files Browse the repository at this point in the history
  • Loading branch information
ephan committed Apr 16, 2024
1 parent e1a2c93 commit 6769c17
Show file tree
Hide file tree
Showing 37 changed files with 1,884 additions and 43 deletions.
67 changes: 35 additions & 32 deletions src/App.tsx
Expand Up @@ -12,46 +12,49 @@ import Footer from './components/Footer/Footer';
import Topbar from './components/Navbar/Topbar';
import { Bounce, ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { WebSocketProvider } from './providers/WebSocketProvider';

function App() {
return (
<BrowserRouter>
<MeshProvider>
<ReactQueryProvider>
<>
{/* Navbar */}
<Topbar />
<WebSocketProvider>
<>
{/* Navbar */}
<Topbar />

{/* Route configuration */}
<Layout>
<Routes>
<Route path="/" element={<AuctionList />} />
<Route path="/auction-list" element={<AuctionList />} />
<Route path="/create-auction" element={<CreateAuction />} />
<Route path="/auction" element={<AuctionDetail />} />
<Route
path="/create-auction-list"
element={<CreateAuctionList />}
/>
{/* TODO: collection/wallet routes */}
</Routes>
</Layout>
<ToastContainer
position="bottom-center"
autoClose={5000}
hideProgressBar={true}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="light"
transition={Bounce}
/>
{/* Route configuration */}
<Layout>
<Routes>
<Route path="/" element={<AuctionList />} />
<Route path="/auction-list" element={<AuctionList />} />
<Route path="/create-auction" element={<CreateAuction />} />
<Route path="/auction" element={<AuctionDetail />} />
<Route
path="/create-auction-list"
element={<CreateAuctionList />}
/>
{/* TODO: collection/wallet routes */}
</Routes>
</Layout>
<ToastContainer
position="bottom-center"
autoClose={5000}
hideProgressBar={true}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="light"
transition={Bounce}
/>

<Footer />
</>
<Footer />
</>
</WebSocketProvider>
</ReactQueryProvider>
</MeshProvider>
</BrowserRouter>
Expand Down
2 changes: 1 addition & 1 deletion src/Components/CreateAuction/CreateAuctionForm.tsx
Expand Up @@ -104,7 +104,7 @@ const CreateAuctionForm = ({ className }: CreateAuctionFormProps) => {
auctionLot: [auctionLot],
biddingStart:
Number(auctionFormValidated.data.biddingStart) < Date.now()
? Date.now().toString()
? (Date.now() + 30000).toString()
: auctionFormValidated.data.biddingStart,
},
additionalAuctionLotOrefs:
Expand Down
5 changes: 2 additions & 3 deletions src/components/AuctionCard/AuctionCard.tsx
Expand Up @@ -32,10 +32,9 @@ function AuctionCard({ auctionInfo }: AuctionCardProps) {
const { name: walletName } = useWallet();
const { data: standingBidState, isLoading: isLoadingStandingBidState } =
useStandingBidState(walletName as WalletApp, auctionInfo);
const standingBidStatePrice = standingBidState?.value || '';

let formattedPrice = '';
// Unexpected response from queryStandingBidState right now, this will be changed
if (contractOutputResultSchema.safeParse(standingBidStatePrice).success) {
if (contractOutputResultSchema.safeParse(standingBidState).success) {
const standingBidValue = standingBidState?.value as StandingBidState;
formattedPrice = formatLovelaceToAda(standingBidValue?.price);
}
Expand Down
91 changes: 91 additions & 0 deletions src/components/AuctionDetail/AuctionDetail.tsx
@@ -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>
);
}
3 changes: 1 addition & 2 deletions src/components/AuctionDetail/BiddingView.tsx
Expand Up @@ -27,9 +27,8 @@ export default function BiddingView({
auctionInfo
);

const standingBidStatePrice = standingBidState?.value || '';
let formattedPrice = '';
if (contractOutputResultSchema.safeParse(standingBidStatePrice)) {
if (contractOutputResultSchema.safeParse(standingBidState).success) {
const standingBidValue = standingBidState?.value as StandingBidState;
formattedPrice = formatLovelaceToAda(standingBidValue?.price);
}
Expand Down
143 changes: 143 additions & 0 deletions src/components/AuctionList/AuctionList.tsx
@@ -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>
</>
);
}

0 comments on commit 6769c17

Please sign in to comment.