diff --git a/src/components/UI/RangeInput/RangeInput.module.scss b/src/components/UI/RangeInput/RangeInput.module.scss
index 191d792..b68e15e 100644
--- a/src/components/UI/RangeInput/RangeInput.module.scss
+++ b/src/components/UI/RangeInput/RangeInput.module.scss
@@ -9,7 +9,7 @@
background: none;
outline: none;
border: none;
- z-index: 5;
+ z-index: 2;
cursor: pointer;
}
@@ -18,6 +18,13 @@
top: 30px;
transition: none;
transform: translateX(-50%);
+ box-shadow: 0px 4px 14px 0px #07072b59;
+ padding: 9px 12px;
+
+ p {
+ font-size: 14px;
+ font-weight: 500;
+ }
}
.range__slider {
@@ -74,18 +81,4 @@
border: 2px solid var(--window-bg-color);
transition: background 0.3s ease-in-out;
}
-
- // .input__range::-webkit-slider-runnable-track::-webkit-slider-thumb {
- // background-color: #fff;
- // border: 2px solid #555;
- // }
-
- // .input__range::-webkit-slider-runnable-track {
- // -webkit-appearance: none;
- // height: 20px;
- // background-color: #1F8FEB;
- // border: 1px solid #ffffff;
- // box-shadow: none;
- // background: transparent;
- // }
}
diff --git a/src/components/UI/RangeInput/RangeInput.tsx b/src/components/UI/RangeInput/RangeInput.tsx
index cc8f8a8..d1df0f7 100644
--- a/src/components/UI/RangeInput/RangeInput.tsx
+++ b/src/components/UI/RangeInput/RangeInput.tsx
@@ -38,7 +38,7 @@ function RangeInput(props: RangeInputProps) {
className={styles.input__range__tooltip}
shown={tooltipShown}
>
- {realValue}%
+
{realValue}%
{
+ return (
+
+ {data.map((tab) => (
+
+ ))}
+
+ );
+};
+
+export default Tabs;
diff --git a/src/components/UI/Tabs/styles.module.scss b/src/components/UI/Tabs/styles.module.scss
new file mode 100644
index 0000000..143ba9c
--- /dev/null
+++ b/src/components/UI/Tabs/styles.module.scss
@@ -0,0 +1,48 @@
+.tabs {
+ width: 100%;
+ border-bottom: 1px solid var(--delimiter-color);
+ display: flex;
+ align-items: center;
+ gap: 22px;
+
+ &.button {
+ flex-wrap: wrap;
+ gap: 5px;
+ border-bottom: none;
+
+ .tabs__item {
+ padding: 6px 10px;
+ border-radius: 25px;
+ font-size: 12px;
+ border: 1px solid var(--action-btn-bg);
+
+ &.active {
+ border-color: transparent;
+ background-color: #1f8feb;
+ }
+ }
+ }
+
+ &__item {
+ cursor: pointer;
+ padding-bottom: 7px;
+ position: relative;
+ border-top-left-radius: 10px;
+ border-top-right-radius: 10px;
+ font-size: 14px;
+ font-weight: 500;
+ border-bottom: 2px solid transparent;
+ background-color: transparent;
+ color: #1f8feb;
+
+ &.active {
+ color: var(--text-color);
+ border-color: #1f8feb;
+ }
+
+ &:hover {
+ border-color: #1f8feb;
+ background-color: transparent;
+ }
+ }
+}
diff --git a/src/components/UI/Tabs/types.ts b/src/components/UI/Tabs/types.ts
new file mode 100644
index 0000000..8b5dc0d
--- /dev/null
+++ b/src/components/UI/Tabs/types.ts
@@ -0,0 +1,12 @@
+export type tabsType = {
+ title: string;
+ type: string;
+ length?: number;
+};
+
+export interface TabsProps {
+ type?: 'tab' | 'button';
+ value: tabsType;
+ setValue: (_next: tabsType) => void;
+ data: tabsType[];
+}
diff --git a/src/components/default/BackButton/BackButton.module.scss b/src/components/default/BackButton/BackButton.module.scss
index 4c7d844..bf7448a 100644
--- a/src/components/default/BackButton/BackButton.module.scss
+++ b/src/components/default/BackButton/BackButton.module.scss
@@ -1,4 +1,13 @@
.back_btn {
display: flex;
gap: 12px;
+
+ &.sm {
+ padding: 12px 22px;
+
+ span {
+ font-size: 14px;
+ font-weight: 500;
+ }
+ }
}
diff --git a/src/components/default/BackButton/BackButton.tsx b/src/components/default/BackButton/BackButton.tsx
index c3b05d7..0fbd994 100644
--- a/src/components/default/BackButton/BackButton.tsx
+++ b/src/components/default/BackButton/BackButton.tsx
@@ -1,16 +1,21 @@
import { ReactComponent as ArrowWhiteIcon } from '@/assets/images/UI/arrow_white.svg';
import Button from '@/components/UI/Button/Button';
import { useRouter } from 'next/router';
+import { classes } from '@/utils/utils';
import styles from './BackButton.module.scss';
+import { BackButtonProps } from './types';
-function BackButton() {
+function BackButton({ className, isSm }: BackButtonProps) {
const router = useRouter();
return (
-
- );
-}
-
-export default InputPanelItem;
diff --git a/src/pages/dex/trading/OrdersBuySellSwitch/OrdersBuySellSwitch.module.scss b/src/pages/dex/trading/OrdersBuySellSwitch/OrdersBuySellSwitch.module.scss
deleted file mode 100644
index aac0fd1..0000000
--- a/src/pages/dex/trading/OrdersBuySellSwitch/OrdersBuySellSwitch.module.scss
+++ /dev/null
@@ -1,31 +0,0 @@
-.orders-buy-sell-switch {
- display: flex;
- align-items: center;
- gap: 8px;
- background-color: transparent !important;
- cursor: pointer;
-
- &:hover {
- opacity: 0.7;
- }
-
- > p {
- font-size: 16px;
- font-weight: 600;
- color: #16d1d6;
- }
-
- > svg > * {
- fill: transparent;
- }
-
- &.orders-buy-sell-switch_sell {
- > p {
- color: #ff6767;
- }
-
- > svg > * {
- stroke: #ff6767;
- }
- }
-}
diff --git a/src/pages/dex/trading/OrdersBuySellSwitch/OrdersBuySellSwitch.tsx b/src/pages/dex/trading/OrdersBuySellSwitch/OrdersBuySellSwitch.tsx
deleted file mode 100644
index fbe8d93..0000000
--- a/src/pages/dex/trading/OrdersBuySellSwitch/OrdersBuySellSwitch.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import HorizontalSelectProps from '@/interfaces/props/components/UI/HorizontalSelect/HorizontalSelectProps';
-import { ReactComponent as ArrowIcon } from '@/assets/images/UI/trade_arrow.svg';
-import SelectValue from '@/interfaces/states/pages/dex/trading/InputPanelItem/SelectValue';
-import { classes } from '@/utils/utils';
-import styles from './OrdersBuySellSwitch.module.scss';
-
-export default function OrdersBuySellSwitch({
- body,
- value,
- setValue,
- className,
-}: HorizontalSelectProps
) {
- const defaultValue = body[0];
-
- const buyValue = body.find((e) => e.code === 'buy');
- const sellValue = body.find((e) => e.code === 'sell');
-
- const isBuy = value.code === 'buy';
-
- return (
- setValue((isBuy ? sellValue : buyValue) || defaultValue)}
- >
- To {isBuy ? 'Sell' : 'Buy'} Orders
-
-
- );
-}
diff --git a/src/pages/dex/trading/[id].tsx b/src/pages/dex/trading/[id].tsx
index ea28999..117c1e5 100644
--- a/src/pages/dex/trading/[id].tsx
+++ b/src/pages/dex/trading/[id].tsx
@@ -1,45 +1,11 @@
import styles from '@/styles/Trading.module.scss';
import Footer from '@/components/default/Footer/Footer';
import Header from '@/components/default/Header/Header';
-import PageTitle from '@/components/default/PageTitle/PageTitle';
-import { ReactComponent as ClockIcon } from '@/assets/images/UI/clock_icon.svg';
-import { ReactComponent as UpIcon } from '@/assets/images/UI/up_icon.svg';
-import { ReactComponent as DownIcon } from '@/assets/images/UI/down_icon.svg';
-import { ReactComponent as VolumeIcon } from '@/assets/images/UI/volume_icon.svg';
-import { ReactComponent as NoOffersIcon } from '@/assets/images/UI/no_offers.svg';
-import { ReactComponent as ArrowRight } from '@/assets/images/UI/arrow-outlined-right.svg';
-import Dropdown from '@/components/UI/Dropdown/Dropdown';
import HorizontalSelect from '@/components/UI/HorizontalSelect/HorizontalSelect';
-import { useContext, useEffect, useRef, useState } from 'react';
-import { Store } from '@/store/store-reducer';
-import { useRouter } from 'next/router';
-import {
- applyOrder,
- cancelOrder,
- getOrdersPage,
- confirmTransaction,
- getPair,
- getPairStats,
- getUserOrdersPage,
- getCandles,
-} from '@/utils/methods';
+import { useCallback, useState } from 'react';
+import { cancelOrder } from '@/utils/methods';
import ContentPreloader from '@/components/UI/ContentPreloader/ContentPreloader';
-import Link from 'next/link';
-import { nanoid } from 'nanoid';
-import {
- cutAddress,
- formatDollarValue,
- getAssetIcon,
- isPositiveFloatStr,
- notationToString,
- roundTo,
- shortenAddress,
- tradingKnownCurrencies,
-} from '@/utils/utils';
import Alert from '@/components/UI/Alert/Alert';
-import socket from '@/utils/socket';
-import SelectValue from '@/interfaces/states/pages/dex/trading/InputPanelItem/SelectValue';
-import AlertType from '@/interfaces/common/AlertType';
import PeriodState from '@/interfaces/states/pages/dex/trading/InputPanelItem/PeriodState';
import OrderRow from '@/interfaces/common/OrderRow';
import ApplyTip from '@/interfaces/common/ApplyTip';
@@ -47,1355 +13,219 @@ import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
import { PairStats } from '@/interfaces/responses/orders/GetPairStatsRes';
import PairData from '@/interfaces/common/PairData';
import CandleRow from '@/interfaces/common/CandleRow';
-import StatItemProps from '@/interfaces/props/pages/dex/trading/StatItemProps';
-import { confirmIonicSwap, ionicSwap } from '@/utils/wallet';
-import Decimal from 'decimal.js';
-import Tooltip from '@/components/UI/Tooltip/Tooltip';
-import { updateAutoClosedNotification } from '@/store/actions';
+import { Trade } from '@/interfaces/responses/trades/GetTradeRes';
+import { periods, buySellValues } from '@/constants';
+import { useAlert } from '@/hook/useAlert';
+import useScroll from '@/hook/useScroll';
+import InputPanelItem from '@/components/dex/InputPanelItem';
+import TradingHeader from '@/components/dex/TradingHeader';
+import UserOrders from '@/components/dex/UserOrders';
+import OrdersPool from '@/components/dex/OrdersPool';
+import CandleChart from '@/components/dex/CandleChart';
+import { useSocketListeners } from '@/hook/useSocketListeners';
+import { useTradingData } from '@/hook/useTradingData';
+import useFilteredData from '@/hook/useFilteredData';
+import useTradeInit from '@/hook/useTradeInit';
+import useMatrixAddresses from '@/hook/useMatrixAddresses';
+import takeOrderClick from '@/utils/takeOrderClick';
import useUpdateUser from '@/hook/useUpdateUser';
-import LightningImg from '@/assets/images/UI/lightning.png';
-import RocketImg from '@/assets/images/UI/rocket.png';
-import { ReactComponent as ConnectionIcon } from '@/assets/images/UI/connection.svg';
-import Image from 'next/image';
-import CandleChart from './CandleChart/CandleChart';
-import OrdersBuySellSwitch from './OrdersBuySellSwitch/OrdersBuySellSwitch';
-import InputPanelItem from './InputPanelItem/InputPanelItem';
-import { validateTokensInput } from '../../../../shared/utils';
-
-function BadgeStatus({ type = 'instant' }: { type?: 'instant' | 'high' }) {
- return (
-
-
- {type === 'instant' ? 'instant' : 'high volume'}
-
- );
-}
function Trading() {
- const router = useRouter();
+ const { alertState, alertSubtitle, setAlertState } = useAlert();
+ const { elementRef: orderListRef, scrollToElement: scrollToOrdersList } =
+ useScroll();
+ const { elementRef: orderFormRef, scrollToElement: scrollToOrderForm } =
+ useScroll();
+
const fetchUser = useUpdateUser();
-
const [ordersHistory, setOrdersHistory] = useState([]);
-
- const orderFormRef = useRef(null);
- const orderListRef = useRef(null);
-
- const pairId = typeof router.query.id === 'string' ? router.query.id : '';
-
- const periods: PeriodState[] = [
- {
- name: '1H',
- code: '1h',
- },
- {
- name: '1D',
- code: '1d',
- },
- {
- name: '1W',
- code: '1w',
- },
- {
- name: '1M',
- code: '1m',
- },
- ];
-
- const buySellValues: SelectValue[] = [
- {
- name: 'Buy',
- code: 'buy',
- },
- {
- name: 'Sell',
- code: 'sell',
- },
- ];
-
- const { state, dispatch } = useContext(Store);
-
const [userOrders, setUserOrders] = useState([]);
-
- const [periodsState, setPeriodsState] = useState(periods[0]);
-
+ const [periodsState, setPeriodsState] = useState(periods[4]);
const [pairData, setPairData] = useState(null);
-
const [candles, setCandles] = useState([]);
-
- const [candlesLoaded, setCandlesLoaded] = useState(false);
-
- const [ordersLoading, setOrdersLoading] = useState(true);
-
+ const [trades, setTrades] = useState([]);
const [myOrdersLoading, setMyOrdersLoading] = useState(true);
-
const [ordersBuySell, setOrdersBuySell] = useState(buySellValues[0]);
-
const [pairStats, setPairStats] = useState(null);
-
const [applyTips, setApplyTips] = useState([]);
+ const matrixAddresses = useMatrixAddresses(ordersHistory);
+ const [orderFormType, setOrderFormType] = useState(buySellValues[1]);
- const [alertState, setAlertState] = useState(null);
+ const {
+ orderForm,
+ currencyNames,
+ firstAssetLink,
+ secondAssetLink,
+ secondAssetUsdPrice,
+ balance,
+ zanoBalance,
+ pairRateUsd,
+ } = useTradeInit({ pairData, pairStats });
- const [alertSubtitle, setAlertSubtitle] = useState('');
+ const {
+ fetchTrades,
+ updateOrders,
+ updateUserOrders,
+ candlesLoaded,
+ ordersLoading,
+ tradesLoading,
+ } = useTradingData({
+ periodsState,
+ setApplyTips,
+ setCandles,
+ setMyOrdersLoading,
+ setOrdersHistory,
+ setPairData,
+ setPairStats,
+ setTrades,
+ setUserOrders,
+ });
- const [matrixAddresses, setMatrixAddresses] = useState([]);
+ useSocketListeners({
+ setUserOrders,
+ ordersHistory,
+ setApplyTips,
+ setOrdersHistory,
+ setPairStats,
+ updateOrders,
+ });
- async function updateOrders() {
- setOrdersLoading(true);
- const result = await getOrdersPage(pairId);
- if (!result.success) return;
- setOrdersHistory(result?.data || []);
- setOrdersLoading(false);
- }
-
- async function socketUpdateOrders() {
- const result = await getUserOrdersPage(pairId);
-
- if (result.success) {
- setUserOrders(result?.data?.orders || []);
- setApplyTips(result?.data?.applyTips || []);
- }
- }
-
- useEffect(() => {
- socket.emit('in-trading', { id: router.query.id });
-
- return () => {
- socket.emit('out-trading', { id: router.query.id });
- };
- }, []);
-
- useEffect(() => {
- socket.on('new-order', async (data) => {
- setOrdersHistory([data.orderData, ...ordersHistory]);
- await socketUpdateOrders();
- });
-
- socket.on('delete-order', async () => {
- await updateOrders();
- await socketUpdateOrders();
- });
-
- return () => {
- socket.off('new-order');
- socket.off('delete-order');
- };
- }, [ordersHistory]);
-
- useEffect(() => {
- function onUpdateStats({ pairStats }: { pairStats: PairStats }) {
- setPairStats(pairStats);
- }
-
- socket.on('update-pair-stats', onUpdateStats);
-
- return () => {
- socket.off('update-pair-stats', onUpdateStats);
- };
- }, []);
-
- useEffect(() => {
- socket.on('update-orders', async () => {
- await socketUpdateOrders();
- });
-
- return () => {
- socket.off('update-orders');
- };
- }, []);
-
- // Detect registered addresses
- const hasConnection = (address: string) =>
- matrixAddresses.some(
- (item: { address: string; registered: boolean }) =>
- item.address === address && item.registered,
- );
-
- const filteredOrdersHistory = ordersHistory
- ?.filter((e) => e.type === ordersBuySell.code)
- ?.filter((e) => e.user.address !== state.wallet?.address)
- ?.sort((a, b) => {
- if (ordersBuySell.code === 'buy') {
- return parseFloat(b.price.toString()) - parseFloat(a.price.toString());
- }
- return parseFloat(a.price.toString()) - parseFloat(b.price.toString());
- });
-
- // Get registered addresses from matrix
- useEffect(() => {
- const fetchConnections = async () => {
- const filteredAddresses = ordersHistory?.map((e) => e?.user?.address);
- if (!filteredAddresses.length) return;
- const response = await fetch('https://messenger.zano.org/api/get-addresses', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- addresses: filteredAddresses,
- }),
+ // Take order from trades
+ const onHandleTakeOrder = useCallback(
+ (event: React.MouseEvent, e: PageOrderData) => {
+ setOrderFormType(() => {
+ return e.type === 'buy' ? buySellValues[2] : buySellValues[1];
});
- const data = await response.json();
- setMatrixAddresses(data.addresses);
- };
+ takeOrderClick({
+ event,
+ PageOrderData: e,
+ balance,
+ orderForm,
+ pairData,
+ scrollToOrderForm,
+ });
+ },
+ [balance, orderForm, pairData, scrollToOrderForm],
+ );
- fetchConnections();
- }, [ordersHistory]);
+ // Cancel all user orders
+ const handleCancelAllOrders = useCallback(async () => {
+ if (!userOrders.length) return;
- const firstCurrencyName = pairData?.first_currency?.name || '';
- const secondCurrencyName = pairData?.second_currency?.name || '';
-
- const firstAssetId = pairData ? pairData.first_currency?.asset_id : undefined;
- const secondAssetId = pairData ? pairData.second_currency?.asset_id : undefined;
- const firstAssetLink = firstAssetId
- ? `https://explorer.zano.org/assets?asset_id=${encodeURIComponent(firstAssetId)}`
- : undefined;
- const secondAssetLink = secondAssetId
- ? `https://explorer.zano.org/assets?asset_id=${encodeURIComponent(secondAssetId)}`
- : undefined;
-
- const secondAssetUsdPrice = state.assetsRates.get(secondAssetId || '');
- const secondCurrencyDP = pairData?.second_currency.asset_info?.decimal_point || 12;
-
- useEffect(() => {
- async function fetchPairStats() {
- const result = await getPairStats(pairId);
- if (!result.success) return;
- setPairStats(result.data);
- }
-
- fetchPairStats();
- }, []);
-
- useEffect(() => {
- async function fetchCandles() {
- setCandlesLoaded(false);
- setCandles([]);
- const result = await getCandles(pairId, periodsState.code);
- if (result.success) {
- setCandles(result.data);
- } else {
- setCandles([]);
- }
- setCandlesLoaded(true);
- }
-
- fetchCandles();
- }, [periodsState]);
-
- useEffect(() => {
- async function getPairData() {
- const result = await getPair(pairId);
- if (!result.success) {
- router.push('/404');
- return;
- }
- setPairData(result.data);
- }
-
- getPairData();
- }, []);
-
- async function updateUserOrders() {
setMyOrdersLoading(true);
- const result = await getUserOrdersPage(pairId);
- console.log('result getuserorderspage', result);
- await fetchUser();
-
- if (!result.success) return;
- setUserOrders(result?.data?.orders || []);
- setApplyTips(result?.data?.applyTips || []);
- setMyOrdersLoading(false);
- }
-
- const loggedIn = !!state.wallet?.connected;
-
- useEffect(() => {
- if (!loggedIn) return;
- setUserOrders([]);
- updateUserOrders();
- }, [state.wallet?.connected && state.wallet?.address]);
-
- useEffect(() => {
- updateOrders();
- }, []);
-
- // useEffect(() => {
- // socket.on
- // }, []);
-
- const [priceState, setPriceState] = useState('');
- const [amountState, setAmountState] = useState('');
- const [totalState, setTotalState] = useState('');
-
- const [totalUsd, setTotalUsd] = useState(undefined);
-
- const [priceValid, setPriceValid] = useState(false);
- const [amountValid, setAmountValid] = useState(false);
- const [totalValid, setTotalValid] = useState(false);
-
- const [buySellState, setBuySellState] = useState(buySellValues[0]);
-
- const [rangeInputValue, setRangeInputValue] = useState('50');
-
- useEffect(() => {
- let totalDecimal: Decimal | undefined;
try {
- totalDecimal = new Decimal(totalState);
+ await Promise.all(userOrders.map((order) => cancelOrder(order.id)));
+ await updateUserOrders();
} catch (err) {
- console.log(err);
+ console.error(err);
+ } finally {
+ setMyOrdersLoading(false);
}
-
- const zanoPrice = state.assetsRates.get(pairData?.second_currency?.asset_id || '');
-
- setTotalUsd(zanoPrice && totalDecimal ? totalDecimal.mul(zanoPrice).toFixed(2) : undefined);
- }, [totalState, state.assetsRates, pairData?.second_currency?.asset_id]);
-
- function setPriceFunction(inputValue: string) {
- if (inputValue !== '' && !isPositiveFloatStr(inputValue)) {
- return;
- }
-
- try {
- const value = new Decimal(inputValue || NaN);
-
- if (value.toString().replace('.', '').length > 18) {
- console.log('TOO MANY DECIMALS');
- return;
- }
- } catch (error) {
- console.log(error);
- }
-
- setPriceState(inputValue);
-
- if (!inputValue) {
- setTotalState('');
- setTotalValid(false);
- setPriceValid(false);
- return;
- }
-
- const valueDecimal = new Decimal(inputValue || NaN);
- const amountDecimal = new Decimal(amountState || NaN);
-
- const validationResult = validateTokensInput(inputValue, secondCurrencyDP);
-
- if (!validationResult.valid) {
- setTotalState('');
- setTotalValid(false);
- setPriceValid(false);
- return;
- }
-
- setPriceValid(true);
-
- if (!valueDecimal.isNaN() && !amountDecimal.isNaN() && amountState !== '') {
- const totalDecimal = valueDecimal.mul(amountDecimal);
- setTotalState(totalDecimal.toString());
- const total = totalDecimal.toFixed(secondCurrencyDP);
-
- const totalValidationResult = validateTokensInput(total, secondCurrencyDP);
-
- setTotalValid(totalValidationResult.valid);
- } else {
- setTotalState('');
- setTotalValid(false);
- }
- }
-
- const assets = state.wallet?.connected ? state.wallet?.assets || [] : [];
-
- const balance = assets.find((e) => e.ticker === firstCurrencyName)?.balance;
-
- function setAmountFunction(inputValue: string) {
- if (inputValue !== '' && !isPositiveFloatStr(inputValue)) {
- return;
- }
-
- try {
- const value = new Decimal(inputValue || NaN);
-
- if (value.toString().replace('.', '').length > 18) {
- console.log('TOO MANY DECIMALS');
- return;
- }
- } catch (error) {
- console.log(error);
- }
-
- setAmountState(inputValue);
-
- if (!inputValue) {
- setTotalState('');
- setTotalValid(false);
- setAmountValid(false);
- return;
- }
-
- const value = new Decimal(inputValue || NaN);
- const price = new Decimal(priceState || NaN);
-
- const validationResult = validateTokensInput(
- inputValue,
- pairData?.first_currency.asset_info?.decimal_point || 12,
- );
- console.log(validationResult);
-
- if (!validationResult.valid) {
- setTotalState('');
- setTotalValid(false);
- setAmountValid(false);
- return;
- }
-
- setAmountValid(true);
-
- if (balance) setRangeInputValue(value.div(balance).mul(100).toFixed());
-
- if (!price.isNaN() && !value.isNaN() && priceState !== '') {
- const totalDecimal = value.mul(price);
- setTotalState(totalDecimal.toString());
- const total = totalDecimal.toFixed(secondCurrencyDP);
- const totalValidationResult = validateTokensInput(total, secondCurrencyDP);
-
- setTotalValid(totalValidationResult.valid);
- } else {
- setTotalState('');
- setTotalValid(false);
- }
- }
-
- function setCorrespondingOrder(price: number, amount: number) {
- const priceDecimal = new Decimal(price || 0);
- const amountDecimal = new Decimal(amount || 0);
- const totalDecimal = priceDecimal.mul(amountDecimal);
-
- setPriceFunction(notationToString(priceDecimal.toString()) || '');
- setAmountFunction(notationToString(amountDecimal.toString()) || '');
- setTotalState(notationToString(totalDecimal.toString()) || '');
-
- if (balance) {
- const balanceDecimal = new Decimal(balance);
-
- const percentageDecimal = amountDecimal.div(balanceDecimal).mul(100);
- setRangeInputValue(percentageDecimal.toFixed() || '');
- }
-
- const total = priceDecimal.mul(amountDecimal).toFixed(secondCurrencyDP);
-
- const totalValidationResult = validateTokensInput(
- total,
- pairData?.second_currency.asset_info?.decimal_point || 12,
- );
-
- setTotalValid(totalValidationResult.valid);
- }
-
- function StatItem(props: StatItemProps) {
- const { Img } = props;
-
- return (
-
-
-
![]()
-
{props.title}
-
-
-
{props.value}
- {props.coefficient !== undefined && (
-
= 0
- ? styles.coefficient__green
- : styles.coefficient__red
- }
- >
- {props.coefficient >= 0 ? '+' : ''}
- {props.coefficient?.toFixed(2)}%
-
- )}
-
-
- );
- }
-
- function takeOrderClick(
- event: React.MouseEvent,
- e: PageOrderData,
- ) {
- event.preventDefault();
- setCorrespondingOrder(e.price, e.amount);
- setBuySellState(
- buySellValues.find((e) => e.code !== ordersBuySell.code) || buySellValues[0],
- );
-
- if (!orderFormRef.current) return;
-
- orderFormRef.current.scrollIntoView({ behavior: 'smooth' });
- }
-
- //* * FOR USAGE IN THIS PAGE TABLES ONLY */
- function OrderRowTooltipCell({
- style,
- children,
- sideText,
- sideTextColor,
- }: {
- style?: React.CSSProperties;
- children: string;
- sideText?: string;
- sideTextColor?: string;
- }) {
- const [showTooltip, setShowTooltip] = useState(false);
-
- const tooltipText = `${children}${sideText ? ` ~${sideText}` : ''}`;
-
- const isLongContent = tooltipText.length > 14;
-
- return (
-
- setShowTooltip(true)}
- onMouseLeave={() => setShowTooltip(false)}
- >
- {children}
- {sideText && (
-
- {sideText}
-
- )}
-
- {isLongContent && (
-
- {tooltipText}
-
- )}
- |
- );
- }
-
- function MatrixConnectionBadge({
- userAdress,
- userAlias,
- }: {
- userAdress?: string;
- userAlias?: string;
- }) {
- const [connectionTooltip, setConnectionTooltip] = useState(false);
- return userAdress && hasConnection(userAdress) ? (
- <>
- setConnectionTooltip(true)}
- onMouseLeave={() => setConnectionTooltip(false)}
- style={{ marginTop: '4px', cursor: 'pointer', position: 'relative' }}
- >
-
-
-
- Matrix connection
-
- >
- ) : (
- <>>
- );
- }
-
- function OrdersRow(props: { orderData: PageOrderData; percentage: number }) {
- const e = props?.orderData || {};
- const percentage = props?.percentage;
-
- const totalDecimal = new Decimal(e.left).mul(new Decimal(e.price));
- const totalValue = secondAssetUsdPrice
- ? totalDecimal.mul(secondAssetUsdPrice).toFixed(2)
- : undefined;
-
- const [showTooltip, setShowTooltip] = useState(false);
-
- let sideText: string;
-
- if (!secondAssetUsdPrice) {
- sideText = 'undefined';
- } else {
- const value = secondAssetUsdPrice * e.price;
- sideText = e.price < 0.9 ? `$${value.toFixed(5)}` : `$${value.toFixed(2)}`;
- }
-
- return (
-
- |
- setShowTooltip(true)}
- onMouseLeave={() => setShowTooltip(false)}
- >
- @{cutAddress(e.user?.alias || 'no alias', 12)}
-
-
- {e.isInstant && }
- {/* High volume */}
- {/* */}
-
- {e.user?.alias.length > 12 && (
-
- {e.user?.alias}
-
- )}
- |
-
- {notationToString(e.price)}
-
- {notationToString(e.amount)}
- {notationToString(e.left)}
-
- {notationToString(totalDecimal.toString())}
-
- {/* {localeTimeLeft(now, parseInt(e.expiration_timestamp, 10))} | */}
-
- takeOrderClick(event, e)}
- style={{
- display: 'flex',
- justifyContent: 'center',
- alignItems: 'center',
- width: '18px',
- height: '18px',
- }}
- >
-
-
-
-
- |
-
- );
- }
-
- function MyOrdersRow(props: { orderData: OrderRow }) {
- const e = props?.orderData || {};
- const [cancellingState, setCancellingState] = useState(false);
-
- const totalDecimal = new Decimal(e.left).mul(new Decimal(e.price));
- const totalValue = secondAssetUsdPrice
- ? totalDecimal.mul(secondAssetUsdPrice).toFixed(2)
- : undefined;
-
- const [showTooltip, setShowTooltip] = useState(false);
-
- async function cancelClick(event: React.MouseEvent) {
- event.preventDefault();
-
- setCancellingState(true);
- const result = await cancelOrder(e.id);
-
- setCancellingState(false);
-
- if (!result.success) {
- setAlertState('error');
- setAlertSubtitle('Error while cancelling order');
- setTimeout(() => {
- setAlertState(null);
- setAlertSubtitle('');
- }, 3000);
- return;
- }
-
- await updateOrders();
- await updateUserOrders();
- await fetchUser();
- }
-
- return (
-
- |
- setShowTooltip(true)}
- onMouseLeave={() => setShowTooltip(false)}
- >
- @
- {cutAddress(
- state.wallet?.connected && state.wallet?.alias
- ? state.wallet.alias
- : 'no alias',
- 12,
- )}
-
-
- {e.isInstant && }
- {(state.wallet?.connected && state.wallet?.alias ? state.wallet?.alias : '')
- ?.length > 12 && (
-
- {state.wallet?.connected && state.wallet?.alias}
-
- )}
- {/* High volume */}
- {/* */}
- |
-
- {notationToString(e.price)}
-
- {notationToString(e.amount)}
- {notationToString(e.left)}
-
- {notationToString(totalDecimal.toString())}
-
- {/* {localeTimeLeft(now, parseInt(e.expiration_timestamp, 10))} | */}
-
-
- {applyTips?.filter((tip) => tip.connected_order_id === e.id)?.length || 0}
-
- |
-
-
- {cancellingState ? 'Process' : 'Cancel'}
-
- |
-
- );
- }
-
- function MyOrdersApplyRow(props: { orderData: ApplyTip }) {
- const e = props?.orderData || {};
-
- const [applyingState, setApplyingState] = useState(false);
-
- const connectedOrder = userOrders.find((order) => order.id === e.connected_order_id);
-
- const totalDecimal = new Decimal(e.left).mul(new Decimal(e.price));
- const totalValue = secondAssetUsdPrice
- ? totalDecimal.mul(secondAssetUsdPrice).toFixed(2)
- : undefined;
-
- const [showTooltip, setShowTooltip] = useState(false);
-
- async function applyClick(event: React.MouseEvent) {
- event.preventDefault();
-
- if (e.id) {
- updateAutoClosedNotification(dispatch, [
- ...state.closed_notifications,
- parseInt(e.id, 10),
- ]);
- }
-
- function alertErr(subtitle: string) {
- setAlertState('error');
- setAlertSubtitle(subtitle);
- setTimeout(() => {
- setAlertState(null);
- setAlertSubtitle('');
- }, 3000);
- }
-
- setApplyingState(true);
- interface SwapOperationResult {
- success: boolean;
- message?: string;
- errorCode?: number;
- data?: unknown;
- }
-
- let result: SwapOperationResult | null = null;
-
- await (async () => {
- if (e.transaction) {
- if (!e.hex_raw_proposal) {
- alertErr('Invalid transaction data received');
- return;
- }
-
- console.log(e.hex_raw_proposal);
-
- const confirmSwapResult = await confirmIonicSwap(e.hex_raw_proposal);
-
- console.log(confirmSwapResult);
-
- if (confirmSwapResult.data?.error?.code === -7) {
- alertErr('Insufficient funds');
- return;
- }
- if (!confirmSwapResult.data?.result) {
- alertErr('Companion responded with an error');
- return;
- }
-
- result = await confirmTransaction(e.id);
- } else {
- const firstCurrencyId = pairData?.first_currency.asset_id;
- const secondCurrencyId = pairData?.second_currency.asset_id;
-
- console.log(firstCurrencyId, secondCurrencyId);
-
- if (!(firstCurrencyId && secondCurrencyId)) {
- alertErr('Invalid transaction data received');
- return;
- }
-
- if (!connectedOrder) return;
-
- const leftDecimal = new Decimal(e.left);
- const priceDecimal = new Decimal(e.price);
-
- const params = {
- destinationAssetID: e.type === 'buy' ? secondCurrencyId : firstCurrencyId,
- destinationAssetAmount: notationToString(
- e.type === 'buy'
- ? leftDecimal.mul(priceDecimal).toString()
- : leftDecimal.toString(),
- ),
- currentAssetID: e.type === 'buy' ? firstCurrencyId : secondCurrencyId,
- currentAssetAmount: notationToString(
- e.type === 'buy'
- ? leftDecimal.toString()
- : leftDecimal.mul(priceDecimal).toString(),
- ),
-
- destinationAddress: e.user.address,
- };
-
- console.log(params);
-
- const createSwapResult = await ionicSwap(params);
-
- console.log(createSwapResult);
-
- const hex = createSwapResult?.data?.result?.hex_raw_proposal;
-
- if (createSwapResult?.data?.error?.code === -7) {
- alertErr('Insufficient funds');
- return;
- }
- if (!hex) {
- alertErr('Companion responded with an error');
- return;
- }
-
- result = await applyOrder({
- ...e,
- hex_raw_proposal: hex,
- });
- }
- })();
-
- setApplyingState(false);
-
- if (!result) {
- return;
- }
-
- if (!(result as { success: boolean }).success) {
- alertErr('Server responded with an error');
- return;
- }
-
- await updateOrders();
- await updateUserOrders();
- await fetchUser();
- }
-
- return (
-
- |
- setShowTooltip(true)}
- onMouseLeave={() => setShowTooltip(false)}
- >
- @{cutAddress(e.user.alias, 12) || 'no alias'}
-
-
- {(e.isInstant || e.transaction) && }
-
- {e.user?.alias.length > 12 && (
-
- {e.user?.alias}
-
- )}
- {/* High volume */}
- {/* */}
- |
-
-
- {notationToString(e.price)}
-
- {notationToString(e.left)}
- |
-
- {notationToString(totalDecimal.toString())}
-
- {/* {localeTimeLeft(now, parseInt(e.expiration_timestamp, 10))} | */}
- |
-
-
- {applyingState ? 'Process' : 'Apply'}
-
- |
-
- );
- }
-
- const imgCode =
- pairData && tradingKnownCurrencies.includes(pairData.first_currency?.code)
- ? pairData.first_currency?.code
- : 'tsds';
-
- const coefficient = pairStats?.coefficient || 0;
- const coefficientOutput =
- parseFloat(coefficient?.toFixed(2) || '0') === -100
- ? -99.99
- : parseFloat(coefficient?.toFixed(2) || '0');
-
- const ordersIsBuy = ordersBuySell.code === 'buy';
- const shownOrdersAmount = filteredOrdersHistory.filter(
- (e) => (e.type === 'buy') === ordersIsBuy,
- ).length;
-
- const ordersSummaryFunds = filteredOrdersHistory
- .reduce(
- (acc, e) => acc.add(new Decimal(e.left).mul(new Decimal(e.price)).toNumber()),
- new Decimal(0),
- )
- .toDP(5)
- .toFixed();
-
- const pairRateUsd =
- pairStats?.rate !== undefined && secondAssetUsdPrice !== undefined
- ? new Decimal(pairStats.rate)
- .mul(secondAssetUsdPrice)
- .toFixed(pairStats.rate < 0.1 ? 6 : 2)
- : undefined;
-
- const scrollToOrderList = () => {
- if (!orderListRef.current) return;
-
- orderListRef.current.scrollIntoView({ behavior: 'smooth' });
+ }, [userOrders, updateUserOrders]);
+
+ const { filteredOrdersHistory } = useFilteredData({
+ ordersBuySell,
+ ordersHistory,
+ });
+
+ const onAfter = async () => {
+ await updateOrders();
+ await updateUserOrders();
+ await fetchUser();
+ await fetchTrades();
};
return (
<>
-
-
-
-
-
-
-
-
-
-
-
- {!(
- pairData &&
- pairData.first_currency?.name &&
- pairData.second_currency?.name
- ) ? (
- '...'
- ) : (
- <>
- {firstCurrencyName}
- /{secondCurrencyName}
- >
- )}
-
-
-
- {notationToString(pairStats?.rate || 0)}{' '}
- {secondCurrencyName}
-
- {pairRateUsd && (
- <>
-
-
- ${pairRateUsd}
-
- >
- )}
-
-
-
- {pairData && firstAssetLink && secondAssetLink && (
-
-
- {firstCurrencyName}:{' '}
-
- {shortenAddress(firstAssetId || '')}
-
-
-
- {secondCurrencyName}:{' '}
-
- {shortenAddress(secondAssetId || '')}
-
-
-
- )}
-
-
-
-
-
-
-
-
-
+
-
-
- {InputPanelItem({
- priceState,
- amountState,
- totalState,
- buySellValues,
- buySellState,
- setBuySellState,
- setPriceFunction,
- setAmountFunction,
- setAlertState,
- setAlertSubtitle,
- setRangeInputValue,
- rangeInputValue,
- firstCurrencyName,
- secondCurrencyName,
- balance: Number(balance),
- priceValid,
- amountValid,
- totalValid,
- totalUsd,
- scrollToOrderList,
- updateUserOrders,
- })}
+
+
+
+
+
+
-
-
+
+
+
- undefined}
+ isTab
+ isSm
/>
{candlesLoaded ? (
-
+
) : (
-
+
)}
-
-
-
-
-
-
-
- {ordersBuySell.code === 'buy' ? 'Buy' : 'Sell'} Orders
- {/* {firstCurrencyName && secondCurrencyName ? " - " + firstCurrencyName + "/" + secondCurrencyName : ""} */}
-
-
-
- {firstCurrencyName && secondCurrencyName
- ? `${firstCurrencyName}/${secondCurrencyName}`
- : ''}
-
-
-
-
-
-
- {shownOrdersAmount}{' '}
- {shownOrdersAmount === 1 ? 'order' : 'orders'}
-
-
-
-
- {ordersSummaryFunds} {secondCurrencyName}
-
-
-
-
- {/*
*/}
-
-
-
-
-
-
-
- | Alias |
-
- Price ({secondCurrencyName})
- |
-
- Amount ({firstCurrencyName})
- |
-
- Remaining ({firstCurrencyName})
- |
-
- {' '}
- Total ({secondCurrencyName})
- |
- |
-
-
- {!ordersLoading && !!filteredOrdersHistory.length && (
-
- {filteredOrdersHistory?.map((e) => {
- const maxValue = Math.max(
- ...filteredOrdersHistory.map((order) =>
- parseFloat(String(order.left)),
- ),
- );
- const percentage = (
- (parseFloat(String(e.left)) / maxValue) *
- 100
- ).toFixed(2);
-
- return (
-
- );
- })}
-
- )}
-
-
- {!filteredOrdersHistory.length && !ordersLoading && (
-
-
-
No orders
-
- )}
- {ordersLoading && (
-
- )}
-
-
-
-
-
My Orders
-
-
-
- {applyTips?.length || 0} Offer
- {(applyTips?.length || 0) === 1 ? '' : 's'}
-
-
-
-
-
-
-
-
- | Alias |
-
- Price ({secondCurrencyName})
- |
-
- Amount ({firstCurrencyName})
- |
-
- Remaining ({firstCurrencyName})
- |
-
- Total ({secondCurrencyName})
- |
- Offers |
- |
-
-
-
- {!myOrdersLoading && loggedIn && !!userOrders.length && (
-
-
-
- {userOrders.map((e) => (
-
- ))}
-
-
- {!!applyTips.length && (
-
-
- {applyTips.map((e) => (
-
- ))}
-
-
- )}
-
- )}
-
- {myOrdersLoading && loggedIn && (
-
- )}
-
- {!loggedIn && (
-
-
-
Connect wallet to see your orders
-
- )}
-
- {loggedIn && !userOrders.length && !myOrdersLoading && (
-
-
-
No orders
-
- )}
-
+
+
+
+
{alertState && (
{
- const { first, second } = context.query;
-
- if (!first || !second) {
- return {
- notFound: true, // Show a 404 page if parameters are missing
- };
- }
-
- try {
- const idFound = await findPairID(
- first as string,
- second as string,
- context.req.headers.host as string,
- );
-
- console.log('ID found:', idFound);
-
- if (typeof idFound === 'number') {
- return {
- redirect: {
- destination: `/dex/trading/${idFound}`,
- permanent: false,
- },
- };
- }
-
- return {
- notFound: true,
- };
- } catch (error) {
- console.error('Error fetching pair ID:', error);
- return {
- props: {
- error: 'Failed to resolve the pair.',
- },
- };
- }
-};
-
-export default getServerSideProps;
diff --git a/src/store/store-reducer.tsx b/src/store/store-reducer.tsx
index ee4edff..848ff98 100644
--- a/src/store/store-reducer.tsx
+++ b/src/store/store-reducer.tsx
@@ -10,6 +10,8 @@ const initialState: ContextState = {
offers: 0,
},
closed_notifications: [],
+ alertState: null,
+ alertSubtitle: '',
};
const reducer = (state: ContextState, action: ContextAction): ContextState => {
@@ -31,6 +33,12 @@ const reducer = (state: ContextState, action: ContextAction): ContextState => {
case 'CLOSED_NOTIFICATIONS_UPDATED': {
return { ...state, closed_notifications: action.payload };
}
+ case 'ALERT_STATE_UPDATED': {
+ return { ...state, alertState: action.payload };
+ }
+ case 'ALERT_SUBTITLE_UPDATED': {
+ return { ...state, alertSubtitle: action.payload };
+ }
default:
return { ...state };
}
@@ -40,6 +48,7 @@ export const Store = createContext({
state: initialState,
dispatch: () => undefined,
});
+
export const StoreProvider = (props: { children: ReactNode }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return {props.children};
diff --git a/src/styles/Dex.module.scss b/src/styles/Dex.module.scss
index bbadf08..6478dd5 100644
--- a/src/styles/Dex.module.scss
+++ b/src/styles/Dex.module.scss
@@ -8,7 +8,7 @@
height: 54px;
padding: 0 12px;
- > div {
+ >div {
display: flex;
align-items: center;
gap: 10px;
@@ -136,12 +136,12 @@
width: 240px;
height: 42px;
- > div:nth-child(1) {
+ >div:nth-child(1) {
border-radius: 10px;
padding: 11px 20px;
- > div {
- > div p {
+ >div {
+ >div p {
font-size: 14px;
font-weight: 500;
}
@@ -160,12 +160,12 @@
}
}
- > div:nth-child(2) {
- > div {
- > div {
+ >div:nth-child(2) {
+ >div {
+ >div {
padding: 11px 20px;
- > div {
+ >div {
p {
font-size: 14px;
font-weight: 500;
@@ -233,7 +233,7 @@
gap: 20px;
.input_wrapper {
- padding: 13px;
+ padding-inline: 13px;
max-width: 240px;
max-height: 42px;
display: flex;
@@ -244,7 +244,9 @@
border-radius: 10px;
.input {
- padding: 0;
+ border-radius: 0;
+ padding-inline: 0;
+ padding-block: 13px;
max-width: 185px;
background-color: transparent;
font-size: 14px;
@@ -303,7 +305,7 @@
left: 50%;
transform: translateX(-50%);
- > p {
+ >p {
width: 100%;
font-size: 16px;
text-wrap: wrap;
@@ -321,11 +323,11 @@
}
}
- > p {
+ >p {
margin-right: 6px;
}
- > input {
+ >input {
margin-left: 33px;
height: 18px;
width: 18px;
@@ -387,7 +389,7 @@
left: 50%;
transform: translateX(-50%);
- > p {
+ >p {
width: 100%;
font-size: 16px;
text-wrap: wrap;
@@ -399,14 +401,14 @@
display: block;
}
- > svg > * {
+ >svg>* {
opacity: 1;
}
}
}
}
- > .curve__chart {
+ >.curve__chart {
display: block;
width: 100%;
height: 50px;
@@ -417,7 +419,7 @@
align-items: center;
gap: 15px;
- > div:first-child {
+ >div:first-child {
width: 48px;
height: 48px;
padding: 10px;
@@ -427,13 +429,13 @@
background: var(--icon-bg-color);
border-radius: 50%;
- > img {
+ >img {
width: auto;
height: 100%;
}
}
- > div:last-child {
+ >div:last-child {
height: 48px;
display: flex;
flex-direction: column;
@@ -502,4 +504,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/src/styles/Trading.module.scss b/src/styles/Trading.module.scss
index 270f4eb..4ba0c53 100644
--- a/src/styles/Trading.module.scss
+++ b/src/styles/Trading.module.scss
@@ -1,1107 +1,92 @@
-.main {
+.trading {
+ padding-inline: 60px;
+ padding-top: 16px;
display: flex;
flex-direction: column;
+ gap: 8px;
- @media screen and (max-width: 600px) {
- margin-top: -50px;
+ @media screen and (max-width: 1600px) {
+ padding-inline: 40px;
}
- > :first-child {
- padding-bottom: 40px;
- border-bottom: 1px solid var(--delimiter-color);
+ @media screen and (max-width: 1200px) {
+ padding-inline: 20px;
}
- table {
- .alias {
- display: flex;
- align-items: center;
- gap: 4px;
-
- p {
- font-size: 14px;
- }
-
- path {
- fill: none;
- }
-
- &__tooltip {
- position: absolute;
- top: 30px;
- left: 5%;
- background-color: var(--trade-table-tooltip);
- font-size: 12px;
-
- &_arrow {
- border-radius: 2px;
- left: 50%;
- background-color: var(--trade-table-tooltip);
- }
- }
- }
- }
-
- .trading__title__wrapper {
+ &__top {
+ margin-top: 16px;
display: flex;
- flex-direction: column;
- gap: 25px;
- position: relative;
- border-bottom: 1px solid var(--delimiter-color);
+ gap: 10px;
+ height: 550px;
- .currency__stats__wrapper {
- max-width: 900px;
- display: flex;
- flex-wrap: wrap;
- gap: 20px;
-
- > :nth-child(2),
- :nth-child(4) {
- padding-left: 40px;
- border-left: 1px solid var(--delimiter-color);
- }
-
- .trading__stat__item {
- padding-top: 10px;
- padding-bottom: 10px;
- display: flex;
- flex-direction: column;
- gap: 16px;
- width: 47%;
-
- > div {
- display: flex;
- align-items: center;
-
- p {
- white-space: nowrap;
- }
-
- &:first-child {
- p {
- color: var(--font-dimmed-color);
- }
-
- gap: 6px;
- }
-
- &:last-child {
- gap: 10px;
-
- p:first-child {
- font-weight: 600;
- }
-
- .coefficient__green {
- color: #16d1d6;
- }
-
- .coefficient__red {
- color: #ff6767;
- }
- }
- }
- }
-
- @media screen and (min-width: 1700px) {
- flex-wrap: nowrap;
- gap: 40px;
- position: absolute;
- transform: translateX(-50%);
- left: 54%;
-
- > div {
- width: auto !important;
- }
-
- > :nth-child(3) {
- padding-left: 40px;
- border-left: 1px solid var(--delimiter-color);
- }
- }
-
- @media screen and (max-width: 600px) {
- gap: 0;
- flex-wrap: nowrap;
- flex-direction: column;
-
- > div {
- width: 100% !important;
- padding-left: 0 !important;
- border-left: none !important;
-
- padding: 20px 0 !important;
- border-bottom: 1px solid var(--delimiter-color);
-
- &:last-child {
- border-bottom: none;
- padding-bottom: 0 !important;
- margin-bottom: -20px;
- }
- }
- }
- }
-
- .trading__currency__wrapper {
- display: flex;
- flex-direction: column;
- gap: 15px;
-
- .trading__currency__wrapper_top {
- display: flex;
- align-items: center;
- gap: 16px;
-
- > div:first-child {
- width: 68px;
- height: 68px;
- display: flex;
- align-items: center;
- justify-content: center;
- background-color: var(--icon-bg-color);
- border-radius: 50%;
-
- img {
- width: 40px;
- height: auto;
- }
- }
-
- > div:last-child {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-
- > p:first-child {
- font-size: 40px;
- font-weight: 500;
-
- span {
- font-size: 40px;
- color: var(--font-dimmed-color);
- }
- }
-
- .trading__currency__rate {
- display: flex;
- align-items: center;
- gap: 10px;
-
- > div {
- background-color: var(--font-dimmed-color);
- width: 1px;
- height: 16px;
- }
-
- > p {
- font-weight: 600;
- }
-
- .trading__currency__rate_usd {
- color: var(--font-dimmed-color);
- }
- }
- }
-
- @media screen and (max-width: 400px) {
- > div:first-child {
- width: 48px;
- height: 48px;
-
- > img {
- scale: 0.7;
- }
- }
-
- > div:last-child {
- > p:first-child {
- font-size: 24px;
-
- > span {
- font-size: 24px;
- }
- }
- }
- }
- }
-
- .trading__currency__wrapper_bottom {
- display: flex;
- flex-direction: column;
- gap: 5px;
- }
- }
- }
-
- .trading__top__wrapper {
- display: flex;
- gap: 20px;
- padding-bottom: 40px;
-
- > div:first-child {
- padding: 30px;
- width: 50%;
- margin-top: 25px;
- border-radius: 10px;
- border: 1px solid var(--delimiter-color);
- background: var(--window-bg-color);
- }
-
- @media screen and (max-width: 1000px) {
- flex-direction: column;
-
- > * {
- width: 100% !important;
- }
- }
- }
-
- .trading__chart__wrapper {
- width: 100%;
- overflow: hidden;
- display: flex;
- flex-direction: column;
-
- &.mobile {
- display: none;
- }
-
- .trading__chart__preloader {
+ &_trades {
+ max-width: 415px;
+ width: 100%;
height: 100%;
- min-height: 545px;
}
- .trading__chart__settings {
+ &_chart {
+ width: 100%;
+ overflow: hidden;
display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 25px 0;
- border-bottom: 1px solid var(--delimiter-color);
+ flex-direction: column;
- .trading__chart__dropdown {
- width: 254px;
- }
- }
-
- @media screen and (max-width: 1000px) {
- &.mobile {
- display: flex;
- }
-
- &.desktop {
- display: none;
- }
- }
- }
-
- .trading__info {
- display: flex;
- gap: 40px;
-
- > * {
- width: 100%;
- }
-
- > div {
- padding: 30px;
-
- background: var(--window-bg-color);
- border: 1px solid var(--delimiter-color);
- border-radius: 10px;
-
- > :first-child {
- margin-right: 30px;
- padding-bottom: 20px;
- border-bottom: 1px solid var(--delimiter-color);
- }
-
- > :last-child {
- padding-top: 30px;
- }
- }
-
- .orders__preloader {
- height: 465px;
- padding-right: 30px;
- }
-
- .trading__orders_panel {
- width: 100%;
-
- padding-right: 0;
-
- .orders-panel__header {
- display: flex;
- justify-content: space-between;
- flex-wrap: wrap;
- column-gap: 15px;
- row-gap: 10px;
-
- .orders-panel__header__select {
- overflow: initial;
- }
-
- .orders-panel__header_left {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- column-gap: 10px;
- row-gap: 5px;
-
- .header__delimiter {
- width: 2px;
- height: 18px;
- margin-left: 17px;
- margin-right: 14px;
- background-color: #525e85;
- }
-
- .header__orders_buy,
- .header__orders_sell {
- padding: 6px 12px;
- border-radius: 8px;
-
- > p {
- font-size: 14px;
- font-weight: 400;
- }
- }
-
- .header__orders_buy {
- border: 1px solid #16d1d6;
-
- > p {
- color: #16d1d6;
- }
- }
-
- .header__orders_sell {
- border: 1px solid #ff6767;
-
- > p {
- color: #ff6767;
- }
- }
-
- > div:first-child {
- display: flex;
- align-items: center;
-
- > p {
- font-size: 21px;
- font-weight: 500;
- color: var(--font-dimmed-color);
- }
- }
-
- .header__stats {
- display: flex;
- align-items: center;
- gap: 5px;
-
- .header__summary-funds {
- padding: 6px 12px;
- border: 1px solid var(--font-dimmed-color);
- border-radius: 8px;
-
- > p,
- > p > span {
- font-size: 14px;
- color: var(--font-dimmed-color);
- }
-
- > p {
- display: flex;
- gap: 5px;
- }
-
- > p > span {
- display: inline-block;
- max-width: 70px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- }
- }
- }
-
- @media screen and (max-width: 640px) {
- .orders-panel__header_left {
- > div:first-child {
- > p {
- font-size: 14px;
- }
- }
-
- .header__delimiter {
- margin-left: 12px;
- margin-right: 12px;
- }
- }
- }
- }
-
- > div:last-child {
- display: flex;
- flex-direction: column;
- }
-
- table {
- width: 100%;
- padding-right: 12px;
-
- thead {
- display: flex;
- width: 100%;
- padding-right: 18px;
- margin-bottom: 8px;
-
- tr {
- width: 100%;
- display: flex;
-
- th {
- width: 100%;
- font-size: 12px;
- font-weight: 700;
- text-align: start;
- color: var(--table-th-color);
-
- br {
- display: none;
- }
-
- &:first-child {
- max-width: 180px;
- }
-
- &:last-child {
- max-width: 10px;
- }
- }
- }
- }
-
- tbody {
- height: 465px;
- display: flex;
- flex-direction: column;
- overflow: auto;
- scrollbar-gutter: stable;
- padding-right: 12px;
- padding-bottom: 50px;
-
- tr {
- position: relative;
- width: 100%;
- display: flex;
- padding: 10px 0;
- align-items: center;
-
- &::after {
- content: '';
- pointer-events: none;
- position: absolute;
- z-index: 1;
- right: 0;
- top: 0;
- width: var(--line-width, 0%);
- height: 100%;
- background: #16d1d61a;
- }
-
- &.sell_section {
- &::after {
- background: #ff67671a;
- }
- }
-
- &:not(:last-child) {
- border-bottom: 1px solid var(--delimiter-color);
- }
-
- td {
- flex: 1;
- min-width: 0;
- position: relative;
-
- > p {
- overflow: hidden;
- text-overflow: ellipsis;
- line-height: 1;
- font-size: 14px;
-
- > span {
- margin: 5px;
- line-height: 1;
- vertical-align: middle;
- color: var(--font-dimmed-color);
- font-size: 12px;
- }
- }
-
- &:first-child {
- max-width: 180px;
- display: flex;
- flex-direction: column;
- gap: 3px;
- }
-
- &:last-child {
- text-align: end;
- max-width: 10px;
- margin-right: 10px;
- }
-
- svg:not(.stroked) * {
- fill: transparent;
- }
-
- svg {
- transform: scale(1.2);
- }
-
- .orders_table__buy {
- &:hover {
- svg path {
- stroke: #56c2c6a8;
- }
- }
- }
-
- .orders_table__sell {
- svg {
- path {
- stroke: #ff6767;
- }
- }
-
- &:hover {
- svg path {
- stroke: #ff8585;
- }
- }
- }
- }
- }
- }
- }
- }
-
- .trading__user__orders {
- padding-right: 0;
-
- th {
- br {
- display: none;
- }
- }
-
- > div:first-child {
- margin-right: 30px;
+ .settings {
display: flex;
align-items: center;
- gap: 10px;
+ justify-content: space-between;
- > div {
- padding: 5px 10px;
- background-color: #ff6767;
- border-radius: 100px;
+ &__dropdown {
+ width: 250px;
+ height: 48px;
- > p {
- font-size: 12px;
- font-weight: 700;
- color: #fff;
- }
- }
- }
-
- > div:last-child {
- padding-right: 12px;
- }
-
- table {
- width: 100%;
- padding-right: 33px;
-
- thead {
- display: flex;
- width: 100%;
- padding-left: 15px;
- margin-bottom: 8px;
-
- tr {
- width: 100%;
- display: flex;
-
- th {
- width: 100%;
- font-size: 12px;
- font-weight: 700;
- text-align: start;
- color: var(--table-th-color);
-
- &:first-child {
- max-width: 112px;
- display: flex;
- flex-direction: column;
- gap: 3px;
- }
-
- &:nth-child(3) {
- width: 120%;
- }
-
- &:nth-last-child(2) {
- max-width: 50px;
- }
-
- &:last-child {
- max-width: 80px;
- }
- }
- }
- }
-
- tbody {
- p,
- a {
- font-size: 14px;
- }
- }
- }
-
- .trading__right__tables {
- padding-bottom: 50px;
- scrollbar-gutter: stable;
- padding-right: 12px;
- height: 465px;
- overflow: auto;
-
- table {
- width: 100%;
- padding: 0 15px;
-
- &.trading__apply__table {
- border: 1px solid rgba(31, 143, 235, 1);
- border-radius: 10px;
- background: var(--blur-color);
- }
-
- tbody {
- display: flex;
- flex-direction: column;
-
- > div:first-child {
- padding-left: 15px;
- padding-right: 10px;
- }
-
- .stats__table__incoming {
- padding-left: 15px;
- padding-right: 10px;
- border: 1px solid rgba(31, 143, 235, 1);
- border-radius: 10px;
- background: rgba(255, 255, 255, 0.05);
- }
-
- tr {
- width: 100%;
- display: flex;
- align-items: center;
- padding: 10px 0;
-
- &:not(:last-child) {
- border-bottom: 1px solid var(--delimiter-color);
- }
-
- td {
- width: 100%;
- min-width: 0;
- position: relative;
-
- > p {
- overflow: hidden;
- text-overflow: ellipsis;
- line-height: 1;
-
- > span {
- margin: 5px;
- vertical-align: middle;
- line-height: 1;
- color: var(--font-dimmed-color);
- font-size: 12px;
- margin: 5px;
- }
- }
-
- &:first-child {
- max-width: 112px;
- display: flex;
- flex-direction: column;
- gap: 3px;
- }
-
- &:nth-child(3) {
- width: 120%;
- }
-
- &:nth-last-child(2) {
- max-width: 50px;
- }
-
- &:last-child {
- text-align: end;
- max-width: 80px;
- }
- }
- }
+ @media screen and (max-width: 1360px) {
+ width: 200px;
}
}
}
}
- .orders__message {
+ &_form {
width: 100%;
- height: 465px;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- gap: 20px;
-
- &.all__orders__msg {
- padding-right: 30px;
- }
-
- &.user__orders__msg {
- padding-right: 18px;
- }
-
- @media screen and (max-width: 550px) {
- &.all__orders__msg {
- padding-right: 20px;
- }
-
- &.user__orders__msg {
- padding-right: 13px;
- }
- }
-
- > h6 {
- color: var(--font-dimmed-color);
- }
- }
- }
-
- .table__tooltip {
- position: absolute;
- top: 30px;
- left: 20%;
- transform: translateX(-50%);
- background-color: var(--trade-table-tooltip);
-
- > .table__tooltip_arrow {
- background-color: var(--trade-table-tooltip);
- }
- }
-
- .table__tooltip_right {
- position: absolute;
- top: 30px;
- left: 2%;
- background-color: var(--trade-table-tooltip);
-
- > .table__tooltip_arrow {
- left: 40px;
- background-color: var(--trade-table-tooltip);
- }
- }
-
- .table__tooltip_end {
- position: absolute;
- top: 30px;
- left: -50%;
- background-color: var(--trade-table-tooltip);
-
- > .table__tooltip_arrow {
- border-radius: 2px;
- left: 10%;
- background-color: var(--trade-table-tooltip);
- }
- }
-
- .badge {
- width: fit-content;
- padding: 1px 4px;
- padding-right: 8px;
- display: flex;
- align-items: center;
- gap: 2px;
- border-radius: 100px;
- background: radial-gradient(100% 246.57% at 0% 0%, #a366ff 0%, #601fff 100%);
-
- > img {
- height: 13px;
- width: auto;
- }
-
- > span {
- font-size: 10px;
- font-weight: 600;
- }
-
- &.high {
- padding: 2px 4px;
- background: radial-gradient(100% 188.88% at 0% 0%, #16d1d6 0%, #274cff 100%);
- }
- }
-
- @media screen and (max-width: 1750px) {
- .trading__info {
- flex-direction: column;
-
- > div:last-child {
- width: 100%;
- min-width: 100%;
- }
- }
- }
-
- @media screen and (max-width: 900px) {
- .trading__orders_panel {
- table {
- th,
- td {
- &:nth-child(1) {
- padding-right: 20px;
- }
- }
- }
- }
-
- .trading__user__orders {
- > div:last-child {
- table {
- td,
- th {
- &:first-child {
- display: none;
- }
- }
- }
- }
- }
- }
-
- @media screen and (max-width: 700px) {
- .trading__user__orders {
- table {
- td > a,
- td > p {
- font-size: 14px;
-
- > span {
- display: none;
- }
- }
-
- td,
- th {
- &:nth-last-child(4) {
- display: none;
- }
- }
-
- tbody {
- tr {
- padding: 12px 0 !important;
- }
- }
- }
- }
-
- .trading__orders_panel {
- table {
- td > a,
- td > p {
- font-size: 14px;
-
- > span {
- display: none;
- }
- }
-
- th,
- td {
- &:nth-last-child(3) {
- display: none;
- }
- }
-
- tbody {
- tr {
- padding: 12px 0 !important;
- }
- }
- }
- }
- }
-
- @media screen and (max-width: 600px) {
- .trading__user__orders th br {
- display: block !important;
- }
- }
-
- @media screen and (max-width: 550px) {
- .trading__top__wrapper {
- > div:first-child {
- padding: 20px !important;
- }
- }
-
- .trading__info {
- > div {
- padding: 20px 0;
- }
-
- .trading__user__orders {
- width: 100%;
- min-width: 100%;
- padding: 20px;
- padding-right: 0;
-
- > div:first-child {
- margin-right: 20px;
- }
-
- > div:last-child {
- padding-right: 7px !important;
-
- > table:first-child {
- padding-right: 26px !important;
- }
- }
-
- table td {
- font-size: 14px;
- }
-
- thead {
- padding-left: 10px !important;
-
- th {
- font-size: 11px;
- }
- }
-
- .trading__right__tables {
- padding-right: 7px !important;
-
- table {
- padding: 0 10px !important;
- }
- }
- }
-
- .trading__orders_panel {
- padding-left: 20px !important;
-
- thead {
- padding-right: 13px !important;
- }
-
- > div:first-child {
- margin-right: 20px;
- }
-
- > :last-child {
- flex-direction: column;
- }
-
- > input[type='number'],
- > button {
- padding-top: 13px !important;
- padding-bottom: 13px !important;
- }
-
- > div:first-child {
- h5 {
- span {
- display: none;
- }
- }
- }
-
- table {
- padding-right: 7px !important;
-
- thead {
- tr th br {
- display: block !important;
- }
- }
-
- tbody {
- padding-right: 7px !important;
- }
- }
- }
- }
-
- .trading__chart__wrapper {
- .trading__chart__settings {
- padding-top: 40px;
- flex-direction: column-reverse;
- align-items: flex-start !important;
- gap: 40px;
-
- .trading__chart__dropdown {
- width: 100%;
-
- > div:first-child {
- height: 48px;
- }
- }
- }
- }
- }
-
- @media screen and (max-width: 450px) {
- .trading__info {
- .trading__orders_panel {
- .orders__preloader {
- padding-right: 20px !important;
- }
-
- table {
- td > a,
- td > p,
- th {
- font-size: 11 px;
- }
-
- thead tr th {
- font-size: 9px;
- }
- }
- }
-
- .trading__user__orders {
- table {
- thead tr th {
- font-size: 9px;
- }
-
- tbody {
- td > p,
- td > a {
- font-size: 11px;
- }
- }
- }
- }
+ height: 100%;
+ max-width: 415px;
}
}
}
+
+@media screen and (max-width: 1280px) {
+ .trading__top {
+ gap: 8px;
+
+ &_trades,
+ &_form {
+ max-width: 310px;
+ }
+ }
+}
+
+@media screen and (max-width: 1024px) {
+ .trading__top {
+ &_trades,
+ &_form {
+ max-width: 100%;
+ }
+
+ &_chart {
+ display: none;
+ }
+ }
+}
+
+@media screen and (max-width: 640px) {
+ .trading__top {
+ height: 380px;
+ }
+}
+
+@media screen and (max-width: 580px) {
+ .trading__top {
+ height: 370px;
+ }
+}
diff --git a/src/styles/globals.scss b/src/styles/globals.scss
index 601f3f7..97e3749 100644
--- a/src/styles/globals.scss
+++ b/src/styles/globals.scss
@@ -233,9 +233,8 @@ svg {
.orders-scroll::-webkit-scrollbar {
width: 6px;
-
+ height: 6px;
background-color: transparent;
- background-clip: padding-box;
}
.orders-scroll::-webkit-scrollbar-thumb {
diff --git a/src/styles/themes/dark.scss b/src/styles/themes/dark.scss
new file mode 100644
index 0000000..de9a109
--- /dev/null
+++ b/src/styles/themes/dark.scss
@@ -0,0 +1,59 @@
+[data-theme='dark'] {
+ --main-bg-color: #0c0c3a;
+ --table-header-font-color: rgba(213, 213, 226, 1);
+ --table-header-bg: rgba(36, 36, 78, 1);
+ --table-button-bg-hover: rgba(40, 40, 83, 1);
+ --font-main-color: rgba(255, 255, 255, 1);
+ --font-dimmed-color: rgba(141, 149, 174, 1);
+ --delimiter-color: rgba(255, 255, 255, 0.1);
+ --window-bg-color: rgba(15, 32, 85, 1);
+ --dropdown-bg-color: rgba(17, 49, 107, 1);
+ --dropdown-bg-hover: rgba(29, 59, 114, 1);
+ --profile-widget-avatar: rgba(17, 49, 107, 1);
+ --window-border-color: rgba(255, 255, 255, 0.3);
+ --bordered-input-bg: rgba(255, 255, 255, 0.1);
+ --row-header-bg: #154d91;
+ --button-bordered-hover: rgba(255, 255, 255, 0.1);
+ --alert-bg: rgba(35, 52, 103, 1);
+ --switch-bg-color: rgba(15, 32, 85, 1);
+ --switch-bg-hover: rgba(39, 54, 102, 1);
+ --switch-disabled-bg-color: rgba(255, 255, 255, 0.1);
+ --dimmed-btn-bg: rgba(255, 255, 255, 0.1);
+ --dimmed-btn-hover: rgba(255, 255, 255, 0.3);
+ --font-faded-color: rgba(255, 255, 255, 0.5);
+ --slider-bg-color: #1d3b72;
+ --blur-color: rgba(255, 255, 255, 0.05);
+ --icon-bg-color: #0f1f54;
+ --swap-btn-bg: rgba(31, 143, 235, 0.1);
+ --table-bg-color: rgba(16, 16, 64, 1);
+ --advices-bg-color: rgba(255, 255, 255, 0.1);
+ --messenger-top-bg: #0f2055;
+ --messenger-bottom-bg: #273666;
+ --messenger-bg: #0f2055;
+ --messenger-border: rgba(255, 255, 255, 0.1);
+ --message-bg: rgba(255, 255, 255, 0.1);
+ --custom-message-bg: transparent;
+ --trade-table-tooltip: #1d3b72;
+ --dex-offer-notification: #0f2055;
+ --dex-panel-bg: #0f2055;
+ --dex-panel-tooltip: #273666;
+ --dex-buy-sell-border: #ffffff1a;
+ --dex-input-currency: #39497c;
+ --footer-selected-link: #ffffffcc;
+ --table-th-color: #ffffffb2;
+ --table-thead-bg: #24244e;
+ --table-tbody-bg: #101040;
+ --admin-table-border-color: #596f98;
+ --alert-btn-bg: rgba(31, 143, 235, 0.2);
+ --alert-btn-hover: rgba(31, 143, 235, 0.3);
+ --table-even-bg: #0c1d4f;
+ --table-tr-hover-color: #172a66;
+ --dex-tooltip-bg: #11316b;
+ --dex-tooltip-border-color: #1f8feb26;
+ --dex-sell-percentage: #272757;
+ --dex-buy-percentage: #103262;
+ --action-btn-bg: #273666;
+ --table-group-header-bg: #0c1940;
+ --tab-bg-color: #1f8feb1a;
+ --selector-bg-color: #0c1940;
+}
diff --git a/src/styles/themes/light.scss b/src/styles/themes/light.scss
index b8eee08..8a639d6 100644
--- a/src/styles/themes/light.scss
+++ b/src/styles/themes/light.scss
@@ -46,54 +46,14 @@
--admin-table-border-color: rgba(31, 143, 235, 0.2);
--alert-btn-bg: rgba(31, 143, 235, 0.2);
--alert-btn-hover: rgba(31, 143, 235, 0.3);
-}
-
-[data-theme='dark'] {
- --main-bg-color: #0c0c3a;
- --table-header-font-color: rgba(213, 213, 226, 1);
- --table-header-bg: rgba(36, 36, 78, 1);
- --table-button-bg-hover: rgba(40, 40, 83, 1);
- --font-main-color: rgba(255, 255, 255, 1);
- --font-dimmed-color: rgba(141, 149, 174, 1);
- --delimiter-color: rgba(255, 255, 255, 0.1);
- --window-bg-color: rgba(15, 32, 85, 1);
- --dropdown-bg-color: rgba(17, 49, 107, 1);
- --dropdown-bg-hover: rgba(29, 59, 114, 1);
- --profile-widget-avatar: rgba(17, 49, 107, 1);
- --window-border-color: rgba(255, 255, 255, 0.3);
- --bordered-input-bg: rgba(255, 255, 255, 0.1);
- --row-header-bg: #154d91;
- --button-bordered-hover: rgba(255, 255, 255, 0.1);
- --alert-bg: rgba(35, 52, 103, 1);
- --switch-bg-color: rgba(15, 32, 85, 1);
- --switch-bg-hover: rgba(39, 54, 102, 1);
- --switch-disabled-bg-color: rgba(255, 255, 255, 0.1);
- --dimmed-btn-bg: rgba(255, 255, 255, 0.1);
- --dimmed-btn-hover: rgba(255, 255, 255, 0.3);
- --font-faded-color: rgba(255, 255, 255, 0.5);
- --slider-bg-color: #1d3b72;
- --blur-color: rgba(255, 255, 255, 0.05);
- --icon-bg-color: #0f1f54;
- --swap-btn-bg: rgba(31, 143, 235, 0.1);
- --table-bg-color: rgba(16, 16, 64, 1);
- --advices-bg-color: rgba(255, 255, 255, 0.1);
- --messenger-top-bg: #0f2055;
- --messenger-bottom-bg: #273666;
- --messenger-bg: #0f2055;
- --messenger-border: rgba(255, 255, 255, 0.1);
- --message-bg: rgba(255, 255, 255, 0.1);
- --custom-message-bg: transparent;
- --trade-table-tooltip: #1d3b72;
- --dex-offer-notification: #0f2055;
- --dex-panel-bg: #0f2055;
- --dex-panel-tooltip: #273666;
- --dex-buy-sell-border: #ffffff1a;
- --dex-input-currency: #39497c;
- --footer-selected-link: #ffffffcc;
- --table-th-color: #ffffffb2;
- --table-thead-bg: #24244e;
- --table-tbody-bg: #101040;
- --admin-table-border-color: #596f98;
- --alert-btn-bg: rgba(31, 143, 235, 0.2);
- --alert-btn-hover: rgba(31, 143, 235, 0.3);
+ --table-even-bg: #f2f5f9;
+ --table-tr-hover-color: #dcf0ff;
+ --dex-tooltip-bg: #eff8ff;
+ --dex-tooltip-border-color: #1f8feb33;
+ --dex-sell-percentage: #fceded;
+ --dex-buy-percentage: #e5f8f8;
+ --action-btn-bg: #d0e6f9;
+ --table-group-header-bg: #f2f5f9;
+ --tab-bg-color: #1f8feb;
+ --selector-bg-color: #e7eff8;
}
diff --git a/src/utils/handleInputChange.ts b/src/utils/handleInputChange.ts
new file mode 100644
index 0000000..7a7f35d
--- /dev/null
+++ b/src/utils/handleInputChange.ts
@@ -0,0 +1,94 @@
+import { Dispatch, SetStateAction } from 'react';
+import Decimal from 'decimal.js';
+import { isPositiveFloatStr } from '@/utils/utils';
+import { validateTokensInput } from 'shared/utils';
+
+type SetStr = (_v: string) => void;
+interface HandleInputChangeParams {
+ inputValue: string;
+ priceOrAmount: 'price' | 'amount';
+ otherValue: string;
+ thisDP: number;
+ totalDP: number;
+ setThisState: SetStr;
+ setTotalState: SetStr;
+ setThisValid: Dispatch>;
+ setTotalValid: Dispatch>;
+ balance?: string | undefined;
+ setRangeInputValue?: Dispatch>;
+}
+
+export function handleInputChange({
+ inputValue,
+ priceOrAmount,
+ otherValue,
+ thisDP,
+ totalDP,
+ setThisState,
+ setTotalState,
+ setThisValid,
+ setTotalValid,
+ balance,
+ setRangeInputValue,
+}: HandleInputChangeParams) {
+ if (inputValue !== '' && !isPositiveFloatStr(inputValue)) return;
+
+ const digitsOnly = inputValue.replace('.', '').replace(/^0+/, '');
+ if (digitsOnly.length > 18) return;
+
+ let thisDecimal: Decimal;
+ let otherDecimal: Decimal;
+
+ try {
+ thisDecimal = new Decimal(inputValue || '0');
+ otherDecimal = new Decimal(otherValue || '0');
+ } catch (err) {
+ console.log(err);
+ setThisValid(false);
+ setTotalValid(false);
+ return;
+ }
+
+ setThisState(inputValue);
+
+ if (!inputValue) {
+ setTotalState('');
+ setTotalValid(false);
+ setThisValid(false);
+ return;
+ }
+
+ const isValid = validateTokensInput(inputValue, thisDP);
+ if (!isValid.valid) {
+ setTotalState('');
+ setTotalValid(false);
+ setThisValid(false);
+ return;
+ }
+
+ setThisValid(true);
+
+ if (!thisDecimal.isNaN() && !otherDecimal.isNaN() && otherValue !== '') {
+ const rawTotal =
+ priceOrAmount === 'price'
+ ? thisDecimal.mul(otherDecimal)
+ : otherDecimal.mul(thisDecimal);
+
+ const totalClamped = rawTotal.toDecimalPlaces(totalDP, Decimal.ROUND_DOWN);
+
+ setTotalState(totalClamped.toString());
+
+ const fmtOk = validateTokensInput(totalClamped.toFixed(totalDP), totalDP).valid;
+ const gtZero = totalClamped.gt(0);
+ setTotalValid(fmtOk && gtZero);
+
+ if (priceOrAmount === 'amount' && balance && setRangeInputValue) {
+ const bal = new Decimal(balance || '0');
+ const percent = bal.gt(0) ? thisDecimal.div(bal).mul(100) : new Decimal(0);
+ setRangeInputValue(percent.toFixed());
+ }
+ } else {
+ setTotalState('');
+ setTotalValid(false);
+ }
+}
diff --git a/src/utils/methods.ts b/src/utils/methods.ts
index db63ea0..476bec0 100644
--- a/src/utils/methods.ts
+++ b/src/utils/methods.ts
@@ -320,6 +320,22 @@ export async function getChatChunk(
.then((res) => res.data);
}
+export async function getTrades(pairId: string) {
+ return axios
+ .post(`/api/orders/get-trades`, {
+ pairId,
+ })
+ .then((res) => res.data);
+}
+
+export async function getUserPendings() {
+ return axios
+ .post('/api/transactions/get-my-pending', {
+ token: sessionStorage.getItem('token'),
+ })
+ .then((res) => res.data);
+}
+
export async function getZanoPrice() {
return axios
.get(
@@ -327,3 +343,15 @@ export async function getZanoPrice() {
)
.then((res) => res.data);
}
+
+export async function getMatrixAddresses(addresses: string[]) {
+ try {
+ const { data } = await axios.post('https://messenger.zano.org/api/get-addresses', {
+ addresses,
+ });
+
+ return data;
+ } catch (error) {
+ console.log(error);
+ }
+}
diff --git a/src/utils/takeOrderClick.ts b/src/utils/takeOrderClick.ts
new file mode 100644
index 0000000..e2a081a
--- /dev/null
+++ b/src/utils/takeOrderClick.ts
@@ -0,0 +1,66 @@
+import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
+import { notationToString } from '@/utils/utils';
+import Decimal from 'decimal.js';
+import React from 'react';
+import PairDataType from '@/interfaces/common/PairData';
+import OrderFormOutput from '@/interfaces/common/orderFormOutput';
+import { handleInputChange } from './handleInputChange';
+
+interface takeOrderClickParams {
+ event:
+ | React.MouseEvent
+ | React.MouseEvent;
+ PageOrderData: PageOrderData;
+ pairData: PairDataType | null;
+ orderForm: OrderFormOutput;
+ balance: string | undefined;
+ scrollToOrderForm: () => void;
+}
+
+function takeOrderClick({
+ event,
+ PageOrderData,
+ pairData,
+ orderForm,
+ balance,
+ scrollToOrderForm,
+}: takeOrderClickParams) {
+ event.preventDefault();
+ const e = PageOrderData;
+
+ const priceStr = notationToString(new Decimal(e.price).toString()) || '';
+ const amountStr = notationToString(new Decimal(e.left).toString()) || '';
+
+ const secondCurrencyDP = pairData?.second_currency?.asset_info?.decimal_point || 12;
+ const firstCurrencyDP = pairData?.first_currency?.asset_info?.decimal_point || 12;
+
+ handleInputChange({
+ inputValue: priceStr,
+ priceOrAmount: 'price',
+ otherValue: amountStr,
+ thisDP: secondCurrencyDP,
+ totalDP: secondCurrencyDP,
+ setThisState: orderForm.setPrice,
+ setTotalState: orderForm.setTotal,
+ setThisValid: orderForm.setPriceValid,
+ setTotalValid: orderForm.setTotalValid,
+ });
+
+ handleInputChange({
+ inputValue: amountStr,
+ priceOrAmount: 'amount',
+ otherValue: priceStr,
+ thisDP: firstCurrencyDP,
+ totalDP: secondCurrencyDP,
+ setThisState: orderForm.setAmount,
+ setTotalState: orderForm.setTotal,
+ setThisValid: orderForm.setAmountValid,
+ setTotalValid: orderForm.setTotalValid,
+ balance,
+ setRangeInputValue: orderForm.setRangeInputValue,
+ });
+
+ scrollToOrderForm();
+}
+
+export default takeOrderClick;
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
index deb3643..a41d021 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -86,13 +86,14 @@ export const roundTo = (x: number | string, digits = 7) => {
return fixedValue.replace(/(\.\d*?[1-9])0+$/g, '$1').replace(/\.0+$/, '');
};
-export const notationToString = (notation: number | string) => {
+export const notationToString = (notation: number | string, fixed?: number) => {
const decimalValue = new Decimal(notation || '0');
- const fixedValue = decimalValue.toFixed();
+ if (fixed !== undefined) {
+ return decimalValue.toFixed(fixed).replace(/\.?0+$/, '');
+ }
- // Remove trailing zeros
- return fixedValue;
+ return decimalValue.toFixed();
};
export const localeTimeLeft = (now: number | null, timestamp: number) => {
@@ -133,9 +134,35 @@ export function isPositiveFloatStr(input: string) {
return regExp.test(input);
}
-export function classes(...items: (string | boolean | undefined)[]): string {
+export function formatTime(ts: string | number) {
+ let num = Number(ts);
+
+ if (num < 1e12) num *= 1000;
+ const date = new Date(num);
+
+ if (Number.isNaN(date.getTime())) return '-';
+
+ return date.toLocaleTimeString('ru-RU', { hour12: false });
+}
+
+export function formatTimestamp(ms: number | string) {
+ if (Number.isNaN(Number(ms))) {
+ return 0;
+ }
+
+ const date = new Date(Number(ms));
+ const YYYY = date.getFullYear();
+ const MM = String(date.getMonth() + 1).padStart(2, '0');
+ const DD = String(date.getDate()).padStart(2, '0');
+ const hh = String(date.getHours()).padStart(2, '0');
+ const mm = String(date.getMinutes()).padStart(2, '0');
+ const ss = String(date.getSeconds()).padStart(2, '0');
+ return `${hh}:${mm}:${ss} ${DD}-${MM}-${YYYY}`;
+}
+
+export function classes(...classes: (string | boolean | undefined)[]): string {
// boolean for constructions like [predicate] && [className]
- return items.filter((className) => className).join(' ');
+ return classes.filter((className) => className).join(' ');
}
export const getAssetIcon = (assetId: string): string => {
@@ -147,6 +174,38 @@ export const getAssetIcon = (assetId: string): string => {
return '/tokens/token.png';
};
+type Getters = {
+ getSide: (_item: T) => 'buy' | 'sell';
+ getPrice: (_item: T) => string | number | Decimal;
+};
+
+export function createOrderSorter({ getSide, getPrice }: Getters) {
+ return (a: T, b: T) => {
+ const aSide = getSide(a);
+ const bSide = getSide(b);
+
+ if (aSide !== bSide) {
+ return aSide === 'sell' ? -1 : 1;
+ }
+
+ const ap = new Decimal(getPrice(a));
+ const bp = new Decimal(getPrice(b));
+
+ return bp.comparedTo(ap);
+ };
+}
+
+export function countByKeyRecord(
+ array: T[],
+ keySelector: (_item: T) => string | number,
+): Record {
+ return array.reduce>((acc, item) => {
+ const key = String(keySelector(item));
+ acc[key] = (acc[key] ?? 0) + 1;
+ return acc;
+ }, {});
+}
+
export const ZANO_ASSET_ID = 'd6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a';
const knownCurrencies = ['zano', 'xmr', 'btc', 'firo', 'usd', 'eur', 'cad', 'jpy'];