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 && (