Merge pull request #57 from hyle-team/dev

Dev
This commit is contained in:
Dmitrii Kolpakov 2026-02-25 11:52:19 +01:00 committed by GitHub
commit 3cafe3c892
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 564 additions and 225 deletions

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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;
};
};
};

View file

@ -0,0 +1,24 @@
export enum GetUserOrdersBodyStatus {
ACTIVE = 'active',
FINISHED = 'finished',
}
export enum GetUserOrdersBodyType {
BUY = 'buy',
SELL = 'sell',
}
export type GetUserOrdersData = {
limit: number;
offset: number;
filterInfo: {
pairId?: number;
status?: GetUserOrdersBodyStatus;
type?: GetUserOrdersBodyType;
date?: {
// UNIX timestamps in milliseconds
from: number;
to: number;
};
};
};

View file

@ -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<SetStateAction<AlertType>>;
setAlertSubtitle: Dispatch<SetStateAction<string>>;
setOrders: Dispatch<SetStateAction<UserOrderData[]>>;
deleteOrder: (orderId: string) => Promise<void>;
}
export default OrdersTableProps;

View file

@ -0,0 +1,5 @@
interface CancelAllRes {
success: true;
}
export default CancelAllRes;

View file

@ -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;

View file

@ -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,13 +36,27 @@ 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 {
success: true;
totalItemsCount: number;
data: UserOrderData[];
}
export default GetUserOrdersRes;
export type { UserOrderData };

View file

