From 4d33a83ceda9fdf4fece0a22c60cf7ee3e3a702b Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Mon, 16 Feb 2026 23:57:55 +0300 Subject: [PATCH 01/12] update: update get-user-orders fetch interface --- .../get-user-orders/GetUserOrdersData.ts | 23 +++++++++++++++++++ .../responses/orders/GetUserOrdersRes.ts | 1 + src/utils/methods.ts | 22 ++++++++++++++++-- 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/interfaces/fetch-data/get-user-orders/GetUserOrdersData.ts diff --git a/src/interfaces/fetch-data/get-user-orders/GetUserOrdersData.ts b/src/interfaces/fetch-data/get-user-orders/GetUserOrdersData.ts new file mode 100644 index 0000000..e8fa4f8 --- /dev/null +++ b/src/interfaces/fetch-data/get-user-orders/GetUserOrdersData.ts @@ -0,0 +1,23 @@ +export enum GetUserOrdersBodyStatus { + ACTIVE = 'active', + FINISHED = 'finished', +} + +export enum GetUserOrdersBodyType { + BUY = 'buy', + SELL = 'sell', +} + +export type GetUserOrdersData = { + limit: number; + offset: number; + filterInfo: { + status?: GetUserOrdersBodyStatus; + type?: GetUserOrdersBodyType; + date?: { + // UNIX timestamps in milliseconds + from: number; + to: number; + }; + }; +}; diff --git a/src/interfaces/responses/orders/GetUserOrdersRes.ts b/src/interfaces/responses/orders/GetUserOrdersRes.ts index 4ac61ac..fca3f67 100644 --- a/src/interfaces/responses/orders/GetUserOrdersRes.ts +++ b/src/interfaces/responses/orders/GetUserOrdersRes.ts @@ -19,6 +19,7 @@ interface UserOrderData { interface GetUserOrdersRes { success: true; + totalItemsCount: number; data: UserOrderData[]; } diff --git a/src/utils/methods.ts b/src/utils/methods.ts index 531fe08..ff26583 100644 --- a/src/utils/methods.ts +++ b/src/utils/methods.ts @@ -25,6 +25,7 @@ import axios from 'axios'; import GetPairsPagesAmountRes from '@/interfaces/responses/dex/GetPairsPagesAmountRes'; import { PairSortOption } from '@/interfaces/enum/pair'; import { API_URL } from '@/constants'; +import { GetUserOrdersData } from '@/interfaces/fetch-data/get-user-orders/GetUserOrdersData'; const isServer = typeof window === 'undefined'; const baseUrl = isServer ? API_URL : ''; @@ -246,10 +247,27 @@ export async function getUserOrdersPage(pairId: string): Promise res.data); } -export async function getUserOrders(): Promise { +export async function getUserOrders({ + limit, + offset, + filterInfo: { status, type, date }, +}: GetUserOrdersData): Promise { return axios - .post('/api/orders/get', { + .patch('/api/orders/get', { token: sessionStorage.getItem('token'), + + limit, + offset, + filterInfo: { + status, + type, + date: date + ? { + from: date.from, + to: date.to, + } + : undefined, + }, }) .then((res) => res.data); } From c0e6fa930876c262e06fae9c73c0055c22596a50 Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Tue, 17 Feb 2026 00:24:13 +0300 Subject: [PATCH 02/12] add: add get-user-orders-all-pairs endpoint method --- .../orders/GetUserOrdersAllPairsRes.ts | 18 ++++++++++++++++++ src/utils/methods.ts | 9 +++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/interfaces/responses/orders/GetUserOrdersAllPairsRes.ts diff --git a/src/interfaces/responses/orders/GetUserOrdersAllPairsRes.ts b/src/interfaces/responses/orders/GetUserOrdersAllPairsRes.ts new file mode 100644 index 0000000..65c8b29 --- /dev/null +++ b/src/interfaces/responses/orders/GetUserOrdersAllPairsRes.ts @@ -0,0 +1,18 @@ +export type GetUserOrdersAllPairsResPair = { + id: number; + firstCurrency: { + id: number; + ticker: string | null; + }; + secondCurrency: { + id: number; + ticker: string | null; + }; +}; + +type GetUserOrdersAllPairsRes = { + success: true; + data: GetUserOrdersAllPairsResPair[]; +}; + +export default GetUserOrdersAllPairsRes; diff --git a/src/utils/methods.ts b/src/utils/methods.ts index ff26583..01aa03b 100644 --- a/src/utils/methods.ts +++ b/src/utils/methods.ts @@ -26,6 +26,7 @@ import GetPairsPagesAmountRes from '@/interfaces/responses/dex/GetPairsPagesAmou import { PairSortOption } from '@/interfaces/enum/pair'; import { API_URL } from '@/constants'; import { GetUserOrdersData } from '@/interfaces/fetch-data/get-user-orders/GetUserOrdersData'; +import GetUserOrdersAllPairsRes from '@/interfaces/responses/orders/GetUserOrdersAllPairsRes'; const isServer = typeof window === 'undefined'; const baseUrl = isServer ? API_URL : ''; @@ -272,6 +273,14 @@ export async function getUserOrders({ .then((res) => res.data); } +export async function getUserOrdersAllPairs(): Promise { + return axios + .patch('/api/orders/get-user-orders-pairs', { + token: sessionStorage.getItem('token'), + }) + .then((res) => res.data); +} + export async function cancelOrder(id: string): Promise { return axios .post('/api/orders/cancel', { From a7ec28fa0b3b7c539bfefef23ab3e72c4830bc25 Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Tue, 17 Feb 2026 02:48:53 +0300 Subject: [PATCH 03/12] wip: add paginated get-user-orders basic usage --- src/pages/dex/orders/index.tsx | 114 +++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 48 deletions(-) diff --git a/src/pages/dex/orders/index.tsx b/src/pages/dex/orders/index.tsx index 66b44bd..ec7d990 100644 --- a/src/pages/dex/orders/index.tsx +++ b/src/pages/dex/orders/index.tsx @@ -6,7 +6,7 @@ import { useEffect, useState } from 'react'; import Dropdown from '@/components/UI/Dropdown/Dropdown'; import DateRangeSelector from '@/components/UI/DateRangeSelector/DateRangeSelector'; import Button from '@/components/UI/Button/Button'; -import { cancelOrder, getUserOrders } from '@/utils/methods'; +import * as fetchMethods from '@/utils/methods'; import Alert from '@/components/UI/Alert/Alert'; import AlertType from '@/interfaces/common/AlertType'; import { UserOrderData } from '@/interfaces/responses/orders/GetUserOrdersRes'; @@ -14,8 +14,12 @@ import PairValue from '@/interfaces/props/pages/dex/orders/PairValue'; import DateState from '@/interfaces/common/DateState'; import useUpdateUser from '@/hook/useUpdateUser'; import { Footer } from '@/zano_ui/src'; +import { GetUserOrdersBodyStatus } from '@/interfaces/fetch-data/get-user-orders/GetUserOrdersData'; +import Decimal from 'decimal.js'; import OrdersTable from './OrdersTable/OrdersTable'; +const ORDERS_PER_PAGE = 10; + function Orders() { const fetchUser = useUpdateUser(); @@ -42,6 +46,8 @@ function Orders() { }, ]; + const [initialized, setInitialized] = useState(false); + const [pairsValues, setPairsValues] = useState([{ name: 'All pairs', code: '' }]); const [pairDropdownValue, setPairDropdownState] = useState(pairsValues[0]); @@ -62,61 +68,73 @@ function Orders() { const [orders, setOrders] = useState([]); useEffect(() => { - async function getOrders() { - setAlertState('loading'); - setAlertSubtitle('Loading orders data...'); + async function initPairsDropdown() { + try { + const getUserOrdersAllPairsRes = await fetchMethods.getUserOrdersAllPairs(); - const result = await getUserOrders(); + if (!getUserOrdersAllPairsRes.success) { + throw new Error('Error fetching pairs for orders'); + } + + const ordersPairs = getUserOrdersAllPairsRes.data; + + const statePairs = ordersPairs.map((e) => ({ + name: `${e.firstCurrency.ticker}/${e.secondCurrency.ticker}`, + code: new Decimal(e.id).toFixed(), + })); + + setPairsValues([{ name: 'All pairs', code: '' }, ...statePairs]); + } catch (error) { + console.error('Error while initPairsDropdown:', error); + } + } + + async function initOrders() { + const getUserOrdersRes = await fetchMethods.getUserOrders({ + limit: ORDERS_PER_PAGE, + offset: 0, + filterInfo: { + status: GetUserOrdersBodyStatus.ACTIVE, + }, + }); + + if (!getUserOrdersRes.success) { + throw new Error('Error fetching user orders'); + } + + setOrders(getUserOrdersRes.data); + return getUserOrdersRes.data; + } + + async function initialize() { + try { + setAlertState('loading'); + setAlertSubtitle('Loading orders data...'); + + // Simulate loading time + await new Promise((resolve) => setTimeout(resolve, 1000)); + + await fetchUser(); + + await initPairsDropdown(); + + await initOrders(); + + setInitialized(true); + setAlertState(null); + setAlertSubtitle(''); + } catch (error) { + console.error('Error during initialization:', error); - if (!result.success) { setAlertState('error'); setAlertSubtitle('Error loading orders data'); await new Promise((resolve) => setTimeout(resolve, 2000)); setAlertState(null); setAlertSubtitle(''); - return; - } - - fetchUser(); - - setOrders(result.data); - - function getPairsFromOrders(orders: UserOrderData[]) { - const pairs = [ - { - code: '', - name: 'All pairs', - }, - ]; - - for (let i = 0; i < orders.length; i++) { - const pair = { - name: `${orders[i].first_currency.name}/${orders[i].second_currency.name}`, - code: orders[i].pair_id, - }; - - if (!pairs.find((e) => e.code === pair.code)) pairs.push(pair); - } - - return pairs; - } - - const pairs = getPairsFromOrders(result.data); - - setPairsValues(pairs); - setPairDropdownState(pairs[0]); - - setAlertState(null); - setAlertSubtitle(''); - - const { success, data } = await getUserOrders(); - - if (success) { - setOrders(data); } } - getOrders(); + initialize(); }, []); function buySellFilter(e: UserOrderData) { @@ -174,7 +192,7 @@ function Orders() { const results = await (async () => { const res = []; for (const order of activeOrders) { - res.push(await cancelOrder(order.id).catch(() => null)); + res.push(await fetchMethods.cancelOrder(order.id).catch(() => null)); } return res; })(); @@ -192,7 +210,7 @@ function Orders() { setAlertSubtitle(''); }, 2000); - const { success, data } = await getUserOrders(); + const { success, data } = await fetchMethods.getUserOrders(); if (success) { setOrders(data); From abb9e0a47688a62e1f8c4a3480c3b8dc1361d5aa Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Tue, 17 Feb 2026 03:36:47 +0300 Subject: [PATCH 04/12] wip: add user orders page useInView and preloader --- src/pages/dex/orders/index.tsx | 13 +++++++++++++ src/styles/Orders.module.scss | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/src/pages/dex/orders/index.tsx b/src/pages/dex/orders/index.tsx index ec7d990..5afaa02 100644 --- a/src/pages/dex/orders/index.tsx +++ b/src/pages/dex/orders/index.tsx @@ -16,6 +16,8 @@ import useUpdateUser from '@/hook/useUpdateUser'; import { Footer } from '@/zano_ui/src'; import { GetUserOrdersBodyStatus } from '@/interfaces/fetch-data/get-user-orders/GetUserOrdersData'; import Decimal from 'decimal.js'; +import { useInView } from 'react-intersection-observer'; +import Preloader from '@/components/UI/Preloader/Preloader'; import OrdersTable from './OrdersTable/OrdersTable'; const ORDERS_PER_PAGE = 10; @@ -23,6 +25,13 @@ const ORDERS_PER_PAGE = 10; function Orders() { const fetchUser = useUpdateUser(); + const { ref: inViewRef } = useInView({ + threshold: 0, + onChange: (inView) => { + console.log('In view:', inView); + }, + }); + const ordersCategories = [ { name: 'Active orders', @@ -278,6 +287,10 @@ function Orders() { setOrders={setOrders} category={categoryState.code} /> + +
+ +
{alertState && ( Date: Tue, 17 Feb 2026 11:05:59 +0300 Subject: [PATCH 05/12] update: update trading page history to use updated getUserOrders endpoint --- src/components/dex/UserOrders/index.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/dex/UserOrders/index.tsx b/src/components/dex/UserOrders/index.tsx index 89e1a9b..b454f4e 100644 --- a/src/components/dex/UserOrders/index.tsx +++ b/src/components/dex/UserOrders/index.tsx @@ -16,6 +16,7 @@ import { countByKeyRecord, createOrderSorter } from '@/utils/utils'; import ApplyTip from '@/interfaces/common/ApplyTip'; import { useQuerySyncedTab } from '@/hook/useQuerySyncedTab'; import { useMediaQuery } from '@/hook/useMediaQuery'; +import { GetUserOrdersBodyStatus } from '@/interfaces/fetch-data/get-user-orders/GetUserOrdersData'; import { UserOrdersProps } from './types'; import styles from './styles.module.scss'; import { @@ -73,7 +74,7 @@ const UserOrders = ({ length: offers.length, }, { - title: 'History', + title: 'History - Last 100 Items', type: 'history', length: ordersHistory.length, }, @@ -105,7 +106,13 @@ const UserOrders = ({ })(); (async () => { - const result = await getUserOrders(); + const result = await getUserOrders({ + limit: 100, + offset: 0, + filterInfo: { + status: GetUserOrdersBodyStatus.FINISHED, + }, + }); if (!result.success) { setAlertState('error'); @@ -116,9 +123,7 @@ const UserOrders = ({ return; } - const filteredOrdersHistory = result.data - .filter((s) => s.pair_id === pairData?.id) - .filter((s) => s.status === 'finished'); + const filteredOrdersHistory = result.data.filter((s) => s.status === 'finished'); fetchUser(); From daecf49bc0d652cfbbc6edc86e9cb71484d8ab18 Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Tue, 17 Feb 2026 23:05:45 +0300 Subject: [PATCH 06/12] wip: add My Orders fetching multiple pages & filtering --- .../get-user-orders/GetUserOrdersData.ts | 1 + src/pages/dex/orders/index.tsx | 301 ++++++++++++------ 2 files changed, 196 insertions(+), 106 deletions(-) diff --git a/src/interfaces/fetch-data/get-user-orders/GetUserOrdersData.ts b/src/interfaces/fetch-data/get-user-orders/GetUserOrdersData.ts index e8fa4f8..ad917db 100644 --- a/src/interfaces/fetch-data/get-user-orders/GetUserOrdersData.ts +++ b/src/interfaces/fetch-data/get-user-orders/GetUserOrdersData.ts @@ -12,6 +12,7 @@ export type GetUserOrdersData = { limit: number; offset: number; filterInfo: { + pairId?: number; status?: GetUserOrdersBodyStatus; type?: GetUserOrdersBodyType; date?: { diff --git a/src/pages/dex/orders/index.tsx b/src/pages/dex/orders/index.tsx index 5afaa02..71b9fab 100644 --- a/src/pages/dex/orders/index.tsx +++ b/src/pages/dex/orders/index.tsx @@ -14,7 +14,10 @@ import PairValue from '@/interfaces/props/pages/dex/orders/PairValue'; import DateState from '@/interfaces/common/DateState'; import useUpdateUser from '@/hook/useUpdateUser'; import { Footer } from '@/zano_ui/src'; -import { GetUserOrdersBodyStatus } from '@/interfaces/fetch-data/get-user-orders/GetUserOrdersData'; +import { + GetUserOrdersBodyStatus, + GetUserOrdersBodyType, +} from '@/interfaces/fetch-data/get-user-orders/GetUserOrdersData'; import Decimal from 'decimal.js'; import { useInView } from 'react-intersection-observer'; import Preloader from '@/components/UI/Preloader/Preloader'; @@ -25,13 +28,6 @@ const ORDERS_PER_PAGE = 10; function Orders() { const fetchUser = useUpdateUser(); - const { ref: inViewRef } = useInView({ - threshold: 0, - onChange: (inView) => { - console.log('In view:', inView); - }, - }); - const ordersCategories = [ { name: 'Active orders', @@ -75,117 +71,214 @@ function Orders() { }); const [orders, setOrders] = useState([]); + const [lastOrderOffset, setLastOrderOffset] = useState(0); + const [totalOrdersCount, setTotalOrdersCount] = useState(undefined); + const [orderPageLoading, setOrderPageLoading] = useState(false); - useEffect(() => { - async function initPairsDropdown() { - try { - const getUserOrdersAllPairsRes = await fetchMethods.getUserOrdersAllPairs(); + function deriveFiltersFromState() { + const status = + categoryState.code === 'active-orders' + ? GetUserOrdersBodyStatus.ACTIVE + : GetUserOrdersBodyStatus.FINISHED; - if (!getUserOrdersAllPairsRes.success) { - throw new Error('Error fetching pairs for orders'); - } - - const ordersPairs = getUserOrdersAllPairsRes.data; - - const statePairs = ordersPairs.map((e) => ({ - name: `${e.firstCurrency.ticker}/${e.secondCurrency.ticker}`, - code: new Decimal(e.id).toFixed(), - })); - - setPairsValues([{ name: 'All pairs', code: '' }, ...statePairs]); - } catch (error) { - console.error('Error while initPairsDropdown:', error); - } - } - - async function initOrders() { - const getUserOrdersRes = await fetchMethods.getUserOrders({ - limit: ORDERS_PER_PAGE, - offset: 0, - filterInfo: { - status: GetUserOrdersBodyStatus.ACTIVE, - }, - }); - - if (!getUserOrdersRes.success) { - throw new Error('Error fetching user orders'); + const type = (() => { + if (buyDropdownValue.name === 'Buy & Sell') { + return undefined; } - setOrders(getUserOrdersRes.data); - return getUserOrdersRes.data; + return buyDropdownValue.name === 'Buy' + ? GetUserOrdersBodyType.BUY + : GetUserOrdersBodyType.SELL; + })(); + + const pairId = + pairDropdownValue.code === '' + ? undefined + : new Decimal(pairDropdownValue.code).toNumber(); + + const date = (() => { + if (!dateRange.first || !dateRange.last) return undefined; + + const firstDate = new Date(dateRange.first); + const lastDate = new Date(dateRange.last); + + firstDate.setHours(0, 0, 0, 0); + lastDate.setHours(23, 59, 59, 999); + + return { + from: firstDate.getTime(), + to: lastDate.getTime(), + }; + })(); + + return { + status, + type, + pairId, + date, + }; + } + + async function addNewOrdersPage() { + const { status, type, pairId, date } = deriveFiltersFromState(); + + const getUserOrdersRes = await fetchMethods.getUserOrders({ + limit: ORDERS_PER_PAGE, + offset: lastOrderOffset, + filterInfo: { + status, + type, + pairId, + date, + }, + }); + + if (!getUserOrdersRes.success) { + throw new Error('Error fetching user orders'); } - async function initialize() { + const newOrders = getUserOrdersRes.data; + const newOrdersAmount = newOrders.length; + + setOrders((prev) => [...prev, ...newOrders]); + setLastOrderOffset((prev) => prev + newOrdersAmount); + setTotalOrdersCount(getUserOrdersRes.totalItemsCount); + } + + const { ref: inViewRef } = useInView({ + threshold: 0, + onChange: async (inView) => { + if (!inView || !initialized) { + return; + } + + if (totalOrdersCount !== undefined && lastOrderOffset >= totalOrdersCount) { + return; + } + + if (orderPageLoading) { + return; + } + + setOrderPageLoading(true); + try { - setAlertState('loading'); - setAlertSubtitle('Loading orders data...'); - - // Simulate loading time - await new Promise((resolve) => setTimeout(resolve, 1000)); - - await fetchUser(); - - await initPairsDropdown(); - - await initOrders(); - - setInitialized(true); - setAlertState(null); - setAlertSubtitle(''); + await addNewOrdersPage(); } catch (error) { - console.error('Error during initialization:', error); + console.error('Error fetching new orders page:', error); setAlertState('error'); - setAlertSubtitle('Error loading orders data'); + setAlertSubtitle('Error loading more orders'); + await new Promise((resolve) => setTimeout(resolve, 2000)); + setAlertState(null); setAlertSubtitle(''); + } finally { + setOrderPageLoading(false); } + }, + }); + + async function initPairsDropdown() { + try { + const getUserOrdersAllPairsRes = await fetchMethods.getUserOrdersAllPairs(); + + if (!getUserOrdersAllPairsRes.success) { + throw new Error('Error fetching pairs for orders'); + } + + const ordersPairs = getUserOrdersAllPairsRes.data; + + const statePairs = ordersPairs.map((e) => ({ + name: `${e.firstCurrency.ticker}/${e.secondCurrency.ticker}`, + code: new Decimal(e.id).toFixed(), + })); + + setPairsValues([{ name: 'All pairs', code: '' }, ...statePairs]); + } catch (error) { + console.error('Error while initPairsDropdown:', error); + } + } + + async function initOrders() { + const { status, type, pairId, date } = deriveFiltersFromState(); + + const getUserOrdersRes = await fetchMethods.getUserOrders({ + limit: ORDERS_PER_PAGE, + offset: 0, + filterInfo: { + status, + type, + pairId, + date, + }, + }); + + if (!getUserOrdersRes.success) { + throw new Error('Error fetching user orders'); } + const newOrders = getUserOrdersRes.data; + const newOrdersAmount = newOrders.length; + + setOrders(newOrders); + setLastOrderOffset(newOrdersAmount); + setTotalOrdersCount(getUserOrdersRes.totalItemsCount); + + return newOrders; + } + + async function initialize() { + try { + setAlertState('loading'); + setAlertSubtitle('Loading orders data...'); + + setOrders([]); + setLastOrderOffset(0); + setTotalOrdersCount(undefined); + + // Simulate loading time + await new Promise((resolve) => setTimeout(resolve, 1000)); + + await fetchUser(); + + await initPairsDropdown(); + + await initOrders(); + + setInitialized(true); + setAlertState(null); + setAlertSubtitle(''); + } catch (error) { + console.error('Error during initialization:', error); + + setAlertState('error'); + setAlertSubtitle('Error loading orders data'); + await new Promise((resolve) => setTimeout(resolve, 2000)); + setAlertState(null); + setAlertSubtitle(''); + } + } + + useEffect(() => { + async function onFilterChange() { + if (!initialized) { + return; + } + + await initialize(); + } + + onFilterChange(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [buyDropdownValue, pairDropdownValue, dateRange, categoryState]); + + useEffect(() => { initialize(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - function buySellFilter(e: UserOrderData) { - if (buyDropdownValue.name === 'Buy & Sell') return true; - - if (buyDropdownValue.name === 'Buy') return e.type === 'buy'; - - if (buyDropdownValue.name === 'Sell') return e.type === 'sell'; - } - - function pairFilter(e: UserOrderData) { - if (!pairDropdownValue) return true; - - return !pairDropdownValue.code || e.pair_id === pairDropdownValue.code; - } - - function dateFilter(e: UserOrderData) { - if (!dateRange.first || !dateRange.last) return true; - const firstDate = new Date(dateRange.first); - const lastDate = new Date(dateRange.last); - - const timestamp = parseInt(e.timestamp, 10); - - firstDate.setHours(0, 0, 0, 0); - lastDate.setHours(24, 0, 0, 0); - - if (!dateRange.first && !dateRange.last) return true; - - if (dateRange.first && !dateRange.last) return timestamp >= firstDate.getTime(); - - if (!dateRange.first && dateRange.last) return timestamp <= lastDate.getTime(); - - return timestamp >= firstDate.getTime() && timestamp <= lastDate.getTime(); - } - - function categoryFilter(e: UserOrderData) { - if (categoryState.code === 'active-orders') { - return e.status === 'active'; - } - return e.status === 'finished'; - } - const activeOrders = orders.filter((e) => e.status === 'active'); async function cancelAllOrders() { @@ -277,11 +370,7 @@ function Orders() {
- + {orderPageLoading && }
{alertState && ( From 09750ccdaa1f6aa1607c76bdbb75cc65e37b8bb3 Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Wed, 18 Feb 2026 00:32:43 +0300 Subject: [PATCH 07/12] wip: update My Orders order delete --- .../orders/OrdersTable/OrdersTableProps.ts | 6 +--- .../dex/orders/OrdersTable/OrdersTable.tsx | 30 ++-------------- src/pages/dex/orders/index.tsx | 35 +++++++++++++++++-- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/interfaces/props/pages/dex/orders/OrdersTable/OrdersTableProps.ts b/src/interfaces/props/pages/dex/orders/OrdersTable/OrdersTableProps.ts index 203e7d7..d48f40a 100644 --- a/src/interfaces/props/pages/dex/orders/OrdersTable/OrdersTableProps.ts +++ b/src/interfaces/props/pages/dex/orders/OrdersTable/OrdersTableProps.ts @@ -1,13 +1,9 @@ -import AlertType from '@/interfaces/common/AlertType'; import { UserOrderData } from '@/interfaces/responses/orders/GetUserOrdersRes'; -import { Dispatch, SetStateAction } from 'react'; interface OrdersTableProps { value: UserOrderData[]; category: string; - setAlertState: Dispatch>; - setAlertSubtitle: Dispatch>; - setOrders: Dispatch>; + deleteOrder: (orderId: string) => Promise; } export default OrdersTableProps; diff --git a/src/pages/dex/orders/OrdersTable/OrdersTable.tsx b/src/pages/dex/orders/OrdersTable/OrdersTable.tsx index dda4b21..dee1ef8 100644 --- a/src/pages/dex/orders/OrdersTable/OrdersTable.tsx +++ b/src/pages/dex/orders/OrdersTable/OrdersTable.tsx @@ -4,7 +4,6 @@ import DeleteIcon from '@/assets/images/UI/delete.svg'; import NoOffersIcon from '@/assets/images/UI/no_offers.svg'; import EmptyLink from '@/components/UI/EmptyLink/EmptyLink'; import { notationToString, toStandardDateString } from '@/utils/utils'; -import { cancelOrder, getUserOrders } from '@/utils/methods'; import OrdersTableProps from '@/interfaces/props/pages/dex/orders/OrdersTable/OrdersTableProps'; import { UserOrderData } from '@/interfaces/responses/orders/GetUserOrdersRes'; import Decimal from 'decimal.js'; @@ -15,7 +14,7 @@ import styles from './OrdersTable.module.scss'; function OrdersTable(props: OrdersTableProps) { const orders = props.value || []; - const { setAlertState, setAlertSubtitle, setOrders, category } = props; + const { deleteOrder, category } = props; const isActive = category === 'active-orders'; @@ -27,31 +26,6 @@ function OrdersTable(props: OrdersTableProps) { const timestampDate = new Date(parseInt(orderData.timestamp, 10)); - async function deleteOrder() { - setAlertState('loading'); - setAlertSubtitle('Canceling order...'); - const result = await cancelOrder(orderData.id); - - if (result.success) { - setAlertState('success'); - setAlertSubtitle('Order canceled'); - } else { - setAlertState('error'); - setAlertSubtitle('Error canceling order'); - } - - setTimeout(() => { - setAlertState(null); - setAlertSubtitle(''); - }, 2000); - - const { success, data } = await getUserOrders(); - - if (success) { - setOrders(data); - } - } - const amount = ( isActive ? new Decimal(orderData.amount) @@ -150,7 +124,7 @@ function OrdersTable(props: OrdersTableProps) { diff --git a/src/pages/dex/orders/index.tsx b/src/pages/dex/orders/index.tsx index 71b9fab..4f0c85b 100644 --- a/src/pages/dex/orders/index.tsx +++ b/src/pages/dex/orders/index.tsx @@ -281,6 +281,37 @@ function Orders() { const activeOrders = orders.filter((e) => e.status === 'active'); + async function deleteOrder(orderId: string) { + setAlertState('loading'); + setAlertSubtitle('Canceling order...'); + + const result = await fetchMethods.cancelOrder(orderId); + + if (!result.success) { + setAlertState('error'); + setAlertSubtitle('Error canceling order'); + + setTimeout(() => { + setAlertState(null); + setAlertSubtitle(''); + }, 2000); + + return; + } + + setAlertState('success'); + setAlertSubtitle('Order canceled'); + + setTimeout(() => { + setAlertState(null); + setAlertSubtitle(''); + }, 2000); + + setOrders((prev) => prev.filter((e) => e.id !== orderId)); + setLastOrderOffset((prev) => Math.max(prev - 1, 0)); + setTotalOrdersCount((prev) => (prev !== undefined ? prev - 1 : prev)); + } + async function cancelAllOrders() { setAlertState('loading'); setAlertSubtitle('Canceling all orders...'); @@ -371,10 +402,8 @@ function Orders() {
From 5fdfe59737fa30b710fdfa31e1f76234d03fa494 Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Wed, 18 Feb 2026 03:16:32 +0300 Subject: [PATCH 08/12] wip: add Cancel All endpoint usage --- .../cancel-all-orders/CancelAllData.ts | 16 ++ .../responses/orders/CancelAllRes.ts | 5 + src/pages/dex/orders/index.tsx | 144 +++++++++++------- src/utils/methods.ts | 22 +++ 4 files changed, 136 insertions(+), 51 deletions(-) create mode 100644 src/interfaces/fetch-data/cancel-all-orders/CancelAllData.ts create mode 100644 src/interfaces/responses/orders/CancelAllRes.ts diff --git a/src/interfaces/fetch-data/cancel-all-orders/CancelAllData.ts b/src/interfaces/fetch-data/cancel-all-orders/CancelAllData.ts new file mode 100644 index 0000000..dfacd38 --- /dev/null +++ b/src/interfaces/fetch-data/cancel-all-orders/CancelAllData.ts @@ -0,0 +1,16 @@ +export enum CancelAllBodyOrderType { + BUY = 'buy', + SELL = 'sell', +} + +export type CancelAllData = { + filterInfo: { + pairId?: number; + type?: CancelAllBodyOrderType; + date?: { + // UNIX timestamps in milliseconds + from: number; + to: number; + }; + }; +}; diff --git a/src/interfaces/responses/orders/CancelAllRes.ts b/src/interfaces/responses/orders/CancelAllRes.ts new file mode 100644 index 0000000..073718d --- /dev/null +++ b/src/interfaces/responses/orders/CancelAllRes.ts @@ -0,0 +1,5 @@ +interface CancelAllRes { + success: true; +} + +export default CancelAllRes; diff --git a/src/pages/dex/orders/index.tsx b/src/pages/dex/orders/index.tsx index 4f0c85b..b2ac204 100644 --- a/src/pages/dex/orders/index.tsx +++ b/src/pages/dex/orders/index.tsx @@ -21,6 +21,7 @@ import { import Decimal from 'decimal.js'; import { useInView } from 'react-intersection-observer'; import Preloader from '@/components/UI/Preloader/Preloader'; +import { CancelAllBodyOrderType } from '@/interfaces/fetch-data/cancel-all-orders/CancelAllData'; import OrdersTable from './OrdersTable/OrdersTable'; const ORDERS_PER_PAGE = 10; @@ -75,7 +76,7 @@ function Orders() { const [totalOrdersCount, setTotalOrdersCount] = useState(undefined); const [orderPageLoading, setOrderPageLoading] = useState(false); - function deriveFiltersFromState() { + function deriveGetUserOrdersFiltersFromState() { const status = categoryState.code === 'active-orders' ? GetUserOrdersBodyStatus.ACTIVE @@ -119,8 +120,46 @@ function Orders() { }; } + function deriveCancelAllOrdersFiltersFromState() { + const type = (() => { + if (buyDropdownValue.name === 'Buy & Sell') { + return undefined; + } + + return buyDropdownValue.name === 'Buy' + ? CancelAllBodyOrderType.BUY + : CancelAllBodyOrderType.SELL; + })(); + + const pairId = + pairDropdownValue.code === '' + ? undefined + : new Decimal(pairDropdownValue.code).toNumber(); + + const date = (() => { + if (!dateRange.first || !dateRange.last) return undefined; + + const firstDate = new Date(dateRange.first); + const lastDate = new Date(dateRange.last); + + firstDate.setHours(0, 0, 0, 0); + lastDate.setHours(23, 59, 59, 999); + + return { + from: firstDate.getTime(), + to: lastDate.getTime(), + }; + })(); + + return { + type, + pairId, + date, + }; + } + async function addNewOrdersPage() { - const { status, type, pairId, date } = deriveFiltersFromState(); + const { status, type, pairId, date } = deriveGetUserOrdersFiltersFromState(); const getUserOrdersRes = await fetchMethods.getUserOrders({ limit: ORDERS_PER_PAGE, @@ -202,7 +241,7 @@ function Orders() { } async function initOrders() { - const { status, type, pairId, date } = deriveFiltersFromState(); + const { status, type, pairId, date } = deriveGetUserOrdersFiltersFromState(); const getUserOrdersRes = await fetchMethods.getUserOrders({ limit: ORDERS_PER_PAGE, @@ -279,15 +318,34 @@ function Orders() { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const activeOrders = orders.filter((e) => e.status === 'active'); - async function deleteOrder(orderId: string) { - setAlertState('loading'); - setAlertSubtitle('Canceling order...'); + try { + setAlertState('loading'); + setAlertSubtitle('Canceling order...'); - const result = await fetchMethods.cancelOrder(orderId); + // Simulate loading time + await new Promise((resolve) => setTimeout(resolve, 500)); + + const result = await fetchMethods.cancelOrder(orderId); + + if (!result.success) { + throw new Error('ERROR_CANCELING_ORDER'); + } + + setAlertState('success'); + setAlertSubtitle('Order canceled'); + + setTimeout(() => { + setAlertState(null); + setAlertSubtitle(''); + }, 2000); + + setOrders((prev) => prev.filter((e) => e.id !== orderId)); + setLastOrderOffset((prev) => Math.max(prev - 1, 0)); + setTotalOrdersCount((prev) => (prev !== undefined ? prev - 1 : prev)); + } catch (error) { + console.error('Error canceling order:', error); - if (!result.success) { setAlertState('error'); setAlertSubtitle('Error canceling order'); @@ -295,58 +353,42 @@ function Orders() { setAlertState(null); setAlertSubtitle(''); }, 2000); - - return; } - - setAlertState('success'); - setAlertSubtitle('Order canceled'); - - setTimeout(() => { - setAlertState(null); - setAlertSubtitle(''); - }, 2000); - - setOrders((prev) => prev.filter((e) => e.id !== orderId)); - setLastOrderOffset((prev) => Math.max(prev - 1, 0)); - setTotalOrdersCount((prev) => (prev !== undefined ? prev - 1 : prev)); } async function cancelAllOrders() { - setAlertState('loading'); - setAlertSubtitle('Canceling all orders...'); + try { + setAlertState('loading'); + setAlertSubtitle('Canceling all orders...'); - // const results = await Promise.allSettled( - // activeOrders.map(async (e) => { - // await cancelOrder(e.id); - // }), - // ); + // Simulate loading time + await new Promise((resolve) => setTimeout(resolve, 500)); - const results = await (async () => { - const res = []; - for (const order of activeOrders) { - res.push(await fetchMethods.cancelOrder(order.id).catch(() => null)); + const { type, pairId, date } = deriveCancelAllOrdersFiltersFromState(); + + const cancelAllRes = await fetchMethods.cancelAllOrders({ + filterInfo: { + type, + pairId, + date, + }, + }); + + if (!cancelAllRes.success) { + throw new Error('Error canceling all orders'); } - return res; - })(); - if (results.some((e) => e === null)) { + await initialize(); + } catch (error) { + console.error('Error canceling all orders:', error); + setAlertState('error'); - setAlertSubtitle('Some of the orders were not canceled'); - } else { - setAlertState('success'); - setAlertSubtitle('All orders canceled'); - } + setAlertSubtitle('Error canceling all orders'); - setTimeout(() => { - setAlertState(null); - setAlertSubtitle(''); - }, 2000); - - const { success, data } = await fetchMethods.getUserOrders(); - - if (success) { - setOrders(data); + setTimeout(() => { + setAlertState(null); + setAlertSubtitle(''); + }, 2000); } } diff --git a/src/utils/methods.ts b/src/utils/methods.ts index 01aa03b..b07aac1 100644 --- a/src/utils/methods.ts +++ b/src/utils/methods.ts @@ -27,6 +27,8 @@ import { PairSortOption } from '@/interfaces/enum/pair'; import { API_URL } from '@/constants'; import { GetUserOrdersData } from '@/interfaces/fetch-data/get-user-orders/GetUserOrdersData'; import GetUserOrdersAllPairsRes from '@/interfaces/responses/orders/GetUserOrdersAllPairsRes'; +import { CancelAllData } from '@/interfaces/fetch-data/cancel-all-orders/CancelAllData'; +import CancelAllRes from '@/interfaces/responses/orders/CancelAllRes'; const isServer = typeof window === 'undefined'; const baseUrl = isServer ? API_URL : ''; @@ -336,6 +338,26 @@ export async function applyOrder(orderData: ApplyOrderData): Promise res.data); } +export async function cancelAllOrders({ + filterInfo: { pairId, type, date }, +}: CancelAllData): Promise { + return axios + .patch('/api/orders/cancel-all', { + token: sessionStorage.getItem('token'), + filterInfo: { + pairId, + type, + date: date + ? { + from: date.from, + to: date.to, + } + : undefined, + }, + }) + .then((res) => res.data); +} + export async function confirmTransaction( transactionId: string, ): Promise { From e9ad4f04a58566496c4185e8f8267c1332e8a770 Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Wed, 18 Feb 2026 03:28:02 +0300 Subject: [PATCH 09/12] fix: fix pair filter --- src/utils/methods.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/methods.ts b/src/utils/methods.ts index b07aac1..57b5072 100644 --- a/src/utils/methods.ts +++ b/src/utils/methods.ts @@ -253,7 +253,7 @@ export async function getUserOrdersPage(pairId: string): Promise { return axios .patch('/api/orders/get', { @@ -262,6 +262,7 @@ export async function getUserOrders({ limit, offset, filterInfo: { + pairId, status, type, date: date From 5f9fffae932dc6b79efa16dc5ecb91805a4fc817 Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Wed, 18 Feb 2026 17:02:59 +0300 Subject: [PATCH 10/12] update: finish cancel all orders feature --- src/pages/dex/orders/index.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pages/dex/orders/index.tsx b/src/pages/dex/orders/index.tsx index b2ac204..ec3e688 100644 --- a/src/pages/dex/orders/index.tsx +++ b/src/pages/dex/orders/index.tsx @@ -76,6 +76,8 @@ function Orders() { const [totalOrdersCount, setTotalOrdersCount] = useState(undefined); const [orderPageLoading, setOrderPageLoading] = useState(false); + const isFinishedCategory = categoryState.code === 'history'; + function deriveGetUserOrdersFiltersFromState() { const status = categoryState.code === 'active-orders' @@ -436,9 +438,11 @@ function Orders() {
- + {!isFinishedCategory && ( + + )} From a943859ad2498a7e5f33efd0d7cb15f60fc8e3c5 Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Thu, 19 Feb 2026 13:15:16 +0300 Subject: [PATCH 11/12] update: add auth session --- .../UI/ConnectButton/ConnectButton.tsx | 81 +++++++++---------- src/components/default/Header/Header.tsx | 3 +- src/utils/utils.ts | 10 --- 3 files changed, 41 insertions(+), 53 deletions(-) diff --git a/src/components/UI/ConnectButton/ConnectButton.tsx b/src/components/UI/ConnectButton/ConnectButton.tsx index 706bcc7..96a2618 100644 --- a/src/components/UI/ConnectButton/ConnectButton.tsx +++ b/src/components/UI/ConnectButton/ConnectButton.tsx @@ -6,8 +6,6 @@ import useUpdateUser from '@/hook/useUpdateUser'; import AlertType from '@/interfaces/common/AlertType'; import ConnectButtonProps from '@/interfaces/props/components/UI/ConnectButton/ConnectButtonProps'; import ZanoWindow from '@/interfaces/common/ZanoWindow'; -import { getSavedWalletCredentials, setWalletCredentials } from '@/utils/utils'; -import { uuid } from 'uuidv4'; import Button from '../Button/Button'; function ConnectButton(props: ConnectButtonProps) { @@ -28,41 +26,51 @@ function ConnectButton(props: ConnectButtonProps) { await (window as unknown as ZanoWindow).zano.request('GET_WALLET_DATA') ).data; - if (!walletData?.address) { + const walletAddress = walletData?.address; + const walletAlias = walletData?.alias; + + if (!walletAddress) { throw new Error('Companion is offline'); } - if (!walletData?.alias) { + if (!walletAlias) { throw new Error('Alias not found'); } - let nonce = ''; - let signature = ''; - let publicKey = ''; - - const existingWallet = getSavedWalletCredentials(); - - if (existingWallet) { - nonce = existingWallet.nonce; - signature = existingWallet.signature; - publicKey = existingWallet.publicKey; - } else { - const generatedNonce = uuid(); - const signResult = await (window as unknown as ZanoWindow).zano.request( - 'REQUEST_MESSAGE_SIGN', - { message: generatedNonce }, - null, - ); - - if (!signResult?.data?.result) { - throw new Error('Sign denied'); - } - - nonce = generatedNonce; - signature = signResult.data.result.sig; - publicKey = signResult.data.result.pkey; + if (typeof walletAddress !== 'string' || typeof walletAlias !== 'string') { + throw new Error('Invalid wallet data'); } + const authRequestRes = await fetch('/api/auth/request-auth', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + address: walletAddress, + alias: walletAlias, + }), + }).then((res) => res.json()); + + const authMessage = authRequestRes?.data; + + if (!authRequestRes.success || typeof authMessage !== 'string') { + throw new Error('Unknown error during auth request'); + } + + const signResult = await (window as unknown as ZanoWindow).zano.request( + 'REQUEST_MESSAGE_SIGN', + { message: authMessage }, + null, + ); + + if (!signResult?.data?.result) { + throw new Error('Sign denied'); + } + + const signature = signResult.data.result.sig; + const publicKey = signResult.data.result.pkey; + const result = await fetch('/api/auth', { method: 'POST', headers: { @@ -70,11 +78,11 @@ function ConnectButton(props: ConnectButtonProps) { }, body: JSON.stringify({ data: { - alias: walletData.alias, - address: walletData.address, + alias: walletAlias, + address: walletAddress, signature, publicKey, - message: nonce, + message: authMessage, }, }), }).then((res) => res.json()); @@ -83,14 +91,6 @@ function ConnectButton(props: ConnectButtonProps) { throw new Error('Server auth error'); } - if (!existingWallet) { - setWalletCredentials({ - publicKey, - signature, - nonce, - }); - } - sessionStorage.setItem('token', result?.data); updateWalletState(dispatch, { ...walletData, connected: true }); @@ -105,7 +105,6 @@ function ConnectButton(props: ConnectButtonProps) { setAlertState('error'); setAlertErrMessage((error as { message: string }).message); setTimeout(() => setAlertState(null), 3000); - setWalletCredentials(undefined); } } diff --git a/src/components/default/Header/Header.tsx b/src/components/default/Header/Header.tsx index 4006c26..6c59e82 100644 --- a/src/components/default/Header/Header.tsx +++ b/src/components/default/Header/Header.tsx @@ -18,7 +18,7 @@ import Button from '@/components/UI/Button/Button'; import { useWindowWidth } from '@react-hook/window-size'; import ConnectButton from '@/components/UI/ConnectButton/ConnectButton'; -import { classes, notationToString, setWalletCredentials, shortenAddress } from '@/utils/utils'; +import { classes, notationToString, shortenAddress } from '@/utils/utils'; import useAdvancedTheme from '@/hook/useTheme'; import { Store } from '@/store/store-reducer'; @@ -54,7 +54,6 @@ function Header({ isLg }: { isLg?: boolean }) { function logout() { sessionStorage.removeItem('token'); - setWalletCredentials(undefined); updateWalletState(dispatch, null); } diff --git a/src/utils/utils.ts b/src/utils/utils.ts index a41d021..6dffb62 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -111,16 +111,6 @@ export const localeTimeLeft = (now: number | null, timestamp: number) => { return `${intToStrFixedLen(hours)}:${intToStrFixedLen(minutes)}:${intToStrFixedLen(seconds)}`; }; -export function getSavedWalletCredentials() { - const savedWallet = localStorage.getItem('wallet'); - if (!savedWallet) return undefined; - try { - return JSON.parse(savedWallet) as WalletCredentials; - } catch { - return undefined; - } -} - export function setWalletCredentials(credentials: WalletCredentials | undefined) { if (credentials) { localStorage.setItem('wallet', JSON.stringify(credentials)); From 9cb526357d925fc6d63eac71e738f612b58df2b7 Mon Sep 17 00:00:00 2001 From: Andrew Besedin Date: Fri, 20 Feb 2026 13:29:48 +0300 Subject: [PATCH 12/12] update: fix prices in My Orders page --- .../responses/orders/GetUserOrdersRes.ts | 40 +++++++++++- .../dex/orders/OrdersTable/OrdersTable.tsx | 62 ++++++++++++++----- 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/src/interfaces/responses/orders/GetUserOrdersRes.ts b/src/interfaces/responses/orders/GetUserOrdersRes.ts index fca3f67..4e023e0 100644 --- a/src/interfaces/responses/orders/GetUserOrdersRes.ts +++ b/src/interfaces/responses/orders/GetUserOrdersRes.ts @@ -1,7 +1,28 @@ import CurrencyRow from '@/interfaces/common/CurrencyRow'; import OfferType from '@/interfaces/common/OfferType'; -interface UserOrderData { +export type GetUserOrdersResCurrency = { + id: number; + name: string; + code: string; + type: string; + asset_id: string; + auto_parsed: boolean; + asset_info?: { + asset_id: string; + logo: string; + price_url: string; + ticker: string; + full_name: string; + total_max_supply: string; + current_supply: string; + decimal_point: number; + meta_info: string; + }; + whitelisted: boolean; +}; + +export interface UserOrderData { id: string; type: OfferType; timestamp: string; @@ -15,6 +36,21 @@ interface UserOrderData { left: number; first_currency: CurrencyRow; second_currency: CurrencyRow; + + pair: { + id: number; + first_currency_id: number; + second_currency_id: number; + rate?: number; + coefficient?: number; + high?: number; + low?: number; + volume: number; + featured: boolean; + + first_currency: GetUserOrdersResCurrency; + second_currency: GetUserOrdersResCurrency; + }; } interface GetUserOrdersRes { @@ -24,5 +60,3 @@ interface GetUserOrdersRes { } export default GetUserOrdersRes; - -export type { UserOrderData }; diff --git a/src/pages/dex/orders/OrdersTable/OrdersTable.tsx b/src/pages/dex/orders/OrdersTable/OrdersTable.tsx index dee1ef8..929a97e 100644 --- a/src/pages/dex/orders/OrdersTable/OrdersTable.tsx +++ b/src/pages/dex/orders/OrdersTable/OrdersTable.tsx @@ -8,7 +8,8 @@ import OrdersTableProps from '@/interfaces/props/pages/dex/orders/OrdersTable/Or import { UserOrderData } from '@/interfaces/responses/orders/GetUserOrdersRes'; import Decimal from 'decimal.js'; import Tooltip from '@/components/UI/Tooltip/Tooltip'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; +import { Store } from '@/store/store-reducer'; import styles from './OrdersTable.module.scss'; function OrdersTable(props: OrdersTableProps) { @@ -19,23 +20,50 @@ function OrdersTable(props: OrdersTableProps) { const isActive = category === 'active-orders'; function Row(props: { orderData: UserOrderData }) { + const { state } = useContext(Store); const { orderData } = props; const firstCurrencyName = orderData?.first_currency?.name || ''; const secondCurrencyName = orderData?.second_currency?.name || ''; + const secondCurrencyId = orderData.second_currency.asset_id ?? undefined; + const timestampDate = new Date(parseInt(orderData.timestamp, 10)); - const amount = ( - isActive - ? new Decimal(orderData.amount) - : new Decimal(orderData.amount).minus(orderData.left) - ).toString(); - const total = ( - isActive - ? new Decimal(orderData.total) - : new Decimal(orderData.amount).minus(orderData.left).mul(orderData.price) - ).toString(); + const secondAssetUsdPriceNumber = secondCurrencyId + ? state.assetsRates.get(secondCurrencyId) + : undefined; + const secondAssetUsdPrice = secondAssetUsdPriceNumber + ? new Decimal(secondAssetUsdPriceNumber) + : undefined; + + const pairRateNumber = orderData.pair.rate; + const pairRate = pairRateNumber !== undefined ? new Decimal(pairRateNumber) : undefined; + + const firstCurrencyUsdPrice = + pairRate && secondAssetUsdPrice ? pairRate.mul(secondAssetUsdPrice) : undefined; + + const actualAmount = isActive + ? new Decimal(orderData.amount) + : new Decimal(orderData.amount).minus(orderData.left); + + const actualTotal = isActive + ? new Decimal(orderData.total) + : new Decimal(orderData.amount).minus(orderData.left).mul(orderData.price); + + const amountUSD = firstCurrencyUsdPrice + ? firstCurrencyUsdPrice.mul(actualAmount) + : undefined; + const priceUSD = secondAssetUsdPrice ? secondAssetUsdPrice.mul(orderData.price) : undefined; + const totalUSD = secondAssetUsdPrice ? secondAssetUsdPrice.mul(actualTotal) : undefined; + + const amountPresentation: string = notationToString(actualAmount.toFixed()); + const pricePresentation: string = notationToString(orderData.price); + const totalPresentation: string = notationToString(actualTotal.toFixed()); + + const amountUSDPresentation: string = amountUSD ? amountUSD.toFixed(2) : 'N/A'; + const priceUSDPresentation: string = priceUSD ? priceUSD.toFixed(2) : 'N/A'; + const totalUSDPresentation: string = totalUSD ? totalUSD.toFixed(2) : 'N/A'; function CurrencyTableData({ header, @@ -102,21 +130,21 @@ function OrdersTable(props: OrdersTableProps) { {isActive && (