Skip to content

Commit

Permalink
LIQ-727 Auction Bid Activity
Browse files Browse the repository at this point in the history
  • Loading branch information
vanminhtran committed Aug 2, 2022
1 parent 1942263 commit 5575a60
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 17 deletions.
9 changes: 6 additions & 3 deletions core/sdk/src/CandyShopAuctionAPI.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Auction, AuctionBid, ListBase, SingleBase } from '@liqnft/candy-shop-types';
import { Auction, AuctionBid, AuctionBidQuery, ListBase, SingleBase } from '@liqnft/candy-shop-types';
import { AuctionQuery, fetchAuctionBid, fetchAuctionHistoryByAddress, fetchAuctionsByShop } from './factory/backend';
import axiosInstance from './vendor/config';

Expand All @@ -13,6 +13,9 @@ export function fetchAuctionBidByWalletAddress(
return fetchAuctionBid(axiosInstance, auctionAddress, walletAddress);
}

export function fetchAuctionHistory(auctionAddress: string): Promise<ListBase<AuctionBid>> {
return fetchAuctionHistoryByAddress(axiosInstance, auctionAddress);
export function fetchAuctionHistory(
auctionAddress: string,
auctionBidQuery?: AuctionBidQuery
): Promise<ListBase<AuctionBid>> {
return fetchAuctionHistoryByAddress(axiosInstance, auctionAddress, auctionBidQuery);
}
19 changes: 15 additions & 4 deletions core/sdk/src/factory/backend/AuctionAPI.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SingleBase, ListBase, Auction, AuctionBid, AuctionStatus } from '@liqnft/candy-shop-types';
import { SingleBase, ListBase, Auction, AuctionBid, AuctionStatus, AuctionBidQuery } from '@liqnft/candy-shop-types';
import { AxiosInstance } from 'axios';
import qs from 'qs';

Expand Down Expand Up @@ -52,8 +52,19 @@ export function fetchAuction(axiosInstance: AxiosInstance, auctionAddress: strin

export function fetchAuctionHistoryByAddress(
axiosInstance: AxiosInstance,
auctionAddress: string
auctionAddress: string,
auctionBidQuery?: AuctionBidQuery
): Promise<ListBase<AuctionBid>> {
console.log(`${Logger}: fetching Auction bid history by auctionAddress=`, auctionAddress);
return axiosInstance.get(`/auction/history/${auctionAddress}`).then((res) => res.data);
let queryString = '';

if (auctionBidQuery) {
if (auctionBidQuery.orderByArr) {
queryString = qs.stringify({ ...auctionBidQuery, orderByArr: JSON.stringify(auctionBidQuery.orderByArr) });
} else {
queryString = qs.stringify(auctionBidQuery);
}
}

console.log(`${Logger}: fetching Auction bid history by auctionAddress=`, auctionAddress, `query=`, queryString);
return axiosInstance.get(`/auction/history/${auctionAddress}?${queryString}`).then((res) => res.data);
}
4 changes: 4 additions & 0 deletions core/types/src/query/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,7 @@ export interface CollectionQuery extends CommonQuery {
export interface ShopQuery extends CommonQuery {
name?: string;
}

export interface AuctionBidQuery extends CommonQuery {
orderByArr?: SortBy;
}
2 changes: 1 addition & 1 deletion core/ui/src/components/CollectionFilter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ListBase, NftCollection } from '@liqnft/candy-shop-types';
import { Processing } from 'components/Processing';
import { CollectionFilter as CollectionFilterType } from 'model';
import { Search } from 'components/Search';
import { removeDuplicate } from 'utils/array';
import { removeDuplicate } from 'utils/helperFunc';
import { LoadStatus } from 'constant';
import '../../style/order-filter.less';

Expand Down
2 changes: 1 addition & 1 deletion core/ui/src/components/ShopFilter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { LoadStatus } from 'constant';
import { ListBase, CandyShop as CandyShopResponse } from '@liqnft/candy-shop-types';
import { Processing } from 'components/Processing';
import { ShopFilter as ShopFilterInfo } from 'model';
import { removeDuplicate } from 'utils/array';
import { removeDuplicate } from 'utils/helperFunc';

import '../../style/order-filter.less';

Expand Down
1 change: 1 addition & 0 deletions core/ui/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { OrderDetail } from './public/OrderDetail';
export { Sell } from './public/Sell';
export { Stat } from './public/Stat';
export { Activity } from './public/Activity';
export { AuctionActivity } from './public/AuctionActivity';
export * from './public/Auction';
export * from './public/Modal';

Expand Down
7 changes: 2 additions & 5 deletions core/ui/src/public/Activity/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Trade, ListBase, ShopStatusType, SortBy } from '@liqnft/candy-shop-type
import { useValidateStatus } from 'hooks/useValidateStatus';
import { useUpdateSubject } from 'public/Context/CandyShopDataValidator';
import { ActivityActionsStatus } from 'constant';
import { removeDuplicate } from 'utils/array';
import { removeDuplicate, EMPTY_FUNCTION } from 'utils/helperFunc';