@ -4,64 +4,66 @@ 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';
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) {
const orders = props.value || [];
const { setAlertState, setAlertSubtitle, setOrders, category } = props;
const { deleteOrder, category } = props;
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));
async function deleteOrder() {
setAlertState('loading');
setAlertSubtitle('Canceling order...');
const result = await cancelOrder(orderData.id);
const secondAssetUsdPriceNumber = secondCurrencyId
? state.assetsRates.get(secondCurrencyId)
: undefined;
const secondAssetUsdPrice = secondAssetUsdPriceNumber
? new Decimal(secondAssetUsdPriceNumber)
: undefined;
if (result.success) {
setAlertState('success');
setAlertSubtitle('Order canceled');
} else {
setAlertState('error');
setAlertSubtitle('Error canceling order');
}
const pairRateNumber = orderData.pair.rate;
const pairRate = pairRateNumber !== undefined ? new Decimal(pairRateNumber) : undefined;
setTimeout(() => {
setAlertState(null);
setAlertSubtitle('');
}, 2000);
const firstCurrencyUsdPrice =
pairRate && secondAssetUsdPrice ? pairRate.mul(secondAssetUsdPrice) : undefined;
const { success, data } = await getUserOrders();
const actualAmount = isActive
? new Decimal(orderData.amount)
: new Decimal(orderData.amount).minus(orderData.left);
if (success) {
setOrders(data);
}
}
const actualTotal = isActive
? new Decimal(orderData.total)
: new Decimal(orderData.amount).minus(orderData.left).mul(orderData.price);
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 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,
@ -128,21 +130,21 @@ function OrdersTable(props: OrdersTableProps) {
</td>
<CurrencyTableData
price={notationToString(5.23)}
price={priceUSDPresentation}
header="Price"
value={notationToString(orderData.price)}
value={pricePresentation}
currency={secondCurrencyName}
/>
<CurrencyTableData
price={notationToString(5.23)}
price={amountUSDPresentation}
header="Amount"
value={notationToString(amount)}
value={amountPresentation}
currency={firstCurrencyName}
/>
<CurrencyTableData
price={notationToString(5.23)}
price={totalUSDPresentation}
header="Total"
value={notationToString(total)}
value={totalPresentation}
currency={secondCurrencyName}
/>
{isActive && (
@ -150,7 +152,7 @@ function OrdersTable(props: OrdersTableProps) {
<Button
key={nanoid(16)}
className={styles.delete__button}
onClick={deleteOrder}
onClick={() => deleteOrder(orderData.id)}
>
<DeleteIcon />
</Button>

View file

@ -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,18 @@ 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,
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';
import { CancelAllBodyOrderType } from '@/interfaces/fetch-data/cancel-all-orders/CancelAllData';
import OrdersTable from './OrdersTable/OrdersTable';
const ORDERS_PER_PAGE = 10;
function Orders() {
const fetchUser = useUpdateUser();
@ -42,6 +52,8 @@ function Orders() {
},
];
const [initialized, setInitialized] = useState(false);
const [pairsValues, setPairsValues] = useState<PairValue[]>([{ name: 'All pairs', code: '' }]);
const [pairDropdownValue, setPairDropdownState] = useState(pairsValues[0]);
@ -60,142 +72,325 @@ function Orders() {
});
const [orders, setOrders] = useState<UserOrderData[]>([]);
const [lastOrderOffset, setLastOrderOffset] = useState(0);
const [totalOrdersCount, setTotalOrdersCount] = useState<number | undefined>(undefined);
const [orderPageLoading, setOrderPageLoading] = useState(false);
useEffect(() => {
async function getOrders() {
setAlertState('loading');
setAlertSubtitle('Loading orders data...');
const isFinishedCategory = categoryState.code === 'history';
const result = await getUserOrders();
function deriveGetUserOrdersFiltersFromState() {
const status =
categoryState.code === 'active-orders'
? GetUserOrdersBodyStatus.ACTIVE
: GetUserOrdersBodyStatus.FINISHED;
if (!result.success) {
setAlertState('error');
setAlertSubtitle('Error loading orders data');
await new Promise((resolve) => setTimeout(resolve, 2000));
setAlertState(null);
setAlertSubtitle('');
const type = (() => {
if (buyDropdownValue.name === 'Buy & Sell') {
return undefined;
}
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,
};
}
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 } = deriveGetUserOrdersFiltersFromState();
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');
}
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;
}
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;
if (totalOrdersCount !== undefined && lastOrderOffset >= totalOrdersCount) {
return;
}
const pairs = getPairsFromOrders(result.data);
setPairsValues(pairs);
setPairDropdownState(pairs[0]);
setAlertState(null);
setAlertSubtitle('');
const { success, data } = await getUserOrders();
if (success) {
setOrders(data);
if (orderPageLoading) {
return;
}
setOrderPageLoading(true);
try {
await addNewOrdersPage();
} catch (error) {
console.error('Error fetching new orders page:', error);
setAlertState('error');
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 } = deriveGetUserOrdersFiltersFromState();
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');
}
getOrders();
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;
async function deleteOrder(orderId: string) {
try {
setAlertState('loading');
setAlertSubtitle('Canceling order...');
if (buyDropdownValue.name === 'Buy') return e.type === 'buy';
// Simulate loading time
await new Promise((resolve) => setTimeout(resolve, 500));
if (buyDropdownValue.name === 'Sell') return e.type === 'sell';
}
const result = await fetchMethods.cancelOrder(orderId);
function pairFilter(e: UserOrderData) {
if (!pairDropdownValue) return true;
if (!result.success) {
throw new Error('ERROR_CANCELING_ORDER');
}
return !pairDropdownValue.code || e.pair_id === pairDropdownValue.code;
}
setAlertState('success');
setAlertSubtitle('Order canceled');
function dateFilter(e: UserOrderData) {
if (!dateRange.first || !dateRange.last) return true;
const firstDate = new Date(dateRange.first);
const lastDate = new Date(dateRange.last);
setTimeout(() => {
setAlertState(null);
setAlertSubtitle('');
}, 2000);
const timestamp = parseInt(e.timestamp, 10);
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);
firstDate.setHours(0, 0, 0, 0);
lastDate.setHours(24, 0, 0, 0);
setAlertState('error');
setAlertSubtitle('Error canceling order');
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';
setTimeout(() => {
setAlertState(null);
setAlertSubtitle('');
}, 2000);
}
return e.status === 'finished';
}
const activeOrders = orders.filter((e) => e.status === 'active');
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 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 getUserOrders();
if (success) {
setOrders(data);
setTimeout(() => {
setAlertState(null);
setAlertSubtitle('');
}, 2000);
}
}
@ -243,23 +438,23 @@ function Orders() {
<DateRangeSelector value={dateRange} setValue={setDateRange} />
</div>
<Button transparent onClick={cancelAllOrders}>
Cancel all orders
</Button>
{!isFinishedCategory && (
<Button transparent onClick={cancelAllOrders}>
Cancel all orders
</Button>
)}
</div>
</div>
<OrdersTable
value={orders
.filter(buySellFilter)
.filter(pairFilter)
.filter(dateFilter)
.filter(categoryFilter)}
setAlertState={setAlertState}
setAlertSubtitle={setAlertSubtitle}
setOrders={setOrders}
value={orders}
category={categoryState.code}
deleteOrder={deleteOrder}
/>
<div className={styles['orders__preloader-wrapper']} ref={inViewRef}>
{orderPageLoading && <Preloader />}
</div>
</div>
{alertState && (
<Alert

View file

@ -92,5 +92,10 @@
}
}
}
.orders__preloader-wrapper {
display: flex;
justify-content: center;
}
}
}

View file

@ -25,6 +25,10 @@ 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';
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 : '';
@ -246,9 +250,35 @@ export async function getUserOrdersPage(pairId: string): Promise<ErrorRes | GetU
.then((res) => res.data);
}
export async function getUserOrders(): Promise<ErrorRes | GetUserOrdersRes> {
export async function getUserOrders({
limit,
offset,
filterInfo: { pairId, status, type, date },
}: GetUserOrdersData): Promise<ErrorRes | GetUserOrdersRes> {
return axios
.post('/api/orders/get', {
.patch('/api/orders/get', {
token: sessionStorage.getItem('token'),
limit,
offset,
filterInfo: {
pairId,
status,
type,
date: date
? {
from: date.from,
to: date.to,
}
: undefined,
},
})
.then((res) => res.data);
}
export async function getUserOrdersAllPairs(): Promise<ErrorRes | GetUserOrdersAllPairsRes> {
return axios
.patch('/api/orders/get-user-orders-pairs', {
token: sessionStorage.getItem('token'),
})
.then((res) => res.data);
@ -309,6 +339,26 @@ export async function applyOrder(orderData: ApplyOrderData): Promise<ErrorRes |
.then((res) => res.data);
}
export async function cancelAllOrders({
filterInfo: { pairId, type, date },
}: CancelAllData): Promise<ErrorRes | CancelAllRes> {
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<ErrorRes | { success: true }> {

View file

@ -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));