From b48fe02510325576ab0039e9284861177465fe4a Mon Sep 17 00:00:00 2001 From: Nathaniel Parke Date: Thu, 15 Oct 2020 18:47:53 +0800 Subject: [PATCH] Add open orders page --- src/components/TopBar.tsx | 3 +- ...{OpenOrderTable.jsx => OpenOrderTable.tsx} | 43 +++++++++--- src/pages/OpenOrdersPage.jsx | 10 --- src/pages/OpenOrdersPage.tsx | 45 +++++++++++++ src/utils/markets.tsx | 66 ++----------------- 5 files changed, 87 insertions(+), 80 deletions(-) rename src/components/UserInfoTable/{OpenOrderTable.jsx => OpenOrderTable.tsx} (61%) delete mode 100644 src/pages/OpenOrdersPage.jsx create mode 100644 src/pages/OpenOrdersPage.tsx diff --git a/src/components/TopBar.tsx b/src/components/TopBar.tsx index 4c8ce66..9117313 100644 --- a/src/components/TopBar.tsx +++ b/src/components/TopBar.tsx @@ -135,7 +135,8 @@ export default function TopBar() { }} > TRADE - BALANCES + {connected && BALANCES} + {connected && ORDERS} window.open(EXTERNAL_LINKS['/learn'], '_blank')}> diff --git a/src/components/UserInfoTable/OpenOrderTable.jsx b/src/components/UserInfoTable/OpenOrderTable.tsx similarity index 61% rename from src/components/UserInfoTable/OpenOrderTable.jsx rename to src/components/UserInfoTable/OpenOrderTable.tsx index ca781f7..7f1d65e 100644 --- a/src/components/UserInfoTable/OpenOrderTable.jsx +++ b/src/components/UserInfoTable/OpenOrderTable.tsx @@ -1,20 +1,27 @@ -import React, { useState } from 'react'; +import React, {useState} from 'react'; import DataTable from '../layout/DataTable'; import styled from 'styled-components'; -import { Button, Row, Col, Tag } from 'antd'; -import { cancelOrder } from '../../utils/send'; -import { useWallet } from '../../utils/wallet'; -import { useSendConnection } from '../../utils/connection'; -import { notify } from '../../utils/notifications'; -import { DeleteOutlined } from '@ant-design/icons'; +import {Button, Col, Row, Tag} from 'antd'; +import {cancelOrder} from '../../utils/send'; +import {useWallet} from '../../utils/wallet'; +import {useSendConnection} from '../../utils/connection'; +import {notify} from '../../utils/notifications'; +import {DeleteOutlined} from '@ant-design/icons'; +import {OrderWithMarketAndMarketName} from "../../utils/types"; const CancelButton = styled(Button)` color: #f23b69; border: 1px solid #f23b69; `; -export default function OpenOrderTable({ openOrders, onCancelSuccess }) { +export default function OpenOrderTable({ openOrders, onCancelSuccess, pageSize, loading, marketFilter } : { + openOrders: OrderWithMarketAndMarketName[] | null | undefined; + onCancelSuccess?: () => void; + pageSize?: number; + loading?: boolean; + marketFilter?: boolean; +}) { let { wallet } = useWallet(); let connection = useSendConnection(); @@ -42,11 +49,17 @@ export default function OpenOrderTable({ openOrders, onCancelSuccess }) { onCancelSuccess && onCancelSuccess(); } + const marketFilters = [ + ...new Set((openOrders || []).map(orderInfos => orderInfos.marketName)) + ].map(marketName => {return {text: marketName, value: marketName}}); + const columns = [ { title: 'Market', dataIndex: 'marketName', key: 'marketName', + filters: (marketFilter ? marketFilters : undefined), + onFilter: (value, record) => record.marketName.indexOf(value) === 0, }, { title: 'Side', @@ -60,16 +73,27 @@ export default function OpenOrderTable({ openOrders, onCancelSuccess }) { {side.charAt(0).toUpperCase() + side.slice(1)} ), + sorter: (a, b) => { + if (a.side === b.side) { + return 0. + } else if (a.side === 'buy') { + return 1. + } else { + return -1. + } + }, }, { title: 'Size', dataIndex: 'size', key: 'size', + sorter: (a, b) => b.size - a.size, }, { title: 'Price', dataIndex: 'price', key: 'price', + sorter: (a, b) => b.price - a.price, }, { key: 'orderId', @@ -98,7 +122,8 @@ export default function OpenOrderTable({ openOrders, onCancelSuccess }) { dataSource={dataSource} columns={columns} pagination={true} - pageSize={5} + pageSize={pageSize ? pageSize : 5} + loading={loading !== undefined && loading} /> diff --git a/src/pages/OpenOrdersPage.jsx b/src/pages/OpenOrdersPage.jsx deleted file mode 100644 index 6db2983..0000000 --- a/src/pages/OpenOrdersPage.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import FloatingElement from '../components/layout/FloatingElement'; - -export default function OpenOrdersPage() { - return ( - - {/**/} - - ); -} diff --git a/src/pages/OpenOrdersPage.tsx b/src/pages/OpenOrdersPage.tsx new file mode 100644 index 0000000..d4059a2 --- /dev/null +++ b/src/pages/OpenOrdersPage.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import FloatingElement from '../components/layout/FloatingElement'; +import {getMarketInfos, useAllMarkets, useAllOpenOrders, useMarket} from "../utils/markets"; +import OpenOrderTable from "../components/UserInfoTable/OpenOrderTable"; +import {Button} from "antd"; +import {OrderWithMarketAndMarketName} from "../utils/types"; + +export default function OpenOrdersPage() { + const {openOrders, loaded, refreshOpenOrders} = useAllOpenOrders(); + let {customMarkets} = useMarket(); + let marketInfos = getMarketInfos(customMarkets); + let marketAddressesToNames = Object.fromEntries(marketInfos.map(info => [info.address.toBase58(), info.name])); + let [allMarkets] = useAllMarkets(customMarkets); + const marketsByAddress = Object.fromEntries((allMarkets || []).map( + marketInfo => [marketInfo.market.address.toBase58(), marketInfo.market] + )); + + const dataSource: OrderWithMarketAndMarketName[] = (openOrders || []).map((orderInfos) => + orderInfos.orders.map(order => { + return { + marketName: marketAddressesToNames[orderInfos.marketAddress], + market: marketsByAddress[orderInfos.marketAddress], + ...order + }; + }) + ).flat(); + + return ( + + + + + ); +} diff --git a/src/utils/markets.tsx b/src/utils/markets.tsx index 403f59b..41b7e61 100644 --- a/src/utils/markets.tsx +++ b/src/utils/markets.tsx @@ -30,6 +30,7 @@ import { Trade, } from "./types"; import {WRAPPED_SOL_MINT} from "@project-serum/serum/lib/token-instructions"; +import {Order} from "@project-serum/serum/lib/market"; // Used in debugging, should be false in production const _IGNORE_DEPRECATED = false; @@ -607,65 +608,6 @@ export function useFillsForAllMarkets(limit = 100) { ); } -// TODO: Update to use websocket -export function useOpenOrdersForAllMarketsOld() { - return [[], true] - // const { connected, wallet } = useWallet(); - // - // const connection = useConnection(); - // // todo: use custom markets - // const allMarkets: {market: Market; marketName: string; programId: PublicKey;}[] = useAllMarkets([]); - // - // async function getOpenOrdersForAllMarkets() { - // let orders: OrderWithMarket[] = []; - // if (!connected) { - // return orders; - // } - // - // let marketData: {market: Market; marketName: string; programId: PublicKey;}; - // for (marketData of allMarkets) { - // const { market, marketName } = marketData; - // if (!market) { - // return orders; - // } - // const openOrdersAccounts = await market.findOpenOrdersAccountsForOwner( - // connection, - // wallet.publicKey, - // ); - // const openOrdersAccount = openOrdersAccounts && openOrdersAccounts[0]; - // if (!openOrdersAccount) { - // return orders; - // } - // const [bids, asks] = await Promise.all([ - // market.loadBids(connection), - // market.loadAsks(connection), - // ]); - // const ordersForMarket = [...bids, ...asks] - // .filter((order) => { - // return order.openOrdersAddress.equals(openOrdersAccount.publicKey); - // }) - // .map((order) => { - // return { ...order, marketName }; - // }); - // orders = orders.concat(ordersForMarket); - // } - // - // return orders; - // } - // - // return useAsyncData( - // getOpenOrdersForAllMarkets, - // tuple( - // 'getOpenOrdersForAllMarkets', - // connected, - // connection, - // wallet, - // allMarkets, - // ), - // { refreshInterval: _SLOW_REFRESH_INTERVAL }, - // ); -} - export function useAllOpenOrdersAccounts() { const {wallet, connected} = useWallet(); const connection = useConnection(); @@ -755,7 +697,11 @@ export function useAllOpenOrdersBalances() { return openOrdersBalances } -export function useAllOpenOrders() { +export function useAllOpenOrders(): { + openOrders: { orders: Order[]; marketAddress: string; }[] | null | undefined; + loaded: boolean, + refreshOpenOrders: () => void, +} { const connection = useConnection(); const { connected } = useWallet(); const [openOrdersAccounts, openOrdersAccountsConnected] = useAllOpenOrdersAccounts();