wip: add My Orders fetching multiple pages & filtering

This commit is contained in:
Andrew Besedin 2026-02-17 23:05:45 +03:00
parent 451e53e244
commit daecf49bc0
2 changed files with 196 additions and 106 deletions

View file

@ -12,6 +12,7 @@ export type GetUserOrdersData = {
limit: number;
offset: number;
filterInfo: {
pairId?: number;
status?: GetUserOrdersBodyStatus;
type?: GetUserOrdersBodyType;
date?: {

View file

@ -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<UserOrderData[]>([]);
const [lastOrderOffset, setLastOrderOffset] = useState(0);
const [totalOrdersCount, setTotalOrdersCount] = useState<number | undefined>(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() {
</div>
<OrdersTable
value={orders
.filter(buySellFilter)
.filter(pairFilter)
.filter(dateFilter)
.filter(categoryFilter)}
value={orders}
setAlertState={setAlertState}
setAlertSubtitle={setAlertSubtitle}
setOrders={setOrders}
@ -289,7 +378,7 @@ function Orders() {
/>
<div className={styles['orders__preloader-wrapper']} ref={inViewRef}>
<Preloader />
{orderPageLoading && <Preloader />}
</div>
</div>
{alertState && (