import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
Expand All @@ -25,9 +25,6 @@ interface ActivityProps {
}

const LIMIT = 10;
const DO_NOTHING_FUNC = () => {
// this prevent double call api transaction in useEffect and infinity lib
};

const Logger = 'CandyShopUI/Activity';

Expand Down Expand Up @@ -103,7 +100,7 @@ export const Activity: React.FC<ActivityProps> = ({ candyShop, identifiers, orde

<InfiniteScroll
dataLength={trades.length}
next={offset === 0 ? DO_NOTHING_FUNC : getTrades(offset, LIMIT)}
next={offset === 0 ? EMPTY_FUNCTION : getTrades(offset, LIMIT)}
loader={<Processing />}
hasMore={hasMore}
>
Expand Down
98 changes: 98 additions & 0 deletions core/ui/src/public/AuctionActivity/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { useState, useCallback, useEffect } from 'react';

import { ExplorerLink } from 'components/ExplorerLink';
import { Processing } from 'components/Processing';
import InfiniteScroll from 'react-infinite-scroll-component';

import { CandyShop, fetchAuctionHistory } from '@liqnft/candy-shop-sdk';
import { AuctionBid, AuctionStatus, ListBase, ShopStatusType, SortBy } from '@liqnft/candy-shop-types';
import { useUpdateSubject } from 'public/Context/CandyShopDataValidator';
import { removeDuplicate, EMPTY_FUNCTION } from 'utils/helperFunc';

import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);
import './style.less';

interface AuctionActivityProps {
candyShop: CandyShop;
orderBy?: SortBy;
auctionAddress: string;
}

const LIMIT = 10;
const Logger = 'CandyShopUI/AuctionActivity';

export const AuctionActivity: React.FC<AuctionActivityProps> = ({ candyShop, auctionAddress, orderBy }) => {
const [bids, setBids] = useState<AuctionBid[]>([]);
const [hasMore, setHasMore] = useState<boolean>(true);
const [offset, setOffset] = useState<number>(0);

useUpdateSubject({ subject: ShopStatusType.Auction });

const getAuctionBids = useCallback(
(offset: number, limit: number, firstLoad?: boolean) => () => {
fetchAuctionHistory(auctionAddress, { offset, limit, orderByArr: orderBy })
.then((res: ListBase<AuctionBid>) => {
const { result, offset, totalCount, count, success } = res;
if (!success) {
return setHasMore(false);
}
const hasMore = offset + count < Number(totalCount);
if (hasMore) {
setOffset(offset + count + 1);
}

setHasMore(hasMore);
setBids((list) => {
if (firstLoad) return result || [];
return removeDuplicate<AuctionBid>(list, result, 'bidAddress');
});
})
.catch((error: any) => {
console.log(`${Logger}: fetchAuctionsByShopAddress failed, error=`, error);
});
},
[auctionAddress, orderBy]
);

useEffect(() => {
getAuctionBids(0, LIMIT)();
}, [getAuctionBids]);

return (
<div className="candy-activity-auction">
<div className="candy-activity-auction-table-container" id="candy-activity-auction-scroll-target">
<div className="candy-activity-auction-header candy-activity-auction-item">
<span>BUYER ADDRESS</span>
<span>PRICE</span>
<span>STATUS</span>
</div>

<InfiniteScroll
dataLength={bids.length}
next={offset === 0 ? EMPTY_FUNCTION : getAuctionBids(offset, LIMIT)}
loader={<Processing />}
hasMore={hasMore}
>
{bids.map((auction) => {
return (
<div key={auction.bidAddress} className="candy-activity-auction-item">
<div>
<ExplorerLink type="address" address={auction.buyerAddress} />
</div>
<div className="candy-activity-auction-price">
{`${(Number(auction.price) / candyShop.baseUnitsPerCurrency).toLocaleString(undefined, {
minimumFractionDigits: candyShop.priceDecimalsMin,
maximumFractionDigits: candyShop.priceDecimals
})} ${candyShop.currencySymbol}`}
</div>
<div>{AuctionStatus[auction.status]}</div>
</div>
);
})}
</InfiniteScroll>
</div>
</div>
);
};
63 changes: 63 additions & 0 deletions core/ui/src/public/AuctionActivity/style.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
@import '../../variable.less';

.candy-activity-auction {
padding: 20px 50px;
font-size: 16px;

@media @desktopS {
padding: 20px 15px;
}
.infinite-scroll-component {
overflow: unset !important;
}

.candy-activity-auction-item {
display: grid;
text-align: left;
align-items: center;

grid-template-columns: minmax(300px, 1fr) 1fr 200px;
> * {
padding: 8px 12px;
border-bottom: 1px solid @gray-light;
min-height: 67px;
display: flex;
align-items: center;
}

@media @desktopL {
grid-template-columns: minmax(300px, 1fr) 1fr 200px;
}

img {
width: 50px;
height: 50px;
background-color: @gray-light;
object-fit: cover;
margin-right: 20px;
}
}

.candy-activity-auction-header {
span {
border-bottom: 2px solid @gray-medium;
font-size: 14px;
color: #757575;
font-weight: 700;
text-align: left;
min-height: unset;
}
}

.candy-activity-auction-table-container {
overflow: auto;

.candy-activity-auction-price {
white-space: nowrap;
}
}

.candy-processing {
margin: 60px auto;
}
}
2 changes: 1 addition & 1 deletion core/ui/src/public/Orders/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { ShopFilter as ShopFilterComponent } from 'components/ShopFilter';
import { useValidateStatus } from 'hooks/useValidateStatus';
import { useUpdateSubject } from 'public/Context/CandyShopDataValidator';
import { CollectionFilter, ShopFilter, OrderDefaultFilter } from 'model';
import { removeDuplicate } from 'utils/array';
import { removeDuplicate } from 'utils/helperFunc';
import { OrdersActionsStatus } from 'constant';
import { ORDER_FETCH_LIMIT, SORT_OPTIONS } from 'constant/Orders';
import './index.less';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ export function removeDuplicate<T>(oldList: T[], addList: T[], key: keyof T): T[
}
return newList;
}

