mirror of https://github.com/certusone/oyster.git
Merge remote-tracking branch 'origin/feature/m-jordan' into feature/m
This commit is contained in:
commit
878e471c05
|
@ -45,6 +45,10 @@ export class BidState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const decodeAuction = (buffer: Buffer) => {
|
||||||
|
return deserializeBorsh(AUCTION_SCHEMA, AuctionData, buffer) as AuctionData;
|
||||||
|
};
|
||||||
|
|
||||||
export const BASE_AUCTION_DATA_SIZE = 32 + 32 + 32 + 8 + 8 + 1 + 9 + 9 + 9 + 9;
|
export const BASE_AUCTION_DATA_SIZE = 32 + 32 + 32 + 8 + 8 + 1 + 9 + 9 + 9 + 9;
|
||||||
|
|
||||||
export class AuctionData {
|
export class AuctionData {
|
||||||
|
@ -67,6 +71,9 @@ export class AuctionData {
|
||||||
/// Gap time is the amount of time in slots after the previous bid at which the auction ends.
|
/// Gap time is the amount of time in slots after the previous bid at which the auction ends.
|
||||||
endAuctionGap?: BN;
|
endAuctionGap?: BN;
|
||||||
|
|
||||||
|
/// Used for precalculation on the front end, not a backend key
|
||||||
|
auctionManagerKey?: PublicKey;
|
||||||
|
|
||||||
constructor(args: {
|
constructor(args: {
|
||||||
authority: PublicKey;
|
authority: PublicKey;
|
||||||
resource: PublicKey;
|
resource: PublicKey;
|
||||||
|
@ -247,7 +254,7 @@ export const AUCTION_SCHEMA = new Map<any, any>([
|
||||||
['resource', 'pubkey'],
|
['resource', 'pubkey'],
|
||||||
['tokenMint', 'pubkey'],
|
['tokenMint', 'pubkey'],
|
||||||
['state', 'u8'],
|
['state', 'u8'],
|
||||||
['bidState', 'BidState'],
|
['bidState', BidState],
|
||||||
['lastBid', { kind: 'option', type: 'u64' }],
|
['lastBid', { kind: 'option', type: 'u64' }],
|
||||||
['endedAt', { kind: 'option', type: 'u64' }],
|
['endedAt', { kind: 'option', type: 'u64' }],
|
||||||
['endAuctionAt', { kind: 'option', type: 'u64' }],
|
['endAuctionAt', { kind: 'option', type: 'u64' }],
|
||||||
|
|
|
@ -258,6 +258,14 @@ export const decodeVault = (buffer: Buffer) => {
|
||||||
return deserializeBorsh(VAULT_SCHEMA, Vault, buffer) as Vault;
|
return deserializeBorsh(VAULT_SCHEMA, Vault, buffer) as Vault;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const decodeSafetyDeposit = (buffer: Buffer) => {
|
||||||
|
return deserializeBorsh(
|
||||||
|
VAULT_SCHEMA,
|
||||||
|
SafetyDepositBox,
|
||||||
|
buffer,
|
||||||
|
) as SafetyDepositBox;
|
||||||
|
};
|
||||||
|
|
||||||
export async function initVault(
|
export async function initVault(
|
||||||
allowFurtherShareCreation: boolean,
|
allowFurtherShareCreation: boolean,
|
||||||
fractionalMint: PublicKey,
|
fractionalMint: PublicKey,
|
||||||
|
|
|
@ -1,39 +1,46 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import {
|
import { Row, Col, Divider, Button, InputNumber } from 'antd';
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
Divider,
|
|
||||||
Button,
|
|
||||||
InputNumber
|
|
||||||
} from 'antd'
|
|
||||||
|
|
||||||
import { Auction, Presale } from '../../types'
|
import { Auction, Presale } from '../../types';
|
||||||
|
|
||||||
import './index.less'
|
import './index.less';
|
||||||
import { getCountdown } from '../../utils/utils'
|
import { getCountdown } from '../../utils/utils';
|
||||||
import { shortenAddress } from '@oyster/common';
|
import { shortenAddress, useConnection } from '@oyster/common';
|
||||||
|
import { AuctionView } from '../../hooks';
|
||||||
|
|
||||||
export const AuctionCard = ({ auction }: { auction: Auction }) => {
|
export const AuctionCard = ({ auctionView }: { auctionView: AuctionView }) => {
|
||||||
const [hours, setHours] = useState<number>(23)
|
const [hours, setHours] = useState<number>(23);
|
||||||
const [minutes, setMinutes] = useState<number>(59)
|
const [minutes, setMinutes] = useState<number>(59);
|
||||||
const [seconds, setSeconds] = useState<number>(59)
|
const [seconds, setSeconds] = useState<number>(59);
|
||||||
|
const [clock, setClock] = useState<number>(0);
|
||||||
|
const connection = useConnection();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
connection.getSlot().then(setClock);
|
||||||
|
}, [connection]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
const { hours, minutes, seconds } = getCountdown(auction.endingTS)
|
const slotDiff =
|
||||||
|
(auctionView.auction.info.endedAt?.toNumber() || 0) - clock;
|
||||||
|
|
||||||
setHours(hours)
|
/* const { hours, minutes, seconds } = getCountdown(
|
||||||
setMinutes(minutes)
|
auctionView.auction.info.endedAt?.toNumber(),
|
||||||
setSeconds(seconds)
|
);
|
||||||
}, 1000)
|
|
||||||
return () => clearInterval(interval)
|
setHours(hours);
|
||||||
}, [])
|
setMinutes(minutes);
|
||||||
|
setSeconds(seconds);*/
|
||||||
|
setHours(1);
|
||||||
|
}, 1000);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [clock]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="presale-card-container">
|
<div className="presale-card-container">
|
||||||
<div className="info-header">STARTING BID</div>
|
<div className="info-header">STARTING BID</div>
|
||||||
<div style={{ fontWeight: 700, fontSize: '1.6rem' }}>◎40.00</div>
|
<div style={{ fontWeight: 700, fontSize: '1.6rem' }}>◎40.00</div>
|
||||||
<br/>
|
<br />
|
||||||
<div className="info-header">AUCTION ENDS IN</div>
|
<div className="info-header">AUCTION ENDS IN</div>
|
||||||
<Row style={{ width: 300 }}>
|
<Row style={{ width: 300 }}>
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
|
@ -49,13 +56,17 @@ export const AuctionCard = ({ auction }: { auction: Auction }) => {
|
||||||
<div className="cd-label">seconds</div>
|
<div className="cd-label">seconds</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<br/>
|
<br />
|
||||||
<div className="info-content" style={{ color: 'rgba(255, 255, 255, 0.7)', fontSize: '0.9rem' }}>
|
<div
|
||||||
Any bids placed in the last 15 minutes will extend the auction for another 15 minutes.
|
className="info-content"
|
||||||
|
style={{ color: 'rgba(255, 255, 255, 0.7)', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
|
Any bids placed in the last 15 minutes will extend the auction for
|
||||||
|
another 15 minutes.
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<div className="info-line"/>
|
<div className="info-line" />
|
||||||
|
|
||||||
<InputNumber
|
<InputNumber
|
||||||
autoFocus
|
autoFocus
|
||||||
|
@ -70,29 +81,36 @@ export const AuctionCard = ({ auction }: { auction: Auction }) => {
|
||||||
// }
|
// }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="info-content" style={{ color: 'rgba(255, 255, 255, 0.7)', fontSize: '0.9rem' }}>
|
<div
|
||||||
|
className="info-content"
|
||||||
|
style={{ color: 'rgba(255, 255, 255, 0.7)', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
Your Balance: ◎ {0.0} (${0.0})
|
Your Balance: ◎ {0.0} (${0.0})
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
size="large"
|
size="large"
|
||||||
className="action-btn"
|
className="action-btn"
|
||||||
style={{ marginTop: 20 }}
|
style={{ marginTop: 20 }}
|
||||||
>
|
>
|
||||||
PLACE BID
|
PLACE BID
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const AuctionBidders = (auctionID: string) => {
|
export const AuctionBidders = (auctionID: string) => {
|
||||||
const bids: any[] = [];
|
const bids: any[] = [];
|
||||||
return <Col>
|
return (
|
||||||
{bids.map((bid, index) => {
|
<Col>
|
||||||
return <Row>{index+1}. {shortenAddress(bid.address)} {bid.amount}</Row>
|
{bids.map((bid, index) => {
|
||||||
})}
|
return (
|
||||||
</Col>
|
<Row>
|
||||||
|
{index + 1}. {shortenAddress(bid.address)} {bid.amount}
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
useConnection,
|
useConnection,
|
||||||
decodeMetadata,
|
decodeMetadata,
|
||||||
decodeNameSymbolTuple,
|
decodeNameSymbolTuple,
|
||||||
|
decodeAuction,
|
||||||
decodeEdition,
|
decodeEdition,
|
||||||
decodeMasterEdition,
|
decodeMasterEdition,
|
||||||
Metadata,
|
Metadata,
|
||||||
|
@ -15,30 +16,55 @@ import {
|
||||||
Edition,
|
Edition,
|
||||||
MasterEdition,
|
MasterEdition,
|
||||||
NameSymbolTuple,
|
NameSymbolTuple,
|
||||||
|
AuctionData,
|
||||||
|
SafetyDepositBox,
|
||||||
|
VaultKey,
|
||||||
|
decodeSafetyDeposit,
|
||||||
} from '@oyster/common';
|
} from '@oyster/common';
|
||||||
import { MintInfo } from '@solana/spl-token';
|
import { MintInfo } from '@solana/spl-token';
|
||||||
import { Connection, PublicKey, PublicKeyAndAccount } from '@solana/web3.js';
|
import { Connection, PublicKey, PublicKeyAndAccount } from '@solana/web3.js';
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
AuctionManager,
|
||||||
|
AuctionManagerStatus,
|
||||||
|
decodeAuctionManager,
|
||||||
|
getAuctionManagerKey,
|
||||||
|
MetaplexKey,
|
||||||
|
} from '../models/metaplex';
|
||||||
|
|
||||||
const { MetadataKey } = actions;
|
const { MetadataKey } = actions;
|
||||||
export interface MetaContextState {
|
export interface MetaContextState {
|
||||||
metadata: ParsedAccount<Metadata>[];
|
metadata: ParsedAccount<Metadata>[];
|
||||||
|
metadataByMint: Record<string, ParsedAccount<Metadata>>;
|
||||||
nameSymbolTuples: Record<string, ParsedAccount<NameSymbolTuple>>;
|
nameSymbolTuples: Record<string, ParsedAccount<NameSymbolTuple>>;
|
||||||
editions: Record<string, ParsedAccount<Edition>>;
|
editions: Record<string, ParsedAccount<Edition>>;
|
||||||
masterEditions: Record<string, ParsedAccount<MasterEdition>>;
|
masterEditions: Record<string, ParsedAccount<MasterEdition>>;
|
||||||
|
auctionManagers: Record<string, ParsedAccount<AuctionManager>>;
|
||||||
|
auctions: Record<string, ParsedAccount<AuctionData>>;
|
||||||
|
safetyDepositBoxesByVaultAndIndex: Record<
|
||||||
|
string,
|
||||||
|
ParsedAccount<SafetyDepositBox>
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MetaContext = React.createContext<MetaContextState>({
|
const MetaContext = React.createContext<MetaContextState>({
|
||||||
metadata: [],
|
metadata: [],
|
||||||
|
metadataByMint: {},
|
||||||
nameSymbolTuples: {},
|
nameSymbolTuples: {},
|
||||||
masterEditions: {},
|
masterEditions: {},
|
||||||
editions: {},
|
editions: {},
|
||||||
|
auctionManagers: {},
|
||||||
|
auctions: {},
|
||||||
|
safetyDepositBoxesByVaultAndIndex: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function MetaProvider({ children = null as any }) {
|
export function MetaProvider({ children = null as any }) {
|
||||||
const connection = useConnection();
|
const connection = useConnection();
|
||||||
const [metadata, setMetadata] = useState<ParsedAccount<Metadata>[]>([]);
|
const [metadata, setMetadata] = useState<ParsedAccount<Metadata>[]>([]);
|
||||||
|
const [metadataByMint, setMetadataByMint] = useState<
|
||||||
|
Record<string, ParsedAccount<Metadata>>
|
||||||
|
>({});
|
||||||
const [nameSymbolTuples, setNameSymbolTuples] = useState<
|
const [nameSymbolTuples, setNameSymbolTuples] = useState<
|
||||||
Record<string, ParsedAccount<NameSymbolTuple>>
|
Record<string, ParsedAccount<NameSymbolTuple>>
|
||||||
>({});
|
>({});
|
||||||
|
@ -48,12 +74,181 @@ export function MetaProvider({ children = null as any }) {
|
||||||
const [editions, setEditions] = useState<
|
const [editions, setEditions] = useState<
|
||||||
Record<string, ParsedAccount<Edition>>
|
Record<string, ParsedAccount<Edition>>
|
||||||
>({});
|
>({});
|
||||||
|
const [auctionManagers, setAuctionManagers] = useState<
|
||||||
|
Record<string, ParsedAccount<AuctionManager>>
|
||||||
|
>({});
|
||||||
|
const [auctions, setAuctions] = useState<
|
||||||
|
Record<string, ParsedAccount<AuctionData>>
|
||||||
|
>({});
|
||||||
|
const [
|
||||||
|
safetyDepositBoxesByVaultAndIndex,
|
||||||
|
setSafetyDepositBoxesByVaultAndIndex,
|
||||||
|
] = useState<Record<string, ParsedAccount<SafetyDepositBox>>>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let dispose = () => {};
|
let dispose = () => {};
|
||||||
(async () => {
|
(async () => {
|
||||||
const mintToMetadata = new Map<string, ParsedAccount<Metadata>>();
|
const processAuctions = async (a: PublicKeyAndAccount<Buffer>) => {
|
||||||
|
try {
|
||||||
|
const auction = await decodeAuction(a.account.data);
|
||||||
|
auction.auctionManagerKey = await getAuctionManagerKey(
|
||||||
|
auction.resource,
|
||||||
|
a.pubkey,
|
||||||
|
);
|
||||||
|
const account: ParsedAccount<AuctionData> = {
|
||||||
|
pubkey: a.pubkey,
|
||||||
|
account: a.account,
|
||||||
|
info: auction,
|
||||||
|
};
|
||||||
|
setAuctions(e => ({
|
||||||
|
...e,
|
||||||
|
[a.pubkey.toBase58()]: account,
|
||||||
|
}));
|
||||||
|
} catch {
|
||||||
|
// ignore errors
|
||||||
|
// add type as first byte for easier deserialization
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const accounts = await connection.getProgramAccounts(
|
||||||
|
programIds().auction,
|
||||||
|
);
|
||||||
|
for (let i = 0; i < accounts.length; i++) {
|
||||||
|
await processAuctions(accounts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let subId = connection.onProgramAccountChange(
|
||||||
|
programIds().auction,
|
||||||
|
async info => {
|
||||||
|
const pubkey =
|
||||||
|
typeof info.accountId === 'string'
|
||||||
|
? new PublicKey((info.accountId as unknown) as string)
|
||||||
|
: info.accountId;
|
||||||
|
await processAuctions({
|
||||||
|
pubkey,
|
||||||
|
account: info.accountInfo,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
dispose = () => {
|
||||||
|
connection.removeProgramAccountChangeListener(subId);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
dispose();
|
||||||
|
};
|
||||||
|
}, [connection, setAuctions]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let dispose = () => {};
|
||||||
|
(async () => {
|
||||||
|
const processSafetyDeposits = async (a: PublicKeyAndAccount<Buffer>) => {
|
||||||
|
try {
|
||||||
|
if (a.account.data[0] == VaultKey.SafetyDepositBoxV1) {
|
||||||
|
const safetyDeposit = await decodeSafetyDeposit(a.account.data);
|
||||||
|
const account: ParsedAccount<SafetyDepositBox> = {
|
||||||
|
pubkey: a.pubkey,
|
||||||
|
account: a.account,
|
||||||
|
info: safetyDeposit,
|
||||||
|
};
|
||||||
|
setSafetyDepositBoxesByVaultAndIndex(e => ({
|
||||||
|
...e,
|
||||||
|
[safetyDeposit.vault.toBase58() +
|
||||||
|
'-' +
|
||||||
|
safetyDeposit.order]: account,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore errors
|
||||||
|
// add type as first byte for easier deserialization
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const accounts = await connection.getProgramAccounts(programIds().vault);
|
||||||
|
for (let i = 0; i < accounts.length; i++) {
|
||||||
|
await processSafetyDeposits(accounts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let subId = connection.onProgramAccountChange(
|
||||||
|
programIds().vault,
|
||||||
|
async info => {
|
||||||
|
const pubkey =
|
||||||
|
typeof info.accountId === 'string'
|
||||||
|
? new PublicKey((info.accountId as unknown) as string)
|
||||||
|
: info.accountId;
|
||||||
|
await processSafetyDeposits({
|
||||||
|
pubkey,
|
||||||
|
account: info.accountInfo,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
dispose = () => {
|
||||||
|
connection.removeProgramAccountChangeListener(subId);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
dispose();
|
||||||
|
};
|
||||||
|
}, [connection, setSafetyDepositBoxesByVaultAndIndex]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let dispose = () => {};
|
||||||
|
(async () => {
|
||||||
|
const processAuctionManagers = async (a: PublicKeyAndAccount<Buffer>) => {
|
||||||
|
try {
|
||||||
|
if (a.account.data[0] == MetaplexKey.AuctionManagerV1) {
|
||||||
|
const auctionManager = await decodeAuctionManager(a.account.data);
|
||||||
|
const account: ParsedAccount<AuctionManager> = {
|
||||||
|
pubkey: a.pubkey,
|
||||||
|
account: a.account,
|
||||||
|
info: auctionManager,
|
||||||
|
};
|
||||||
|
setAuctionManagers(e => ({
|
||||||
|
...e,
|
||||||
|
[a.pubkey.toBase58()]: account,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore errors
|
||||||
|
// add type as first byte for easier deserialization
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const accounts = await connection.getProgramAccounts(
|
||||||
|
programIds().metaplex,
|
||||||
|
);
|
||||||
|
for (let i = 0; i < accounts.length; i++) {
|
||||||
|
await processAuctionManagers(accounts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let subId = connection.onProgramAccountChange(
|
||||||
|
programIds().metaplex,
|
||||||
|
async info => {
|
||||||
|
const pubkey =
|
||||||
|
typeof info.accountId === 'string'
|
||||||
|
? new PublicKey((info.accountId as unknown) as string)
|
||||||
|
: info.accountId;
|
||||||
|
await processAuctionManagers({
|
||||||
|
pubkey,
|
||||||
|
account: info.accountInfo,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
dispose = () => {
|
||||||
|
connection.removeProgramAccountChangeListener(subId);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
dispose();
|
||||||
|
};
|
||||||
|
}, [connection, setAuctionManagers]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let dispose = () => {};
|
||||||
|
(async () => {
|
||||||
const processMetaData = async (meta: PublicKeyAndAccount<Buffer>) => {
|
const processMetaData = async (meta: PublicKeyAndAccount<Buffer>) => {
|
||||||
try {
|
try {
|
||||||
if (meta.account.data[0] == MetadataKey.MetadataV1) {
|
if (meta.account.data[0] == MetadataKey.MetadataV1) {
|
||||||
|
@ -67,7 +262,10 @@ export function MetaProvider({ children = null as any }) {
|
||||||
account: meta.account,
|
account: meta.account,
|
||||||
info: metadata,
|
info: metadata,
|
||||||
};
|
};
|
||||||
mintToMetadata.set(metadata.mint.toBase58(), account);
|
setMetadataByMint(e => ({
|
||||||
|
...e,
|
||||||
|
[metadata.mint.toBase58()]: account,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
} else if (meta.account.data[0] == MetadataKey.EditionV1) {
|
} else if (meta.account.data[0] == MetadataKey.EditionV1) {
|
||||||
const edition = decodeEdition(meta.account.data);
|
const edition = decodeEdition(meta.account.data);
|
||||||
|
@ -113,20 +311,21 @@ export function MetaProvider({ children = null as any }) {
|
||||||
await processMetaData(accounts[i]);
|
await processMetaData(accounts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
await queryExtendedMetadata(connection, setMetadata, mintToMetadata);
|
await queryExtendedMetadata(connection, setMetadata, metadataByMint);
|
||||||
|
|
||||||
let subId = connection.onProgramAccountChange(
|
let subId = connection.onProgramAccountChange(
|
||||||
programIds().metadata,
|
programIds().metadata,
|
||||||
async info => {
|
async info => {
|
||||||
const pubkey = typeof info.accountId === 'string' ?
|
const pubkey =
|
||||||
new PublicKey((info.accountId as unknown) as string) :
|
typeof info.accountId === 'string'
|
||||||
info.accountId;
|
? new PublicKey((info.accountId as unknown) as string)
|
||||||
|
: info.accountId;
|
||||||
await processMetaData({
|
await processMetaData({
|
||||||
pubkey,
|
pubkey,
|
||||||
account: info.accountInfo,
|
account: info.accountInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
queryExtendedMetadata(connection, setMetadata, mintToMetadata);
|
queryExtendedMetadata(connection, setMetadata, metadataByMint);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
dispose = () => {
|
dispose = () => {
|
||||||
|
@ -147,7 +346,16 @@ export function MetaProvider({ children = null as any }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MetaContext.Provider
|
<MetaContext.Provider
|
||||||
value={{ metadata, editions, masterEditions, nameSymbolTuples }}
|
value={{
|
||||||
|
metadata,
|
||||||
|
editions,
|
||||||
|
masterEditions,
|
||||||
|
nameSymbolTuples,
|
||||||
|
auctionManagers,
|
||||||
|
auctions,
|
||||||
|
metadataByMint,
|
||||||
|
safetyDepositBoxesByVaultAndIndex,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</MetaContext.Provider>
|
</MetaContext.Provider>
|
||||||
|
@ -157,14 +365,14 @@ export function MetaProvider({ children = null as any }) {
|
||||||
const queryExtendedMetadata = async (
|
const queryExtendedMetadata = async (
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
setMetadata: (metadata: ParsedAccount<Metadata>[]) => void,
|
setMetadata: (metadata: ParsedAccount<Metadata>[]) => void,
|
||||||
mintToMeta: Map<string, ParsedAccount<Metadata>>,
|
mintToMeta: Record<string, ParsedAccount<Metadata>>,
|
||||||
) => {
|
) => {
|
||||||
const mintToMetadata = new Map<string, ParsedAccount<Metadata>>(mintToMeta);
|
const mintToMetadata = { ...mintToMeta };
|
||||||
const extendedMetadataFetch = new Map<string, Promise<any>>();
|
const extendedMetadataFetch = new Map<string, Promise<any>>();
|
||||||
|
|
||||||
const mints = await getMultipleAccounts(
|
const mints = await getMultipleAccounts(
|
||||||
connection,
|
connection,
|
||||||
[...mintToMetadata.keys()].filter(k => !cache.get(k)),
|
[...Object.keys(mintToMetadata)].filter(k => !cache.get(k)),
|
||||||
'single',
|
'single',
|
||||||
);
|
);
|
||||||
mints.keys.forEach((key, index) => {
|
mints.keys.forEach((key, index) => {
|
||||||
|
@ -176,9 +384,9 @@ const queryExtendedMetadata = async (
|
||||||
) as ParsedAccount<MintInfo>;
|
) as ParsedAccount<MintInfo>;
|
||||||
if (mint.info.supply.gt(new BN(1)) || mint.info.decimals !== 0) {
|
if (mint.info.supply.gt(new BN(1)) || mint.info.decimals !== 0) {
|
||||||
// naive not NFT check
|
// naive not NFT check
|
||||||
mintToMetadata.delete(key);
|
delete mintToMetadata[key];
|
||||||
} else {
|
} else {
|
||||||
const metadata = mintToMetadata.get(key);
|
const metadata = mintToMetadata[key];
|
||||||
if (metadata && metadata.info.uri) {
|
if (metadata && metadata.info.uri) {
|
||||||
extendedMetadataFetch.set(
|
extendedMetadataFetch.set(
|
||||||
key,
|
key,
|
||||||
|
@ -190,19 +398,19 @@ const queryExtendedMetadata = async (
|
||||||
!metadata.info.extended ||
|
!metadata.info.extended ||
|
||||||
metadata.info.extended?.files?.length === 0
|
metadata.info.extended?.files?.length === 0
|
||||||
) {
|
) {
|
||||||
mintToMetadata.delete(key);
|
delete mintToMetadata[key];
|
||||||
} else {
|
} else {
|
||||||
if (metadata.info.extended?.image) {
|
if (metadata.info.extended?.image) {
|
||||||
metadata.info.extended.image = `${metadata.info.uri}/${metadata.info.extended.image}`;
|
metadata.info.extended.image = `${metadata.info.uri}/${metadata.info.extended.image}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
mintToMetadata.delete(key);
|
delete mintToMetadata[key];
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
mintToMetadata.delete(key);
|
delete mintToMetadata[key];
|
||||||
return undefined;
|
return undefined;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -212,7 +420,7 @@ const queryExtendedMetadata = async (
|
||||||
|
|
||||||
await Promise.all([...extendedMetadataFetch.values()]);
|
await Promise.all([...extendedMetadataFetch.values()]);
|
||||||
|
|
||||||
setMetadata([...mintToMetadata.values()]);
|
setMetadata([...Object.values(mintToMetadata)]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useMeta = () => {
|
export const useMeta = () => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { PublicKey } from '@solana/web3.js';
|
import { PublicKey } from '@solana/web3.js';
|
||||||
import { useMeta } from './../contexts';
|
import { useMeta } from '../contexts';
|
||||||
import { Art } from '../types';
|
import { Art } from '../types';
|
||||||
|
|
||||||
export const useArt = (id: PublicKey | string) => {
|
export const useArt = (id: PublicKey | string) => {
|
|
@ -0,0 +1,45 @@
|
||||||
|
import {
|
||||||
|
ParsedAccount,
|
||||||
|
Metadata,
|
||||||
|
SafetyDepositBox,
|
||||||
|
AuctionData,
|
||||||
|
useConnection,
|
||||||
|
AuctionState,
|
||||||
|
} from '@oyster/common';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { AuctionView, processAccountsIntoAuctionView } from '.';
|
||||||
|
import { useMeta } from '../contexts';
|
||||||
|
import { AuctionManager } from '../models/metaplex';
|
||||||
|
import { sampleAuction } from '../views/home/sampleData';
|
||||||
|
|
||||||
|
export const useAuction = (id: string) => {
|
||||||
|
const connection = useConnection();
|
||||||
|
const [clock, setClock] = useState<number>(0);
|
||||||
|
const [auctionView, setAuctionView] = useState<AuctionView | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
connection.getSlot().then(setClock);
|
||||||
|
}, [connection]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
auctions,
|
||||||
|
auctionManagers,
|
||||||
|
safetyDepositBoxesByVaultAndIndex,
|
||||||
|
metadataByMint,
|
||||||
|
} = useMeta();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const auction = auctions[id];
|
||||||
|
if (auction) {
|
||||||
|
const auctionView = processAccountsIntoAuctionView(
|
||||||
|
auction,
|
||||||
|
auctionManagers,
|
||||||
|
safetyDepositBoxesByVaultAndIndex,
|
||||||
|
metadataByMint,
|
||||||
|
clock,
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
if (auctionView) setAuctionView(auctionView);
|
||||||
|
}
|
||||||
|
}, [clock]);
|
||||||
|
return auctionView;
|
||||||
|
};
|
|
@ -1,9 +0,0 @@
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import { sampleAuction } from '../views/home/sampleData';
|
|
||||||
import { useMeta } from './../contexts';
|
|
||||||
|
|
||||||
export const useAuction = (id: string) => {
|
|
||||||
const { metadata } = useMeta();
|
|
||||||
|
|
||||||
return sampleAuction;
|
|
||||||
}
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
import {
|
||||||
|
ParsedAccount,
|
||||||
|
Metadata,
|
||||||
|
SafetyDepositBox,
|
||||||
|
AuctionData,
|
||||||
|
useConnection,
|
||||||
|
AuctionState,
|
||||||
|
} from '@oyster/common';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useMeta } from '../contexts';
|
||||||
|
import { AuctionManager } from '../models/metaplex';
|
||||||
|
|
||||||
|
export enum AuctionViewState {
|
||||||
|
Live = '0',
|
||||||
|
Upcoming = '1',
|
||||||
|
Ended = '2',
|
||||||
|
BuyNow = '3',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AuctionViewItem {
|
||||||
|
metadata: ParsedAccount<Metadata>;
|
||||||
|
safetyDeposit: ParsedAccount<SafetyDepositBox>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flattened surface item for easy display
|
||||||
|
export interface AuctionView {
|
||||||
|
items: AuctionViewItem[];
|
||||||
|
auction: ParsedAccount<AuctionData>;
|
||||||
|
auctionManager: ParsedAccount<AuctionManager>;
|
||||||
|
openEditionItem?: AuctionViewItem;
|
||||||
|
state: AuctionViewState;
|
||||||
|
thumbnail: AuctionViewItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAuctions = (state: AuctionViewState) => {
|
||||||
|
const connection = useConnection();
|
||||||
|
const [clock, setClock] = useState<number>(0);
|
||||||
|
const [auctionViews, setAuctionViews] = useState<AuctionView[]>([]);
|
||||||
|
useEffect(() => {
|
||||||
|
connection.getSlot().then(setClock);
|
||||||
|
}, [connection]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
auctions,
|
||||||
|
auctionManagers,
|
||||||
|
safetyDepositBoxesByVaultAndIndex,
|
||||||
|
metadataByMint,
|
||||||
|
} = useMeta();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const newAuctionViews: AuctionView[] = [];
|
||||||
|
Object.keys(auctions).forEach(a => {
|
||||||
|
const auction = auctions[a];
|
||||||
|
const auctionView = processAccountsIntoAuctionView(
|
||||||
|
auction,
|
||||||
|
auctionManagers,
|
||||||
|
safetyDepositBoxesByVaultAndIndex,
|
||||||
|
metadataByMint,
|
||||||
|
clock,
|
||||||
|
state,
|
||||||
|
);
|
||||||
|
if (auctionView) newAuctionViews.push(auctionView);
|
||||||
|
});
|
||||||
|
setAuctionViews(newAuctionViews);
|
||||||
|
}, [clock, state, auctions]);
|
||||||
|
|
||||||
|
return auctionViews;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function processAccountsIntoAuctionView(
|
||||||
|
auction: ParsedAccount<AuctionData>,
|
||||||
|
auctionManagers: Record<string, ParsedAccount<AuctionManager>>,
|
||||||
|
safetyDepositBoxesByVaultAndIndex: Record<
|
||||||
|
string,
|
||||||
|
ParsedAccount<SafetyDepositBox>
|
||||||
|
>,
|
||||||
|
metadataByMint: Record<string, ParsedAccount<Metadata>>,
|
||||||
|
clock: number,
|
||||||
|
desiredState: AuctionViewState | undefined,
|
||||||
|
) {
|
||||||
|
let state: AuctionViewState;
|
||||||
|
if (
|
||||||
|
auction.info.state == AuctionState.Ended ||
|
||||||
|
(auction.info.endedAt && auction.info.endedAt.toNumber() <= clock)
|
||||||
|
) {
|
||||||
|
state = AuctionViewState.Ended;
|
||||||
|
} else if (
|
||||||
|
auction.info.state == AuctionState.Started ||
|
||||||
|
(auction.info.endedAt && auction.info.endedAt.toNumber() > clock)
|
||||||
|
) {
|
||||||
|
state = AuctionViewState.Live;
|
||||||
|
} else if (auction.info.state == AuctionState.Created) {
|
||||||
|
state = AuctionViewState.Upcoming;
|
||||||
|
} else {
|
||||||
|
state = AuctionViewState.BuyNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desiredState && desiredState != state) return null;
|
||||||
|
|
||||||
|
const auctionManager =
|
||||||
|
auctionManagers[auction.info.auctionManagerKey?.toBase58() || ''];
|
||||||
|
if (auctionManager) {
|
||||||
|
let boxes: ParsedAccount<SafetyDepositBox>[] = [];
|
||||||
|
let box =
|
||||||
|
safetyDepositBoxesByVaultAndIndex[
|
||||||
|
auctionManager.info.vault.toBase58() + '-0'
|
||||||
|
];
|
||||||
|
if (box) {
|
||||||
|
boxes.push(box);
|
||||||
|
let i = 1;
|
||||||
|
while (box) {
|
||||||
|
box =
|
||||||
|
safetyDepositBoxesByVaultAndIndex[
|
||||||
|
auctionManager.info.vault.toBase58() + '-' + i.toString()
|
||||||
|
];
|
||||||
|
if (box) boxes.push(box);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boxes.length > 0) {
|
||||||
|
let view: any = {
|
||||||
|
auction,
|
||||||
|
auctionManager,
|
||||||
|
state,
|
||||||
|
items: auctionManager.info.settings.winningConfigs.map(w => ({
|
||||||
|
metadata:
|
||||||
|
metadataByMint[
|
||||||
|
boxes[w.safetyDepositBoxIndex].info.tokenMint.toBase58()
|
||||||
|
],
|
||||||
|
safetyDeposit: boxes[w.safetyDepositBoxIndex],
|
||||||
|
})),
|
||||||
|
openEditionItem:
|
||||||
|
auctionManager.info.settings.openEditionConfig != null
|
||||||
|
? {
|
||||||
|
metadata:
|
||||||
|
metadataByMint[
|
||||||
|
boxes[
|
||||||
|
auctionManager.info.settings.openEditionConfig
|
||||||
|
].info.tokenMint.toBase58()
|
||||||
|
],
|
||||||
|
safetyDeposit:
|
||||||
|
boxes[auctionManager.info.settings.openEditionConfig],
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
view.thumbnail = view.items[0] || view.openEditionItem;
|
||||||
|
if (!view.thumbnail || !view.thumbnail.metadata) return null;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import { useMeta } from './../contexts';
|
|
||||||
|
|
||||||
export enum AuctionState {
|
|
||||||
Live = '0',
|
|
||||||
Upcoming = '1',
|
|
||||||
Ended = '2',
|
|
||||||
BuyNow = '3',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useAuctions = (state: AuctionState) => {
|
|
||||||
const { metadata } = useMeta();
|
|
||||||
|
|
||||||
return metadata;
|
|
||||||
}
|
|
|
@ -140,6 +140,9 @@ export class WinningConfig {
|
||||||
Object.assign(this, args);
|
Object.assign(this, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export const decodeAuctionManager = (buffer: Buffer) => {
|
||||||
|
return deserializeBorsh(SCHEMA, AuctionManager, buffer) as AuctionManager;
|
||||||
|
};
|
||||||
|
|
||||||
export class WinningConfigState {
|
export class WinningConfigState {
|
||||||
amountMinted: number = 0;
|
amountMinted: number = 0;
|
||||||
|
@ -313,6 +316,20 @@ export const SCHEMA = new Map<any, any>([
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export async function getAuctionManagerKey(
|
||||||
|
vault: PublicKey,
|
||||||
|
auctionKey: PublicKey,
|
||||||
|
): Promise<PublicKey> {
|
||||||
|
const PROGRAM_IDS = programIds();
|
||||||
|
|
||||||
|
return (
|
||||||
|
await PublicKey.findProgramAddress(
|
||||||
|
[Buffer.from(METAPLEX_PREFIX), auctionKey.toBuffer()],
|
||||||
|
PROGRAM_IDS.metaplex,
|
||||||
|
)
|
||||||
|
)[0];
|
||||||
|
}
|
||||||
|
|
||||||
export async function getAuctionKeys(
|
export async function getAuctionKeys(
|
||||||
vault: PublicKey,
|
vault: PublicKey,
|
||||||
): Promise<{ auctionKey: PublicKey; auctionManagerKey: PublicKey }> {
|
): Promise<{ auctionKey: PublicKey; auctionManagerKey: PublicKey }> {
|
||||||
|
@ -329,12 +346,7 @@ export async function getAuctionKeys(
|
||||||
)
|
)
|
||||||
)[0];
|
)[0];
|
||||||
|
|
||||||
const auctionManagerKey: PublicKey = (
|
const auctionManagerKey = await getAuctionManagerKey(vault, auctionKey);
|
||||||
await PublicKey.findProgramAddress(
|
|
||||||
[Buffer.from(METAPLEX_PREFIX), auctionKey.toBuffer()],
|
|
||||||
PROGRAM_IDS.metaplex,
|
|
||||||
)
|
|
||||||
)[0];
|
|
||||||
|
|
||||||
return { auctionKey, auctionManagerKey };
|
return { auctionKey, auctionManagerKey };
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,40 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { Row, Col, Divider, Layout, Image } from 'antd';
|
import { Row, Col, Divider, Layout, Image, Spin } from 'antd';
|
||||||
import { AuctionCard } from '../../components/AuctionCard';
|
import { AuctionCard } from '../../components/AuctionCard';
|
||||||
import { useArt, useAuction } from '../../hooks';
|
import { useArt, useAuction } from '../../hooks';
|
||||||
import { ArtContent } from '../../components/ArtContent';
|
import { ArtContent } from '../../components/ArtContent';
|
||||||
import { sampleArtist } from '../home/sampleData';
|
import { sampleArtist } from '../home/sampleData';
|
||||||
|
|
||||||
const { Content } = Layout
|
const { Content } = Layout;
|
||||||
|
|
||||||
export const AuctionView = () => {
|
export const AuctionView = () => {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
const auction = useAuction(id);
|
const auction = useAuction(id);
|
||||||
const art = useArt(id);
|
const art = useArt(id);
|
||||||
const artist = sampleArtist
|
const artist = sampleArtist;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Content>
|
<Content>
|
||||||
<Col>
|
<Col>
|
||||||
<Row>
|
<Row>
|
||||||
<ArtContent category={art.category} content={art.image} className="artwork-image" />
|
<ArtContent
|
||||||
|
category={art.category}
|
||||||
|
content={art.image}
|
||||||
|
className="artwork-image"
|
||||||
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Row style={{ margin: '0 30px', textAlign: 'left', fontSize: '1.4rem' }}>
|
<Row
|
||||||
<Col span={12} >
|
style={{ margin: '0 30px', textAlign: 'left', fontSize: '1.4rem' }}
|
||||||
|
>
|
||||||
|
<Col span={12}>
|
||||||
<div style={{ fontWeight: 700 }}>{art.title}</div>
|
<div style={{ fontWeight: 700 }}>{art.title}</div>
|
||||||
<br />
|
<br />
|
||||||
<div className="info-header">CREATED BY</div>
|
<div className="info-header">CREATED BY</div>
|
||||||
<div className="info-content"><img src={artist.image} className="artist-image" /> @{art.artist}</div>
|
<div className="info-content">
|
||||||
|
<img src={artist.image} className="artist-image" /> @{art.artist}
|
||||||
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div className="info-header">CREATOR ROYALTIES</div>
|
<div className="info-header">CREATOR ROYALTIES</div>
|
||||||
<div className="royalties">{art.royalties}%</div>
|
<div className="royalties">{art.royalties}%</div>
|
||||||
|
@ -38,7 +46,7 @@ export const AuctionView = () => {
|
||||||
<div className="info-content">{artist.about}</div>
|
<div className="info-content">{artist.about}</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<AuctionCard auction={auction} />
|
{auction ? <AuctionCard auctionView={auction} /> : <Spin />}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
|
@ -129,7 +129,7 @@ export const AuctionCreateView = () => {
|
||||||
const [attributes, setAttributes] = useState<AuctionState>({
|
const [attributes, setAttributes] = useState<AuctionState>({
|
||||||
reservationPrice: 0,
|
reservationPrice: 0,
|
||||||
items: [],
|
items: [],
|
||||||
category: AuctionCategory.Open,
|
category: AuctionCategory.Single,
|
||||||
saleType: 'auction',
|
saleType: 'auction',
|
||||||
winnersCount: 1,
|
winnersCount: 1,
|
||||||
});
|
});
|
||||||
|
@ -161,6 +161,7 @@ export const AuctionCreateView = () => {
|
||||||
usize: ZERO,
|
usize: ZERO,
|
||||||
});
|
});
|
||||||
} else if (attributes.category == AuctionCategory.Single) {
|
} else if (attributes.category == AuctionCategory.Single) {
|
||||||
|
console.log('Using single');
|
||||||
settings = new AuctionManagerSettings({
|
settings = new AuctionManagerSettings({
|
||||||
openEditionWinnerConstraint: WinningConstraint.NoOpenEdition,
|
openEditionWinnerConstraint: WinningConstraint.NoOpenEdition,
|
||||||
openEditionNonWinningConstraint: NonWinningConstraint.NoOpenEdition,
|
openEditionNonWinningConstraint: NonWinningConstraint.NoOpenEdition,
|
||||||
|
|
|
@ -1,52 +1,58 @@
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react';
|
||||||
import { Layout, Row, Col, Tabs } from 'antd'
|
import { Layout, Row, Col, Tabs } from 'antd';
|
||||||
import Masonry from 'react-masonry-css'
|
import Masonry from 'react-masonry-css';
|
||||||
|
|
||||||
import { PreSaleBanner } from '../../components/PreSaleBanner'
|
import { PreSaleBanner } from '../../components/PreSaleBanner';
|
||||||
import { AuctionState, useAuctions } from '../../hooks'
|
import { AuctionViewState, useAuctions } from '../../hooks';
|
||||||
|
|
||||||
import './index.less'
|
import './index.less';
|
||||||
import { ArtCard } from '../../components/ArtCard'
|
import { ArtCard } from '../../components/ArtCard';
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
const { TabPane } = Tabs;
|
const { TabPane } = Tabs;
|
||||||
|
|
||||||
const { Content } = Layout
|
const { Content } = Layout;
|
||||||
export const HomeView = () => {
|
export const HomeView = () => {
|
||||||
const [activeKey, setActiveKey] = useState(AuctionState.Live);
|
const [activeKey, setActiveKey] = useState(AuctionViewState.Live);
|
||||||
const auctions = useAuctions(AuctionState.Live)
|
const auctions = useAuctions(activeKey);
|
||||||
|
console.log('Auctions', auctions);
|
||||||
const breakpointColumnsObj = {
|
const breakpointColumnsObj = {
|
||||||
default: 4,
|
default: 4,
|
||||||
1100: 3,
|
1100: 3,
|
||||||
700: 2,
|
700: 2,
|
||||||
500: 1
|
500: 1,
|
||||||
}
|
};
|
||||||
|
|
||||||
const auctionGrid = <Masonry
|
const auctionGrid = (
|
||||||
|
<Masonry
|
||||||
breakpointCols={breakpointColumnsObj}
|
breakpointCols={breakpointColumnsObj}
|
||||||
className="my-masonry-grid"
|
className="my-masonry-grid"
|
||||||
columnClassName="my-masonry-grid_column"
|
columnClassName="my-masonry-grid_column"
|
||||||
>
|
>
|
||||||
{auctions.map(m => {
|
{auctions.map(m => {
|
||||||
const id = m.pubkey.toBase58();
|
const id = m.auction.pubkey.toBase58();
|
||||||
return <Link to={`/art/${id}`}>
|
return (
|
||||||
<ArtCard key={id}
|
<Link to={`/art/${id}`}>
|
||||||
image={m.info.extended?.image}
|
<ArtCard
|
||||||
category={m.info.extended?.category}
|
key={id}
|
||||||
name={m.info?.name}
|
image={m.thumbnail.metadata.info.extended?.image}
|
||||||
symbol={m.info.symbol}
|
category={m.thumbnail.metadata.info.extended?.category}
|
||||||
description={m.info.extended?.description}
|
name={m.thumbnail.metadata?.info.name}
|
||||||
preview={false} />
|
symbol={m.thumbnail.metadata?.info.symbol}
|
||||||
</Link>
|
description={m.thumbnail.metadata?.info.extended?.description}
|
||||||
})}
|
preview={false}
|
||||||
</Masonry>;
|
/>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Masonry>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout style={{ margin: 0, marginTop: 30 }}>
|
<Layout style={{ margin: 0, marginTop: 30 }}>
|
||||||
<PreSaleBanner
|
<PreSaleBanner
|
||||||
artistName={"RAC"}
|
artistName={'RAC'}
|
||||||
productName={"THE BOY COLLECTION"}
|
productName={'THE BOY COLLECTION'}
|
||||||
preSaleTS={1618690343000}
|
preSaleTS={1618690343000}
|
||||||
image="img/banner1.jpeg"
|
image="img/banner1.jpeg"
|
||||||
/>
|
/>
|
||||||
|
@ -54,28 +60,31 @@ export const HomeView = () => {
|
||||||
<Content style={{ display: 'flex', flexWrap: 'wrap' }}>
|
<Content style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||||
<Col style={{ width: '100%', marginTop: 10 }}>
|
<Col style={{ width: '100%', marginTop: 10 }}>
|
||||||
<Row>
|
<Row>
|
||||||
<Tabs activeKey={activeKey} onTabClick={(key) => setActiveKey(key as AuctionState)}>
|
<Tabs
|
||||||
|
activeKey={activeKey}
|
||||||
|
onTabClick={key => setActiveKey(key as AuctionViewState)}
|
||||||
|
>
|
||||||
<TabPane
|
<TabPane
|
||||||
tab={<span className="tab-title">Live</span>}
|
tab={<span className="tab-title">Live</span>}
|
||||||
key={AuctionState.Live}
|
key={AuctionViewState.Live}
|
||||||
>
|
>
|
||||||
{auctionGrid}
|
{auctionGrid}
|
||||||
</TabPane>
|
</TabPane>
|
||||||
<TabPane
|
<TabPane
|
||||||
tab={<span className="tab-title">Upcoming</span>}
|
tab={<span className="tab-title">Upcoming</span>}
|
||||||
key={AuctionState.Upcoming}
|
key={AuctionViewState.Upcoming}
|
||||||
>
|
>
|
||||||
{auctionGrid}
|
{auctionGrid}
|
||||||
</TabPane>
|
</TabPane>
|
||||||
<TabPane
|
<TabPane
|
||||||
tab={<span className="tab-title">Ended</span>}
|
tab={<span className="tab-title">Ended</span>}
|
||||||
key={AuctionState.Ended}
|
key={AuctionViewState.Ended}
|
||||||
>
|
>
|
||||||
{auctionGrid}
|
{auctionGrid}
|
||||||
</TabPane>
|
</TabPane>
|
||||||
<TabPane
|
<TabPane
|
||||||
tab={<span className="tab-title">Buy Now</span>}
|
tab={<span className="tab-title">Buy Now</span>}
|
||||||
key={AuctionState.BuyNow}
|
key={AuctionViewState.BuyNow}
|
||||||
>
|
>
|
||||||
{auctionGrid}
|
{auctionGrid}
|
||||||
</TabPane>
|
</TabPane>
|
||||||
|
|
Loading…
Reference in New Issue