From 0c2d9250390680ebc48bb4c6af36c0e13ea310e3 Mon Sep 17 00:00:00 2001 From: Bartlomiej Tarczynski Date: Thu, 18 Apr 2024 16:51:54 +0200 Subject: [PATCH] Display settled bids list --- .../components/allBids/SettledBidsList.tsx | 107 ++++++++++++++++++ .../src/components/bids/allBids/AllBids.tsx | 16 ++- .../bids/allBids/GoldenTicketWinner.tsx | 65 +++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 packages/frontend/src/components/allBids/SettledBidsList.tsx create mode 100644 packages/frontend/src/components/bids/allBids/GoldenTicketWinner.tsx diff --git a/packages/frontend/src/components/allBids/SettledBidsList.tsx b/packages/frontend/src/components/allBids/SettledBidsList.tsx new file mode 100644 index 00000000..32f083a4 --- /dev/null +++ b/packages/frontend/src/components/allBids/SettledBidsList.tsx @@ -0,0 +1,107 @@ +import { useMemo } from 'react' +import { Bid, bidToBidWithPlace } from '@/types/bid' +import { useBids } from '@/providers/BidsProvider' +import { useAuctionWinners } from '@/blockchain/hooks/useAuctionWinners' +import { GoldenTicketWinner } from '@/components/bids/allBids/GoldenTicketWinner' +import { NothingFound } from '@/components/bids/allBids/NothingFound' +import { BidsListHeaders } from '@/components/bids/BidsListHeaders' +import { BidsSubList } from '@/components/bids/allBids/BidsSubList' +import { matchesBidFn } from '@/components/bids/allBids/matchesBidFn' + +interface Bids { + auction: Bid[] + raffle: Bid[] + others: Bid[] + goldenTicket?: Bid +} + +interface SettledBidsListProps { + search: string +} + +export const SettledBidsList = ({ search }: SettledBidsListProps) => { + const { bidList } = useBids() + const matchesSearch = matchesBidFn(search) + const { auctionWinners, raffleWinners } = useAuctionWinners() + + const settledBids = useMemo( + () => divideBids(bidList, auctionWinners, raffleWinners), + [bidList, auctionWinners, raffleWinners], + ) + + const filteredBids = useMemo(() => filterBids(settledBids, matchesSearch), [settledBids, matchesSearch]) + + return ( + <> + {search && isEmpty(filteredBids) ? ( + + ) : ( + <> + {filteredBids.goldenTicket && } + + {filteredBids.auction.length !== 0 && ( + + )} + {filteredBids.raffle.length !== 0 && ( + + )} + {filteredBids.others.length !== 0 && ( + + )} + + )} + + ) +} + +function divideBids( + bids: Bid[], + auctionWinners: readonly bigint[] | undefined, + raffleWinners: readonly bigint[] | undefined, +): Bids { + const settledBids: Bids = { + auction: [], + raffle: [], + others: [], + } + + if (!auctionWinners || !raffleWinners) { + return settledBids + } + + bids.forEach((bid, index) => { + const bidderID = bid.bidderId + const bidWithPlace = bidToBidWithPlace(bid, index) + if (auctionWinners.find((winnerId) => bid.bidderId === winnerId)) { + settledBids.auction.push(bidWithPlace) + return + } + if (bidderID === raffleWinners[0]) { + settledBids.goldenTicket = bidWithPlace + return + } + if (raffleWinners.find((winnerId) => bid.bidderId === winnerId)) { + settledBids.raffle.push(bidWithPlace) + return + } + settledBids.others.push(bidWithPlace) + }) + return settledBids +} + +function filterBids(bids: Bids, matchesSearch: (bid: Bid) => boolean) { + return { + auction: bids.auction.filter(matchesSearch), + raffle: bids.raffle.filter(matchesSearch), + others: bids.others.filter(matchesSearch), + goldenTicket: bids.goldenTicket && matchesSearch(bids.goldenTicket) ? bids.goldenTicket : undefined, + } +} + +function isEmpty(bids: Bids) { + return bids.auction.length === 0 && bids.raffle.length === 0 && bids.others.length === 0 && !bids.goldenTicket +} diff --git a/packages/frontend/src/components/bids/allBids/AllBids.tsx b/packages/frontend/src/components/bids/allBids/AllBids.tsx index 1ce038ee..ad7dd865 100644 --- a/packages/frontend/src/components/bids/allBids/AllBids.tsx +++ b/packages/frontend/src/components/bids/allBids/AllBids.tsx @@ -6,6 +6,9 @@ import { NothingFound } from '@/components/bids/allBids/NothingFound' import { LoadingBids } from '@/components/bids/allBids/LoadingBids' import { AllBidsList } from '@/components/bids/allBids/AllBidsList' import { SearchInput } from '@/components/form/SearchInput' +import { useContractState } from '@/blockchain/hooks/useAuctionState' +import { isAuctionSettled } from '@/utils/isAuctionSettled' +import { SettledBidsList } from '@/components/allBids/SettledBidsList' export const AllBids = () => { const [search, setSearch] = useState('') @@ -21,6 +24,7 @@ export const AllBids = () => { const AllBidsContent = ({ search }: { search: string }) => { const { auctionWinnersCount, raffleWinnersCount, isLoading: areParamsLoading } = useReadAuctionParams() const { bidList, isLoading: areBidsLoading } = useBids() + const { state } = useContractState() if (areParamsLoading || areBidsLoading || !auctionWinnersCount || !raffleWinnersCount) { return @@ -31,7 +35,17 @@ const AllBidsContent = ({ search }: { search: string }) => { } return ( - + <> + {isAuctionSettled(state) ? ( + + ) : ( + + )} + ) } diff --git a/packages/frontend/src/components/bids/allBids/GoldenTicketWinner.tsx b/packages/frontend/src/components/bids/allBids/GoldenTicketWinner.tsx new file mode 100644 index 00000000..f4537961 --- /dev/null +++ b/packages/frontend/src/components/bids/allBids/GoldenTicketWinner.tsx @@ -0,0 +1,65 @@ +import styled from 'styled-components' +import { Colors } from '@/styles/colors' +import { useExplorerAddressLink } from '@/blockchain/hooks/useExplorerAddressLink' +import { Hex } from 'viem' + +interface Props { + bidderAddress: Hex +} + +export const GoldenTicketWinner = ({ bidderAddress }: Props) => { + const explorerLink = useExplorerAddressLink(bidderAddress) + + return ( + + 🎉 +
+ THE GOLDEN TICKET WINNER IS: + + {bidderAddress} + +
+ 🎉 +
+ ) +} + +const Container = styled.div` + display: flex; + justify-content: space-evenly; + align-items: center; + width: 100%; + height: 90px; + background-color: ${Colors.GreenLight}; +` + +const Section = styled.div` + display: flex; + flex-direction: column; + justify-content: space-evenly; + align-items: center; + height: 100%; +` + +const Doot = styled.div` + display: flex; + justify-content: center; + align-items: center; + font-size: 40px; +` + +const ReverseDoot = styled(Doot)` + transform: matrix(-1, 0, 0, 1, 0, 0); +` + +const HeaderText = styled.h3` + font-size: 20px; + line-height: 150%; +` + +const AddressLink = styled.a` + font-family: 'Space Mono', 'Roboto Mono', monospace; + font-style: normal; + color: ${Colors.Blue}; + text-decoration: none; +`