export function EMPTY_FUNCTION(): void {
//
}
13 changes: 11 additions & 2 deletions example/AuctionExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { WalletMultiButton } from '@solana/wallet-adapter-ant-design';
import { useAnchorWallet } from '@solana/wallet-adapter-react';

import { CandyShop, SingleTokenInfo } from '../core/sdk/.';
import { CreateAuction, Auctions } from '../core/ui/.';
import { AuctionStatus } from '../core/types/.';
import { CreateAuction, Auctions, AuctionActivity } from '../core/ui/.';
import { AuctionStatus, SortBy } from '../core/types/.';

import 'antd/dist/antd.min.css';

Expand Down Expand Up @@ -38,8 +38,17 @@ export const AuctionExample: React.FC<AuctionExampleProps> = ({ candyShop }) =>
walletConnectComponent={<WalletMultiButton />}
statusFilters={AUCTION_FILTER}
/>

<h1 style={{ marginTop: 40, marginBottom: 40 }}>Auction Activities</h1>
<AuctionActivity
candyShop={candyShop}
auctionAddress="91cr87Pib1ue3obYrZnDmzsa4KAok6UvRFi2F2c6LxQa"
orderBy={AUCTION_ORDER}
/>
</div>
);
};

const AUCTION_ORDER: SortBy = { column: 'price', order: 'desc' };

const AUCTION_FILTER = [AuctionStatus.CREATED, AuctionStatus.STARTED, AuctionStatus.EXPIRED, AuctionStatus.COMPLETE];

0 comments on commit 5575a60

Please sign in to comment.