diff --git a/js/packages/web/src/components/AuctionCard/index.tsx b/js/packages/web/src/components/AuctionCard/index.tsx index 12a7cd9..ea97ff9 100644 --- a/js/packages/web/src/components/AuctionCard/index.tsx +++ b/js/packages/web/src/components/AuctionCard/index.tsx @@ -21,6 +21,7 @@ import { MAX_EDITION_LEN, useWalletModal, VaultState, + BidStateType, } from '@oyster/common'; import { useWallet } from '@solana/wallet-adapter-react'; import { AuctionView, useBidsForAuction, useUserBalance } from '../../hooks'; @@ -254,14 +255,23 @@ export const AuctionCard = ({ const isAuctionNotStarted = auctionView.auction.info.state === AuctionState.Created; - //if instant sale auction bid and claimed hide buttons - if ( - (auctionView.isInstantSale && - Number(auctionView.myBidderPot?.info.emptied) !== 0 && - isAuctionManagerAuthorityNotWalletOwner && - auctionView.auction.info.bidState.max.toNumber() === bids.length) || - auctionView.vault.info.state === VaultState.Deactivated - ) { + const isOpenEditionSale = + auctionView.auction.info.bidState.type === BidStateType.OpenEdition; + const doesInstantSaleHasNoItems = + Number(auctionView.myBidderPot?.info.emptied) !== 0 && + auctionView.auction.info.bidState.max.toNumber() === bids.length; + + const shouldHideInstantSale = + !isOpenEditionSale && + auctionView.isInstantSale && + isAuctionManagerAuthorityNotWalletOwner && + doesInstantSaleHasNoItems; + + const shouldHide = + shouldHideInstantSale || + auctionView.vault.info.state === VaultState.Deactivated; + + if (shouldHide) { return <>; } @@ -515,13 +525,16 @@ export const AuctionCard = ({ const instantSale = async () => { setLoading(true); + const instantSalePrice = auctionView.auctionDataExtended?.info.instantSalePrice; const winningConfigType = + auctionView.participationItem?.winningConfigType || auctionView.items[0][0].winningConfigType; - const isAuctionItemMaster = - winningConfigType === WinningConfigType.FullRightsTransfer || - winningConfigType === WinningConfigType.TokenOnlyTransfer; + const isAuctionItemMaster = [ + WinningConfigType.FullRightsTransfer, + WinningConfigType.TokenOnlyTransfer, + ].includes(winningConfigType); const allowBidToPublic = myPayingAccount && !auctionView.myBidderPot && @@ -532,7 +545,10 @@ export const AuctionCard = ({ isAuctionItemMaster; // Placing a "bid" of the full amount results in a purchase to redeem. - if (instantSalePrice && (allowBidToPublic || allowBidToAuctionOwner)) { + if ( + instantSalePrice && + (allowBidToPublic || allowBidToAuctionOwner) + ) { try { const bid = await sendPlaceBid( connection, diff --git a/js/packages/web/src/views/auctionCreate/index.tsx b/js/packages/web/src/views/auctionCreate/index.tsx index 57531fd..346f986 100644 --- a/js/packages/web/src/views/auctionCreate/index.tsx +++ b/js/packages/web/src/views/auctionCreate/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useMemo, useCallback } from 'react'; import { Divider, Steps, @@ -67,6 +67,12 @@ export enum AuctionCategory { Tiered, } +enum InstantSaleType { + Limited, + Single, + Open, +} + interface TierDummyEntry { safetyDepositBoxIndex: number; amount: number; @@ -123,6 +129,7 @@ export interface AuctionState { winnersCount: number; instantSalePrice?: number; + instantSaleType?: InstantSaleType; } export const AuctionCreateView = () => { @@ -173,26 +180,47 @@ export const AuctionCreateView = () => { const createAuction = async () => { let winnerLimit: WinnerLimit; - if (attributes.category === AuctionCategory.InstantSale) { - if (attributes.items.length > 0) { - const item = attributes.items[0]; - if (!attributes.editions) { + if ( + attributes.category === AuctionCategory.InstantSale && + attributes.instantSaleType === InstantSaleType.Open + ) { + const { items, instantSalePrice } = attributes; + + if (items.length > 0 && items[0].participationConfig) { + items[0].participationConfig.fixedPrice = new BN( + toLamports(instantSalePrice, mint) || 0, + ); + } + + winnerLimit = new WinnerLimit({ + type: WinnerLimitType.Unlimited, + usize: ZERO, + }); + } else if (attributes.category === AuctionCategory.InstantSale) { + const { items, editions } = attributes; + + if (items.length > 0) { + const item = items[0]; + + if (!editions) { item.winningConfigType = item.metadata.info.updateAuthority === (wallet?.publicKey || SystemProgram.programId).toBase58() ? WinningConfigType.FullRightsTransfer : WinningConfigType.TokenOnlyTransfer; } + item.amountRanges = [ new AmountRange({ amount: new BN(1), - length: new BN(attributes.editions || 1), + length: new BN(editions || 1), }), ]; } + winnerLimit = new WinnerLimit({ type: WinnerLimitType.Capped, - usize: new BN(attributes.editions || 1), + usize: new BN(editions || 1), }); } else if (attributes.category === AuctionCategory.Open) { if ( @@ -447,19 +475,25 @@ export const AuctionCreateView = () => { name: null, }; + const isOpenEdition = + attributes.category === AuctionCategory.Open || + attributes.instantSaleType === InstantSaleType.Open; + const safetyDepositDrafts = isOpenEdition + ? [] + : attributes.category !== AuctionCategory.Tiered + ? attributes.items + : tieredAttributes.items; + const participationSafetyDepositDraft = isOpenEdition + ? attributes.items[0] + : attributes.participationNFT; + const _auctionObj = await createAuctionManager( connection, wallet, whitelistedCreatorsByCreator, auctionSettings, - attributes.category === AuctionCategory.Open - ? [] - : attributes.category !== AuctionCategory.Tiered - ? attributes.items - : tieredAttributes.items, - attributes.category === AuctionCategory.Open - ? attributes.items[0] - : attributes.participationNFT, + safetyDepositDrafts, + participationSafetyDepositDraft, QUOTE_MINT.toBase58(), ); setAuctionObj(_auctionObj); @@ -743,19 +777,28 @@ const CategoryStep = (props: { ); }; -const InstantSaleStep = (props: { +const InstantSaleStep = ({ + attributes, + setAttributes, + confirm, +}: { attributes: AuctionState; setAttributes: (attr: AuctionState) => void; confirm: () => void; }) => { - const [copiesChecked, setCopiesChecked] = useState(false); - const copiesEnabled = React.useMemo( - () => !!props.attributes?.items?.[0]?.masterEdition?.info?.maxSupply, - [props.attributes?.items?.[0]], + const copiesEnabled = useMemo( + () => !!attributes?.items?.[0]?.masterEdition?.info?.maxSupply, + [attributes?.items?.[0]], + ); + const artistFilter = useCallback( + (i: SafetyDepositDraft) => + !(i.metadata.info.data.creators || []).some((c: Creator) => !c.verified), + [], ); - let artistFilter = (i: SafetyDepositDraft) => - !(i.metadata.info.data.creators || []).find((c: Creator) => !c.verified); + const isLimitedEdition = + attributes.instantSaleType === InstantSaleType.Limited; + const shouldRenderSelect = attributes.items.length > 0; return ( <> @@ -767,46 +810,63 @@ const InstantSaleStep = (props: { { - props.setAttributes({ ...props.attributes, items }); + setAttributes({ ...attributes, items }); }} allowMultiple={false} > Select NFT - + {shouldRenderSelect && ( + + )}