-
New order
-
+
+
+ {isBuy ? 'Buy' : 'Sell'} {secondCurrencyName}
+
+
+
+ Fee: 0.01 Zano
+
-
+
{LabeledInput({
value: priceState,
setValue: setPriceFunction,
@@ -232,6 +155,7 @@ function InputPanelItem(props: InputPanelItemProps) {
label: 'Price',
invalid: !!priceState && !priceValid,
})}
+
{LabeledInput({
value: amountState,
setValue: setAmountFunction,
@@ -240,7 +164,9 @@ function InputPanelItem(props: InputPanelItemProps) {
label: 'Amount',
invalid: !!amountState && !amountValid,
})}
+
+
{LabeledInput({
value: totalState,
setValue: () => undefined,
@@ -253,20 +179,23 @@ function InputPanelItem(props: InputPanelItemProps) {
})}
{state.wallet?.connected ? (
) : (
-
+
)}
-
);
diff --git a/src/pages/dex/trading/components/InputPanelItem/styles.module.scss b/src/pages/dex/trading/components/InputPanelItem/styles.module.scss
new file mode 100644
index 0000000..bb00386
--- /dev/null
+++ b/src/pages/dex/trading/components/InputPanelItem/styles.module.scss
@@ -0,0 +1,94 @@
+.inputPanel {
+ width: 100%;
+ padding: 15px;
+ background: var(--window-bg-color);
+ border: 1px solid var(--delimiter-color);
+ border-radius: 10px;
+
+ &__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding-bottom: 10px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+ margin-bottom: 10px;
+
+ .title {
+ font-size: 16px;
+ font-weight: 600;
+ }
+ }
+
+ &__fees {
+ color: var(--table-th-color);
+ font-weight: 400;
+ font-size: 12px;
+
+ span {
+ font-weight: 400;
+ font-size: 12px;
+ }
+ }
+
+ &__body {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+
+ &_btn {
+ margin-top: 10px;
+
+ &.buy {
+ background-color: #16d1d6;
+
+ &:hover {
+ background-color: #45dade;
+ }
+ }
+
+ &.sell {
+ background-color: #ff6767;
+
+ &:hover {
+ background-color: #ff8585;
+ }
+ }
+ }
+ }
+}
+
+.applyAlert {
+ display: flex;
+ gap: 20px;
+ align-items: center;
+
+ &__content {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ }
+
+ &__button {
+ max-width: 125px;
+ background-color: var(--alert-btn-bg);
+ color: #1f8feb;
+ padding: 7px 32px;
+ font-size: 12px;
+ font-weight: 500;
+
+ &:hover {
+ background-color: var(--alert-btn-hover);
+ }
+ }
+
+ h2 {
+ font-size: 16px;
+ font-weight: 600;
+ }
+
+ p {
+ font-size: 14px;
+ opacity: 0.7;
+ margin-bottom: 5px;
+ }
+}
diff --git a/src/pages/dex/trading/components/MatrixConnectionBadge/index.tsx b/src/pages/dex/trading/components/MatrixConnectionBadge/index.tsx
new file mode 100644
index 0000000..4839242
--- /dev/null
+++ b/src/pages/dex/trading/components/MatrixConnectionBadge/index.tsx
@@ -0,0 +1,41 @@
+import Tooltip from '@/components/UI/Tooltip/Tooltip';
+import { useState } from 'react';
+import { ReactComponent as ConnectionIcon } from '@/assets/images/UI/connection.svg';
+import styles from './styles.module.scss';
+import { MatrixConnectionBadgeProps } from './types';
+
+function MatrixConnectionBadge({
+ userAdress,
+ userAlias,
+ matrixAddresses,
+}: MatrixConnectionBadgeProps) {
+ const hasConnection = (address: string) =>
+ matrixAddresses.some((item) => item.address === address && item.registered);
+
+ const [connectionTooltip, setConnectionTooltip] = useState(false);
+ return userAdress && hasConnection(userAdress) ? (
+
+ ) : (
+ <>>
+ );
+}
+
+export default MatrixConnectionBadge;
diff --git a/src/pages/dex/trading/components/MatrixConnectionBadge/styles.module.scss b/src/pages/dex/trading/components/MatrixConnectionBadge/styles.module.scss
new file mode 100644
index 0000000..9d64826
--- /dev/null
+++ b/src/pages/dex/trading/components/MatrixConnectionBadge/styles.module.scss
@@ -0,0 +1,28 @@
+.badge {
+ position: relative;
+
+ &__link {
+ margin-top: 4px;
+ cursor: pointer;
+ }
+
+ &__tooltip {
+ position: absolute;
+ top: 30px;
+ left: 50%;
+ transform: translateX(-50%);
+ background-color: var(--trade-table-tooltip);
+ font-size: 12px;
+ z-index: 9999;
+
+ &_text {
+ font-size: 12px !important;
+ }
+
+ &_arrow {
+ border-radius: 2px;
+ left: 50%;
+ background-color: var(--trade-table-tooltip) !important;
+ }
+ }
+}
diff --git a/src/pages/dex/trading/components/MatrixConnectionBadge/types.ts b/src/pages/dex/trading/components/MatrixConnectionBadge/types.ts
new file mode 100644
index 0000000..08f8141
--- /dev/null
+++ b/src/pages/dex/trading/components/MatrixConnectionBadge/types.ts
@@ -0,0 +1,7 @@
+import MatrixAddress from '@/interfaces/common/MatrixAddress';
+
+export interface MatrixConnectionBadgeProps {
+ userAdress?: string;
+ userAlias?: string;
+ matrixAddresses: MatrixAddress[];
+}
diff --git a/src/pages/dex/trading/components/OrderRowTooltipCell/index.tsx b/src/pages/dex/trading/components/OrderRowTooltipCell/index.tsx
new file mode 100644
index 0000000..b584236
--- /dev/null
+++ b/src/pages/dex/trading/components/OrderRowTooltipCell/index.tsx
@@ -0,0 +1,52 @@
+import Tooltip from '@/components/UI/Tooltip/Tooltip';
+import { useState } from 'react';
+import styles from './styles.module.scss';
+import { OrderRowTooltipCellProps } from './types';
+
+function OrderRowTooltipCell({
+ style,
+ children,
+ sideText,
+ sideTextColor,
+ noTooltip,
+}: OrderRowTooltipCellProps) {
+ 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 && !noTooltip && (
+
+ {tooltipText}
+
+ )}
+ |
+ );
+}
+
+export default OrderRowTooltipCell;
diff --git a/src/pages/dex/trading/components/OrderRowTooltipCell/styles.module.scss b/src/pages/dex/trading/components/OrderRowTooltipCell/styles.module.scss
new file mode 100644
index 0000000..099fc8b
--- /dev/null
+++ b/src/pages/dex/trading/components/OrderRowTooltipCell/styles.module.scss
@@ -0,0 +1,28 @@
+.row {
+ position: relative;
+
+ &:last-child {
+ > p {
+ text-align: right;
+ }
+ }
+
+ > p {
+ min-width: 80px;
+ width: 100%;
+ font-size: 12px;
+ font-weight: 400;
+ }
+}
+
+.tooltip {
+ position: absolute;
+ top: 30px;
+ left: 20%;
+ transform: translateX(-50%);
+ background-color: var(--trade-table-tooltip);
+
+ &__arrow {
+ background-color: var(--trade-table-tooltip);
+ }
+}
diff --git a/src/pages/dex/trading/components/OrderRowTooltipCell/types.ts b/src/pages/dex/trading/components/OrderRowTooltipCell/types.ts
new file mode 100644
index 0000000..965bc02
--- /dev/null
+++ b/src/pages/dex/trading/components/OrderRowTooltipCell/types.ts
@@ -0,0 +1,9 @@
+import { ReactNode } from 'react';
+
+export interface OrderRowTooltipCellProps {
+ style?: React.CSSProperties;
+ children: string | ReactNode;
+ sideText?: string;
+ sideTextColor?: string;
+ noTooltip?: boolean;
+}
diff --git a/src/pages/dex/trading/components/OrdersPool/components/OrdersRow/index.tsx b/src/pages/dex/trading/components/OrdersPool/components/OrdersRow/index.tsx
new file mode 100644
index 0000000..a4c3eb7
--- /dev/null
+++ b/src/pages/dex/trading/components/OrdersPool/components/OrdersRow/index.tsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import { classes, notationToString } from '@/utils/utils';
+import { nanoid } from 'nanoid';
+import Decimal from 'decimal.js';
+import styles from './styles.module.scss';
+import { OrdersRowProps } from './types';
+import OrderRowTooltipCell from '../../../OrderRowTooltipCell';
+
+function OrdersRow({
+ orderData,
+ percentage,
+ takeOrderClick,
+ setOrdersInfoTooltip,
+}: OrdersRowProps) {
+ const e = orderData || {};
+
+ const totalDecimal = new Decimal(e.left).mul(new Decimal(e.price));
+
+ return (
+
setOrdersInfoTooltip(e)}
+ onClick={(event) => takeOrderClick(event, e)}
+ className={classes(styles.row, e.type === 'sell' && styles.sell_section)}
+ style={{ '--line-width': `${percentage}%` } as React.CSSProperties}
+ key={nanoid(16)}
+ >
+
+ {notationToString(e.price)}
+
+ {notationToString(e.amount)}
+
+ {notationToString(totalDecimal.toString())}
+
+
+ );
+}
+
+export default OrdersRow;
diff --git a/src/pages/dex/trading/components/OrdersPool/components/OrdersRow/styles.module.scss b/src/pages/dex/trading/components/OrdersPool/components/OrdersRow/styles.module.scss
new file mode 100644
index 0000000..34a925f
--- /dev/null
+++ b/src/pages/dex/trading/components/OrdersPool/components/OrdersRow/styles.module.scss
@@ -0,0 +1,48 @@
+.row {
+ cursor: pointer;
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ padding: 4px 0;
+
+ &:nth-child(even) {
+ background-color: var(--table-even-bg);
+ }
+
+ &::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;
+ }
+ }
+
+ td {
+ position: relative;
+
+ &:last-child {
+ > p {
+ text-align: right;
+ }
+ }
+
+ > p {
+ min-width: 80px;
+ width: 100%;
+ font-size: 12px;
+ font-weight: 400;
+ }
+ }
+}
diff --git a/src/pages/dex/trading/components/OrdersPool/components/OrdersRow/types.ts b/src/pages/dex/trading/components/OrdersPool/components/OrdersRow/types.ts
new file mode 100644
index 0000000..0f7ea0a
--- /dev/null
+++ b/src/pages/dex/trading/components/OrdersPool/components/OrdersRow/types.ts
@@ -0,0 +1,14 @@
+import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
+import { Dispatch, SetStateAction } from 'react';
+
+export interface OrdersRowProps {
+ orderData: PageOrderData;
+ percentage: number;
+ takeOrderClick: (
+ _event:
+ | React.MouseEvent
+ | React.MouseEvent,
+ _e: PageOrderData,
+ ) => void;
+ setOrdersInfoTooltip: Dispatch>;
+}
diff --git a/src/pages/dex/trading/components/OrdersPool/index.tsx b/src/pages/dex/trading/components/OrdersPool/index.tsx
new file mode 100644
index 0000000..194094b
--- /dev/null
+++ b/src/pages/dex/trading/components/OrdersPool/index.tsx
@@ -0,0 +1,198 @@
+import React, { useRef, useState } from 'react';
+import { classes, cutAddress, formatDollarValue, notationToString } from '@/utils/utils';
+import { nanoid } from 'nanoid';
+import Decimal from 'decimal.js';
+import Tooltip from '@/components/UI/Tooltip/Tooltip';
+import ContentPreloader from '@/components/UI/ContentPreloader/ContentPreloader';
+import { buySellValues } from '@/constants';
+import EmptyMessage from '@/components/UI/EmptyMessage';
+import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
+import useMouseLeave from '@/hook/useMouseLeave';
+import OrdersRow from './components/OrdersRow';
+import styles from './styles.module.scss';
+import BadgeStatus from '../BadgeStatus';
+import { OrdersPoolProps } from './types';
+
+const OrdersPool = (props: OrdersPoolProps) => {
+ const {
+ ordersBuySell,
+ setOrdersBuySell,
+ currencyNames,
+ ordersLoading,
+ filteredOrdersHistory,
+ secondAssetUsdPrice,
+ takeOrderClick,
+ } = props;
+ const ordersInfoRef = useRef(null);
+ const { firstCurrencyName, secondCurrencyName } = currencyNames;
+ const [infoTooltipPos, setInfoTooltipPos] = useState({ x: 0, y: 0 });
+ const [ordersInfoTooltip, setOrdersInfoTooltip] = useState(null);
+
+ const moveInfoTooltip = (event: React.MouseEvent) => {
+ setInfoTooltipPos({ x: event.clientX, y: event.clientY });
+ };
+
+ useMouseLeave(ordersInfoRef, () => setOrdersInfoTooltip(null));
+ return (
+ <>
+
+
+
Orders pool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Price ({secondCurrencyName}) |
+ Amount ({firstCurrencyName}) |
+ Total ({secondCurrencyName}) |
+
+
+
+ {!ordersLoading && !!filteredOrdersHistory.length && (
+ setOrdersInfoTooltip(null)}
+ className="orders-scroll"
+ >
+ {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 && (
+
+ )}
+ {ordersLoading &&
}
+
+
+
+ {/* Order tooltip */}
+ {ordersInfoTooltip &&
+ (() => {
+ const totalDecimal = new Decimal(ordersInfoTooltip?.left).mul(
+ new Decimal(ordersInfoTooltip?.price),
+ );
+ const totalValue = secondAssetUsdPrice
+ ? totalDecimal.mul(secondAssetUsdPrice).toFixed(2)
+ : undefined;
+
+ return (
+
+
+
Alias
+
+ @{cutAddress(ordersInfoTooltip?.user?.alias || 'no alias', 12)}{' '}
+ {ordersInfoTooltip?.isInstant && (
+
+ )}
+
+
+
Price ({secondCurrencyName})
+
+ {notationToString(ordersInfoTooltip?.price)}
+
+
+ ~
+ {secondAssetUsdPrice && ordersInfoTooltip?.price !== undefined
+ ? (() => {
+ const total =
+ secondAssetUsdPrice * ordersInfoTooltip.price;
+ const formatted =
+ ordersInfoTooltip.price < 0.9
+ ? `$${total.toFixed(5)}`
+ : `$${total.toFixed(2)}`;
+ return formatted;
+ })()
+ : 'undefined'}
+
+
+
Amount ({firstCurrencyName})
+
{notationToString(ordersInfoTooltip?.amount)}
+
+
Total ({secondCurrencyName})
+
{notationToString(totalDecimal.toString())}
+
+ ~{' '}
+ {totalValue ? `$${formatDollarValue(totalValue)}` : 'undefined'}
+
+
+
+ );
+ })()}
+ >
+ );
+};
+
+export default OrdersPool;
diff --git a/src/pages/dex/trading/components/OrdersPool/styles.module.scss b/src/pages/dex/trading/components/OrdersPool/styles.module.scss
new file mode 100644
index 0000000..d16c375
--- /dev/null
+++ b/src/pages/dex/trading/components/OrdersPool/styles.module.scss
@@ -0,0 +1,151 @@
+.ordersPool {
+ max-width: 415px;
+ width: 100%;
+ padding: 5px;
+ background: var(--window-bg-color);
+ border: 1px solid var(--delimiter-color);
+ border-radius: 10px;
+
+ @media screen and (max-width: 1480px) {
+ max-width: 340px;
+ }
+
+ &__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+ padding: 10px;
+ padding-bottom: 10px;
+ border-bottom: 1px solid var(--delimiter-color);
+
+ &_title {
+ font-size: 18px;
+ font-weight: 600;
+ }
+
+ &_type {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+
+ .btn {
+ cursor: pointer;
+ width: 20px;
+ height: 20px;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: 700;
+ transition: 0.3s opacity ease;
+ color: #ffffff;
+
+ &.selected,
+ &:hover {
+ opacity: 80%;
+ }
+
+ &.all {
+ background: linear-gradient(to left, #ff6767 50%, #16d1d6 50%);
+ }
+
+ &.buy {
+ background-color: #16d1d6;
+ }
+
+ &.sell {
+ background-color: #ff6767;
+ }
+ }
+ }
+ }
+
+ &__content {
+ display: flex;
+ flex-direction: column;
+ padding-top: 10px;
+
+ table {
+ width: 100%;
+
+ thead {
+ display: flex;
+ width: 100%;
+ padding-inline: 10px;
+ margin-bottom: 9px;
+
+ tr {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+
+ th {
+ font-size: 11px;
+ font-weight: 700;
+ text-align: start;
+ color: var(--table-th-color);
+ min-width: 80px;
+
+ &:last-child {
+ text-align: right;
+ }
+ }
+ }
+ }
+
+ tbody {
+ height: 29dvh;
+ min-height: 265px;
+ max-height: 380px;
+ display: flex;
+ flex-direction: column;
+ overflow: auto;
+ padding-bottom: 20px;
+ padding: 10px;
+ }
+ }
+ }
+}
+
+.tooltip {
+ pointer-events: none;
+ position: fixed;
+ border: 1px solid var(--dex-tooltip-border-color);
+ min-width: 140px;
+ max-width: 180px;
+ padding: 10px;
+ transform: translateX(-50%);
+ background-color: var(--dex-tooltip-bg);
+
+ &__arrow {
+ border-top: 1px solid var(--dex-tooltip-border-color);
+ background-color: var(--dex-tooltip-bg) !important;
+ }
+
+ h6 {
+ color: var(--table-th-color);
+ margin-top: 12px;
+ font-size: 11px;
+ font-weight: 700;
+
+ &:first-child {
+ margin-top: 0;
+ }
+ }
+
+ p {
+ font-size: 12px;
+ font-weight: 400;
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ margin-top: 6px;
+ }
+
+ span {
+ margin-top: 5px;
+ display: block;
+ color: #8d95ae;
+ font-size: 11px;
+ font-weight: 400;
+ }
+}
diff --git a/src/pages/dex/trading/components/OrdersPool/types.ts b/src/pages/dex/trading/components/OrdersPool/types.ts
new file mode 100644
index 0000000..c5c5a8b
--- /dev/null
+++ b/src/pages/dex/trading/components/OrdersPool/types.ts
@@ -0,0 +1,21 @@
+import { Dispatch, SetStateAction } from 'react';
+import SelectValue from '@/interfaces/states/pages/dex/trading/InputPanelItem/SelectValue';
+import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
+
+export interface OrdersPoolProps {
+ ordersBuySell: SelectValue;
+ setOrdersBuySell: Dispatch>;
+ currencyNames: {
+ firstCurrencyName: string;
+ secondCurrencyName: string;
+ };
+ ordersLoading: boolean;
+ filteredOrdersHistory: PageOrderData[];
+ secondAssetUsdPrice: number | undefined;
+ takeOrderClick: (
+ _event:
+ | React.MouseEvent
+ | React.MouseEvent,
+ _e: PageOrderData,
+ ) => void;
+}
diff --git a/src/pages/dex/trading/components/StatItem/index.tsx b/src/pages/dex/trading/components/StatItem/index.tsx
new file mode 100644
index 0000000..c14c13c
--- /dev/null
+++ b/src/pages/dex/trading/components/StatItem/index.tsx
@@ -0,0 +1,32 @@
+import StatItemProps from '@/interfaces/props/pages/dex/trading/StatItemProps';
+import { classes } from '@/utils/utils';
+import styles from './styles.module.scss';
+
+function StatItem({ Img, title, value, className, coefficient }: StatItemProps) {
+ return (
+
+
+
![]()
+
{title}
+
+
+
+
{value}
+
+ {coefficient !== undefined && (
+
= 0 ? styles.green : styles.red,
+ )}
+ >
+ {coefficient >= 0 ? '+' : ''}
+ {coefficient?.toFixed(2)}%
+
+ )}
+
+
+ );
+}
+
+export default StatItem;
diff --git a/src/pages/dex/trading/components/StatItem/styles.module.scss b/src/pages/dex/trading/components/StatItem/styles.module.scss
new file mode 100644
index 0000000..2173148
--- /dev/null
+++ b/src/pages/dex/trading/components/StatItem/styles.module.scss
@@ -0,0 +1,44 @@
+.statItem {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+
+ &__nav {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+
+ &_title {
+ color: var(--footer-selected-link);
+ white-space: nowrap;
+ font-size: 14px;
+ font-weight: 700;
+ }
+ }
+
+ &__content {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+
+ &_val {
+ white-space: nowrap;
+ font-size: 14px;
+ font-weight: 400;
+ }
+
+ &_coefficient {
+ white-space: nowrap;
+ font-size: 14px;
+ font-weight: 400;
+
+ &.green {
+ color: #16d1d6;
+ }
+
+ &.red {
+ color: #ff6767;
+ }
+ }
+ }
+}
diff --git a/src/pages/dex/trading/TimeLeft/TimeLeft.tsx b/src/pages/dex/trading/components/TimeLeft/index.tsx
similarity index 100%
rename from src/pages/dex/trading/TimeLeft/TimeLeft.tsx
rename to src/pages/dex/trading/components/TimeLeft/index.tsx
diff --git a/src/pages/dex/trading/components/TradingHeader/components/AssetRow/index.tsx b/src/pages/dex/trading/components/TradingHeader/components/AssetRow/index.tsx
new file mode 100644
index 0000000..dd978c7
--- /dev/null
+++ b/src/pages/dex/trading/components/TradingHeader/components/AssetRow/index.tsx
@@ -0,0 +1,23 @@
+import { shortenAddress } from '@/utils/utils';
+import Link from 'next/link';
+import CurrencyIcon from '../CurrencyIcon';
+import styles from './styles.module.scss';
+import { AssetRowProps } from './types';
+
+const AssetRow = ({ name, link, id, code }: AssetRowProps) => (
+
+
+ {name}:
+
+
+ {shortenAddress(id)}
+
+
+);
+
+export default AssetRow;
diff --git a/src/pages/dex/trading/components/TradingHeader/components/AssetRow/styles.module.scss b/src/pages/dex/trading/components/TradingHeader/components/AssetRow/styles.module.scss
new file mode 100644
index 0000000..15e8a85
--- /dev/null
+++ b/src/pages/dex/trading/components/TradingHeader/components/AssetRow/styles.module.scss
@@ -0,0 +1,19 @@
+.asset {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+
+ &__name {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ font-size: 14px;
+ font-weight: 400;
+ }
+
+ &__address {
+ font-size: 14px;
+ font-weight: 400;
+ }
+}
diff --git a/src/pages/dex/trading/components/TradingHeader/components/AssetRow/types.ts b/src/pages/dex/trading/components/TradingHeader/components/AssetRow/types.ts
new file mode 100644
index 0000000..354ce55
--- /dev/null
+++ b/src/pages/dex/trading/components/TradingHeader/components/AssetRow/types.ts
@@ -0,0 +1,6 @@
+export interface AssetRowProps {
+ name: string;
+ link: string;
+ id: string;
+ code: string | undefined;
+}
diff --git a/src/pages/dex/trading/components/TradingHeader/components/CurrencyIcon/index.tsx b/src/pages/dex/trading/components/TradingHeader/components/CurrencyIcon/index.tsx
new file mode 100644
index 0000000..95e2d80
--- /dev/null
+++ b/src/pages/dex/trading/components/TradingHeader/components/CurrencyIcon/index.tsx
@@ -0,0 +1,8 @@
+import Image from 'next/image';
+import { CurrencyIconProps } from './types';
+
+const CurrencyIcon = ({ code, size = 50 }: CurrencyIconProps) => (
+
+);
+
+export default CurrencyIcon;
diff --git a/src/pages/dex/trading/components/TradingHeader/components/CurrencyIcon/types.ts b/src/pages/dex/trading/components/TradingHeader/components/CurrencyIcon/types.ts
new file mode 100644
index 0000000..75dc2f0
--- /dev/null
+++ b/src/pages/dex/trading/components/TradingHeader/components/CurrencyIcon/types.ts
@@ -0,0 +1,4 @@
+export interface CurrencyIconProps {
+ code: string | undefined;
+ size?: number;
+}
diff --git a/src/pages/dex/trading/components/TradingHeader/index.tsx b/src/pages/dex/trading/components/TradingHeader/index.tsx
new file mode 100644
index 0000000..32d1f47
--- /dev/null
+++ b/src/pages/dex/trading/components/TradingHeader/index.tsx
@@ -0,0 +1,127 @@
+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 BackButton from '@/components/default/BackButton/BackButton';
+import { tradingKnownCurrencies, roundTo, notationToString } from '@/utils/utils';
+import styles from './styles.module.scss';
+import StatItem from '../StatItem';
+import { TradingHeaderProps } from './types';
+import CurrencyIcon from './components/CurrencyIcon';
+import AssetRow from './components/AssetRow';
+
+const getCurrencyCode = (code?: string) =>
+ tradingKnownCurrencies.includes(code || '') ? code : 'tsds';
+
+const TradingHeader = ({
+ pairStats,
+ pairRateUsd,
+ firstAssetLink,
+ secondAssetLink,
+ firstAssetId,
+ secondAssetId,
+ pairData,
+}: TradingHeaderProps) => {
+ const currencyNames = {
+ firstCurrencyName: pairData?.first_currency?.name || '',
+ secondCurrencyName: pairData?.second_currency?.name || '',
+ };
+
+ const { firstCurrencyName, secondCurrencyName } = currencyNames;
+ const imgCode = getCurrencyCode(pairData?.first_currency?.code || '');
+ const imgCode2 = getCurrencyCode(pairData?.second_currency?.code || '');
+
+ const coefficient = pairStats?.coefficient || 0;
+ const coefficientOutput =
+ parseFloat(coefficient?.toFixed(2) || '0') === -100
+ ? -99.99
+ : parseFloat(coefficient?.toFixed(2) || '0');
+
+ const stats = [
+ {
+ Img: ClockIcon,
+ title: '24h change',
+ value: `${roundTo(notationToString(pairStats?.rate || 0), 8)} ${secondCurrencyName}`,
+ coefficient: coefficientOutput,
+ },
+ {
+ Img: UpIcon,
+ title: '24h high',
+ value: `${roundTo(notationToString(pairStats?.high || 0), 8)} ${secondCurrencyName}`,
+ },
+ {
+ Img: DownIcon,
+ title: '24h low',
+ value: `${roundTo(notationToString(pairStats?.low || 0), 8)} ${secondCurrencyName}`,
+ },
+ {
+ Img: VolumeIcon,
+ title: '24h volume',
+ value: `${roundTo(notationToString(pairStats?.volume || 0), 8)} ${secondCurrencyName}`,
+ },
+ ];
+
+ return (
+
+
+
+
+
+
+
+
+ {!pairData ? (
+ '...'
+ ) : (
+ <>
+ {firstCurrencyName}
+ /{secondCurrencyName}
+ >
+ )}
+
+
+
+
+ {notationToString(pairStats?.rate || 0)} {secondCurrencyName}
+
+ {pairRateUsd &&
~ ${pairRateUsd}
}
+
+
+
+
+
+ {pairData && firstAssetLink && secondAssetLink && (
+
+ )}
+
+ {stats.map(({ Img, title, value, coefficient }) => (
+
+ ))}
+
+
+
+
+ );
+};
+
+export default TradingHeader;
diff --git a/src/pages/dex/trading/components/TradingHeader/styles.module.scss b/src/pages/dex/trading/components/TradingHeader/styles.module.scss
new file mode 100644
index 0000000..6a87c1d
--- /dev/null
+++ b/src/pages/dex/trading/components/TradingHeader/styles.module.scss
@@ -0,0 +1,78 @@
+.header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 25px;
+ position: relative;
+ border: none;
+
+ &__currency {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+
+ &_icon {
+ min-width: 48px;
+ min-height: 48px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: var(--icon-bg-color);
+ border-radius: 50%;
+
+ > img {
+ width: 26px;
+ height: auto;
+ }
+ }
+
+ &_item {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+
+ .currencyName {
+ font-size: 18px;
+ font-weight: 600;
+
+ span {
+ color: var(--footer-selected-link);
+ }
+ }
+
+ .price {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+
+ &__secondCurrency {
+ font-weight: 400;
+ font-size: 14px;
+ }
+
+ &__usd {
+ color: var(--footer-selected-link);
+ font-size: 12px;
+ font-weight: 400;
+ }
+ }
+ }
+ }
+
+ &__stats {
+ display: flex;
+ flex-wrap: nowrap;
+ gap: 20px;
+
+ &_assets {
+ display: flex;
+ flex-direction: column;
+ gap: 7px;
+ }
+
+ &_item {
+ padding-left: 20px;
+ border-left: 1px solid var(--delimiter-color);
+ }
+ }
+}
diff --git a/src/pages/dex/trading/components/TradingHeader/types.ts b/src/pages/dex/trading/components/TradingHeader/types.ts
new file mode 100644
index 0000000..9371ec0
--- /dev/null
+++ b/src/pages/dex/trading/components/TradingHeader/types.ts
@@ -0,0 +1,12 @@
+import PairData from '@/interfaces/common/PairData';
+import { PairStats } from '@/interfaces/responses/orders/GetPairStatsRes';
+
+export interface TradingHeaderProps {
+ pairStats: PairStats | null;
+ pairRateUsd: string | undefined;
+ firstAssetLink?: string;
+ secondAssetLink?: string;
+ firstAssetId?: string | null;
+ secondAssetId?: string | null;
+ pairData: PairData | null;
+}
diff --git a/src/pages/dex/trading/components/UserOrders/components/MyOrdersApplyRow/index.tsx b/src/pages/dex/trading/components/UserOrders/components/MyOrdersApplyRow/index.tsx
new file mode 100644
index 0000000..d1b447d
--- /dev/null
+++ b/src/pages/dex/trading/components/UserOrders/components/MyOrdersApplyRow/index.tsx
@@ -0,0 +1,231 @@
+import React, { useContext, useState } from 'react';
+import { cutAddress, formatDollarValue, notationToString } from '@/utils/utils';
+import { nanoid } from 'nanoid';
+import Tooltip from '@/components/UI/Tooltip/Tooltip';
+import Decimal from 'decimal.js';
+import { confirmIonicSwap, ionicSwap } from '@/utils/wallet';
+import { applyOrder, confirmTransaction } from '@/utils/methods';
+import { updateAutoClosedNotification } from '@/store/actions';
+import Link from 'next/link';
+import { Store } from '@/store/store-reducer';
+import { useAlert } from '@/hook/useAlert';
+import OrderRowTooltipCell from '../../../OrderRowTooltipCell';
+import MatrixConnectionBadge from '../../../MatrixConnectionBadge';
+import styles from '../../styles.module.scss';
+import { MyOrdersApplyRowProps } from './types';
+import BadgeStatus from '../../../BadgeStatus';
+
+function MyOrdersApplyRow(props: MyOrdersApplyRowProps) {
+ const {
+ orderData,
+ fetchUser,
+ matrixAddresses,
+ secondAssetUsdPrice,
+ updateOrders,
+ updateUserOrders,
+ fetchTrades,
+ pairData,
+ userOrders,
+ } = props;
+ const e = orderData || {};
+
+ const { state, dispatch } = useContext(Store);
+ const { setAlertState, setAlertSubtitle } = useAlert();
+ 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();
+ await fetchTrades();
+ }
+
+ return (
+
+ |
+
+ setShowTooltip(true)}
+ onMouseLeave={() => setShowTooltip(false)}
+ className={styles.alias__text}
+ >
+ @{cutAddress(e.user.alias, 12) || 'no alias'}
+
+
+
+ {e.isInstant && (
+
+
+
+ )}
+
+
+ {(e.isInstant || e.transaction) && }
+
+ {e.user?.alias.length > 12 && (
+
+ {e.user?.alias}
+
+ )}
+ |
+
+
+ {notationToString(e.price)}
+
+ {notationToString(e.left)}
+
+
+ {notationToString(totalDecimal.toString())}{' '}
+ ~ ${totalValue && formatDollarValue(totalValue)}
+
+
+ |
+
+
+ {applyingState ? 'Process' : 'Apply'}
+
+ |
+
+ );
+}
+
+export default MyOrdersApplyRow;
diff --git a/src/pages/dex/trading/components/UserOrders/components/MyOrdersApplyRow/types.ts b/src/pages/dex/trading/components/UserOrders/components/MyOrdersApplyRow/types.ts
new file mode 100644
index 0000000..bec6f27
--- /dev/null
+++ b/src/pages/dex/trading/components/UserOrders/components/MyOrdersApplyRow/types.ts
@@ -0,0 +1,16 @@
+import ApplyTip from '@/interfaces/common/ApplyTip';
+import MatrixAddress from '@/interfaces/common/MatrixAddress';
+import OrderRow from '@/interfaces/common/OrderRow';
+import PairData from '@/interfaces/common/PairData';
+
+export interface MyOrdersApplyRowProps {
+ orderData: ApplyTip;
+ secondAssetUsdPrice: number | undefined;
+ updateOrders: () => Promise;
+ updateUserOrders: () => Promise;
+ fetchUser: () => Promise;
+ fetchTrades: () => Promise;
+ matrixAddresses: MatrixAddress[];
+ pairData: PairData | null;
+ userOrders: OrderRow[];
+}
diff --git a/src/pages/dex/trading/components/UserOrders/components/MyOrdersRow/index.tsx b/src/pages/dex/trading/components/UserOrders/components/MyOrdersRow/index.tsx
new file mode 100644
index 0000000..f697441
--- /dev/null
+++ b/src/pages/dex/trading/components/UserOrders/components/MyOrdersRow/index.tsx
@@ -0,0 +1,140 @@
+import Decimal from 'decimal.js';
+import { nanoid } from 'nanoid';
+import { useContext, useState } from 'react';
+import { cutAddress, formatDollarValue, notationToString } from '@/utils/utils';
+import Tooltip from '@/components/UI/Tooltip/Tooltip';
+import Link from 'next/link';
+import { cancelOrder } from '@/utils/methods';
+import { Store } from '@/store/store-reducer';
+import { useAlert } from '@/hook/useAlert';
+import BadgeStatus from '../../../BadgeStatus';
+import styles from '../../styles.module.scss';
+import MatrixConnectionBadge from '../../../MatrixConnectionBadge';
+import OrderRowTooltipCell from '../../../OrderRowTooltipCell';
+import { MyOrdersRowProps } from './types';
+
+function MyOrdersRow(props: MyOrdersRowProps) {
+ const {
+ orderData,
+ secondAssetUsdPrice,
+ fetchUser,
+ updateOrders,
+ updateUserOrders,
+ matrixAddresses,
+ applyTips,
+ } = props;
+
+ const e = orderData || {};
+ const { state } = useContext(Store);
+ const { setAlertState, setAlertSubtitle } = useAlert();
+ 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();
+
+ if (cancellingState) return;
+
+ try {
+ setCancellingState(true);
+ const result = await cancelOrder(e.id);
+
+ if (!result.success) {
+ setAlertState('error');
+ setAlertSubtitle('Error while cancelling order');
+ setTimeout(() => {
+ setAlertState(null);
+ setAlertSubtitle('');
+ }, 3000);
+ return;
+ }
+
+ await updateOrders();
+ await updateUserOrders();
+ await fetchUser();
+ } catch (error) {
+ console.log(error);
+ } finally {
+ setCancellingState(false);
+ }
+ }
+
+ return (
+
+ |
+
+ setShowTooltip(true)}
+ onMouseLeave={() => setShowTooltip(false)}
+ className={styles.alias__text}
+ >
+ @
+ {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}
+
+
+ )}
+ |
+
+
+ {notationToString(e.price)}
+
+
+ {notationToString(e.amount)}
+
+
+ {notationToString(totalDecimal.toString())}{' '}
+ ~ ${totalValue && formatDollarValue(totalValue)}
+
+
+
+
+ {applyTips?.filter((tip) => tip.connected_order_id === e.id)?.length || 0}
+
+ |
+
+
+ {cancellingState ? 'Process' : 'Cancel'}
+
+ |
+
+ );
+}
+
+export default MyOrdersRow;
diff --git a/src/pages/dex/trading/components/UserOrders/components/MyOrdersRow/types.ts b/src/pages/dex/trading/components/UserOrders/components/MyOrdersRow/types.ts
new file mode 100644
index 0000000..9bd8026
--- /dev/null
+++ b/src/pages/dex/trading/components/UserOrders/components/MyOrdersRow/types.ts
@@ -0,0 +1,13 @@
+import ApplyTip from '@/interfaces/common/ApplyTip';
+import MatrixAddress from '@/interfaces/common/MatrixAddress';
+import OrderRow from '@/interfaces/common/OrderRow';
+
+export interface MyOrdersRowProps {
+ orderData: OrderRow;
+ secondAssetUsdPrice: number | undefined;
+ updateOrders: () => Promise;
+ updateUserOrders: () => Promise;
+ fetchUser: () => Promise;
+ matrixAddresses: MatrixAddress[];
+ applyTips: ApplyTip[];
+}
diff --git a/src/pages/dex/trading/components/UserOrders/index.tsx b/src/pages/dex/trading/components/UserOrders/index.tsx
new file mode 100644
index 0000000..e580296
--- /dev/null
+++ b/src/pages/dex/trading/components/UserOrders/index.tsx
@@ -0,0 +1,133 @@
+import { classes } from '@/utils/utils';
+import ContentPreloader from '@/components/UI/ContentPreloader/ContentPreloader';
+import useUpdateUser from '@/hook/useUpdateUser';
+import EmptyMessage from '@/components/UI/EmptyMessage';
+import styles from './styles.module.scss';
+import { UserOrdersProps } from './types';
+import MyOrdersRow from './components/MyOrdersRow';
+import MyOrdersApplyRow from './components/MyOrdersApplyRow';
+
+const UserOrders = ({
+ userOrders,
+ applyTips,
+ myOrdersLoading,
+ loggedIn,
+ ordersType,
+ setOrdersType,
+ handleCancelAllOrders,
+ orderListRef,
+ matrixAddresses,
+ secondAssetUsdPrice,
+ updateOrders,
+ updateUserOrders,
+ fetchTrades,
+ pairData,
+}: UserOrdersProps) => {
+ const fetchUser = useUpdateUser();
+ const firstCurrencyName = pairData?.first_currency?.name || '';
+ const secondCurrencyName = pairData?.second_currency?.name || '';
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Alias |
+ Price ({secondCurrencyName}) |
+ Amount ({firstCurrencyName}) |
+ Total ({secondCurrencyName}) |
+ Offers |
+ |
+
+
+
+
+ {!myOrdersLoading && loggedIn && !!userOrders.length && (
+
+
+
+ {userOrders.map((e) => (
+
+ ))}
+
+
+
+ {!!applyTips.length && (
+
+
+ {applyTips.map((e) => (
+
+ ))}
+
+
+ )}
+
+ )}
+
+ {myOrdersLoading && loggedIn &&
}
+
+ {!loggedIn &&
}
+
+ {loggedIn && !userOrders.length && !myOrdersLoading && (
+
+ )}
+
+
+ );
+};
+
+export default UserOrders;
diff --git a/src/pages/dex/trading/components/UserOrders/styles.module.scss b/src/pages/dex/trading/components/UserOrders/styles.module.scss
new file mode 100644
index 0000000..cb2a2c5
--- /dev/null
+++ b/src/pages/dex/trading/components/UserOrders/styles.module.scss
@@ -0,0 +1,227 @@
+.userOrders {
+ width: 100%;
+ padding: 5px;
+ background: var(--window-bg-color);
+ border: 1px solid var(--delimiter-color);
+ border-radius: 10px;
+
+ @media screen and (max-width: 1440px) {
+ width: 520px;
+ }
+
+ &__header {
+ border-bottom: 1px solid var(--delimiter-color);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ position: relative;
+ padding: 10px;
+ padding-bottom: 0;
+
+ &_nav {
+ display: flex;
+ align-items: center;
+ gap: 22px;
+
+ .navItem {
+ padding-bottom: 7px;
+ position: relative;
+ border-top-left-radius: 10px;
+ border-top-right-radius: 10px;
+ font-size: 16px;
+ border-bottom: 2px solid transparent;
+ font-weight: 600;
+ background-color: transparent;
+ cursor: pointer;
+
+ span {
+ top: -10px;
+ right: -15px;
+ position: absolute;
+ display: grid;
+ place-content: center;
+ color: #fff;
+ background-color: #ff6767;
+ width: 15px;
+ height: 15px;
+ font-size: 10px;
+ font-weight: 700;
+ border-radius: 50%;
+ }
+
+ &.active {
+ border-color: #1f8feb;
+ }
+
+ &:hover {
+ color: #1f8feb;
+ }
+ }
+ }
+
+ &_btn {
+ position: absolute;
+ right: 5px;
+ top: 5px;
+ z-index: 10;
+ cursor: pointer;
+ background-color: #1f8feb33;
+ color: #1f8feb;
+ font-size: 14px;
+ font-weight: 500;
+ padding: 6px 10px;
+ border-radius: 8px;
+
+ &:hover {
+ background-color: #1f8feb43;
+ }
+ }
+ }
+
+ table {
+ width: 100%;
+
+ thead {
+ display: flex;
+ width: 100%;
+ padding-inline: 10px;
+ padding-bottom: 5px;
+ margin-top: 10px;
+
+ tr {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+
+ th {
+ min-width: 100px;
+ font-size: 11px;
+ font-weight: 700;
+ text-align: left;
+ color: var(--table-th-color);
+
+ &:last-child {
+ text-align: right;
+ min-width: 50px;
+ }
+ }
+ }
+ }
+
+ tbody {
+ a {
+ display: block;
+ text-align: right;
+ font-size: 12px;
+ font-weight: 400;
+ }
+ }
+ }
+
+ &__body {
+ padding: 10px;
+ padding-bottom: 20px;
+ height: 300px;
+ overflow: auto;
+
+ table {
+ width: 100%;
+
+ &.apply {
+ border-top: 1px solid #1f8feb40;
+ border-bottom: 1px solid #1f8feb40;
+ background-color: var(--blur-color) !important;
+
+ tr {
+ &:not(:last-child) {
+ border-bottom: 1px solid var(--delimiter-color);
+ }
+ }
+ }
+
+ tbody {
+ display: flex;
+ flex-direction: column;
+
+ &.incoming {
+ tr {
+ &:nth-child(even) {
+ background-color: var(--table-even-bg);
+ }
+ }
+ }
+
+ tr {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ padding: 4px 0;
+
+ td {
+ position: relative;
+ min-width: 100px;
+
+ &:last-child {
+ min-width: 50px;
+ }
+
+ @media screen and (max-width: 1440px) {
+ min-width: 0;
+
+ &:last-child {
+ min-width: 0;
+ }
+ }
+
+ > p {
+ width: 100%;
+ font-size: 12px;
+ font-weight: 400;
+
+ > span {
+ line-height: 1;
+ color: var(--font-dimmed-color);
+ font-size: 11px;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+.alias {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 14px;
+
+ &__text {
+ color: var(--font-main-color) !important;
+ }
+
+ path {
+ fill: none;
+ }
+}
+
+.tooltip {
+ position: absolute;
+ top: 30px;
+ left: 5%;
+ background-color: var(--trade-table-tooltip);
+
+ z-index: 9999;
+
+ &__text {
+ font-size: 12px !important;
+ }
+
+ &__arrow {
+ border-radius: 2px;
+ left: 30% !important;
+ background-color: var(--trade-table-tooltip) !important;
+ }
+}
diff --git a/src/pages/dex/trading/components/UserOrders/types.ts b/src/pages/dex/trading/components/UserOrders/types.ts
new file mode 100644
index 0000000..b67eb69
--- /dev/null
+++ b/src/pages/dex/trading/components/UserOrders/types.ts
@@ -0,0 +1,22 @@
+import ApplyTip from '@/interfaces/common/ApplyTip';
+import MatrixAddress from '@/interfaces/common/MatrixAddress';
+import OrderRow from '@/interfaces/common/OrderRow';
+import PairData from '@/interfaces/common/PairData';
+import { Dispatch, ForwardedRef, SetStateAction } from 'react';
+
+export interface UserOrdersProps {
+ orderListRef: ForwardedRef;
+ userOrders: OrderRow[];
+ applyTips: ApplyTip[];
+ myOrdersLoading: boolean;
+ loggedIn: boolean;
+ ordersType: 'opened' | 'history';
+ setOrdersType: Dispatch>;
+ handleCancelAllOrders: () => void;
+ secondAssetUsdPrice: number | undefined;
+ updateOrders: () => Promise;
+ updateUserOrders: () => Promise;
+ fetchTrades: () => Promise;
+ matrixAddresses: MatrixAddress[];
+ pairData: PairData | null;
+}
diff --git a/src/pages/dex/trading/find-pair/index.tsx b/src/pages/dex/trading/find-pair/index.tsx
deleted file mode 100644
index 0a7149d..0000000
--- a/src/pages/dex/trading/find-pair/index.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { findPairID } from '@/utils/methods';
-import { GetServerSideProps } from 'next';
-
-const getServerSideProps: GetServerSideProps = async (context) => {
- 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/pages/dex/trading/helpers/handleInputChange.ts b/src/pages/dex/trading/helpers/handleInputChange.ts
new file mode 100644
index 0000000..ee32ed3
--- /dev/null
+++ b/src/pages/dex/trading/helpers/handleInputChange.ts
@@ -0,0 +1,89 @@
+import { Dispatch, SetStateAction } from 'react';
+import Decimal from 'decimal.js';
+import { isPositiveFloatStr } from '@/utils/utils';
+import { validateTokensInput } from 'shared/utils';
+
+interface HandleInputChangeParams {
+ inputValue: string;
+ priceOrAmount: 'price' | 'amount';
+ otherValue: string;
+ thisDP: number;
+ totalDP: number;
+ setThisState: Dispatch>;
+ setTotalState: Dispatch>;
+ 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 total =
+ priceOrAmount === 'price'
+ ? thisDecimal.mul(otherDecimal)
+ : otherDecimal.mul(thisDecimal);
+
+ setTotalState(total.toString());
+
+ const totalValid = validateTokensInput(total.toFixed(totalDP), totalDP);
+ setTotalValid(totalValid.valid);
+
+ if (priceOrAmount === 'amount' && balance && setRangeInputValue) {
+ const percent = thisDecimal.div(balance).mul(100);
+ setRangeInputValue(percent.toFixed());
+ }
+ } else {
+ setTotalState('');
+ setTotalValid(false);
+ }
+}
diff --git a/src/pages/dex/trading/helpers/takeOrderClick.ts b/src/pages/dex/trading/helpers/takeOrderClick.ts
new file mode 100644
index 0000000..d80fdfe
--- /dev/null
+++ b/src/pages/dex/trading/helpers/takeOrderClick.ts
@@ -0,0 +1,96 @@
+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;
+ buyForm: OrderFormOutput;
+ sellForm: OrderFormOutput;
+ balance: string | undefined;
+ scrollToOrderForm: () => void;
+}
+
+function takeOrderClick({
+ event,
+ PageOrderData,
+ pairData,
+ buyForm,
+ sellForm,
+ balance,
+ scrollToOrderForm,
+}: takeOrderClickParams) {
+ event.preventDefault();
+ const e = PageOrderData;
+
+ const priceStr = notationToString(new Decimal(e.price).toString()) || '';
+ const amountStr = notationToString(new Decimal(e.amount).toString()) || '';
+
+ const secondCurrencyDP = pairData?.second_currency?.asset_info?.decimal_point || 12;
+ const firstCurrencyDP = pairData?.first_currency?.asset_info?.decimal_point || 12;
+
+ if (e.type === 'sell') {
+ handleInputChange({
+ inputValue: priceStr,
+ priceOrAmount: 'price',
+ otherValue: amountStr,
+ thisDP: secondCurrencyDP,
+ totalDP: secondCurrencyDP,
+ setThisState: buyForm.setPrice,
+ setTotalState: buyForm.setTotal,
+ setThisValid: buyForm.setPriceValid,
+ setTotalValid: buyForm.setTotalValid,
+ });
+
+ handleInputChange({
+ inputValue: amountStr,
+ priceOrAmount: 'amount',
+ otherValue: priceStr,
+ thisDP: firstCurrencyDP,
+ totalDP: secondCurrencyDP,
+ setThisState: buyForm.setAmount,
+ setTotalState: buyForm.setTotal,
+ setThisValid: buyForm.setAmountValid,
+ setTotalValid: buyForm.setTotalValid,
+ balance,
+ setRangeInputValue: buyForm.setRangeInputValue,
+ });
+ } else {
+ handleInputChange({
+ inputValue: priceStr,
+ priceOrAmount: 'price',
+ otherValue: amountStr,
+ thisDP: secondCurrencyDP,
+ totalDP: secondCurrencyDP,
+ setThisState: sellForm.setPrice,
+ setTotalState: sellForm.setTotal,
+ setThisValid: sellForm.setPriceValid,
+ setTotalValid: sellForm.setTotalValid,
+ });
+
+ handleInputChange({
+ inputValue: amountStr,
+ priceOrAmount: 'amount',
+ otherValue: priceStr,
+ thisDP: firstCurrencyDP,
+ totalDP: secondCurrencyDP,
+ setThisState: sellForm.setAmount,
+ setTotalState: sellForm.setTotal,
+ setThisValid: sellForm.setAmountValid,
+ setTotalValid: sellForm.setTotalValid,
+ balance,
+ setRangeInputValue: sellForm.setRangeInputValue,
+ });
+ }
+
+ scrollToOrderForm();
+}
+
+export default takeOrderClick;
diff --git a/src/pages/dex/trading/hooks/useFilteredData.ts b/src/pages/dex/trading/hooks/useFilteredData.ts
new file mode 100644
index 0000000..43b3122
--- /dev/null
+++ b/src/pages/dex/trading/hooks/useFilteredData.ts
@@ -0,0 +1,47 @@
+import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
+import { Trade } from '@/interfaces/responses/trades/GetTradeRes';
+import SelectValue from '@/interfaces/states/pages/dex/trading/InputPanelItem/SelectValue';
+import { Store } from '@/store/store-reducer';
+import { useContext } from 'react';
+
+interface useFilteredDataParams {
+ trades: Trade[];
+ ordersHistory: PageOrderData[];
+ ordersBuySell: SelectValue;
+ tradesType: 'all' | 'my';
+}
+
+const useFilteredData = ({
+ ordersHistory,
+ trades,
+ ordersBuySell,
+ tradesType,
+}: useFilteredDataParams) => {
+ const { state } = useContext(Store);
+
+ const filteredTrades =
+ tradesType === 'my'
+ ? trades.filter(
+ (trade) =>
+ trade.buyer.address === state.wallet?.address ||
+ trade.seller.address === state.wallet?.address,
+ )
+ : trades;
+
+ const filteredOrdersHistory = ordersHistory
+ ?.filter((e) => (ordersBuySell.code === 'all' ? 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());
+ });
+
+ return {
+ filteredOrdersHistory,
+ filteredTrades,
+ };
+};
+
+export default useFilteredData;
diff --git a/src/pages/dex/trading/hooks/useMatrixAddresses.ts b/src/pages/dex/trading/hooks/useMatrixAddresses.ts
new file mode 100644
index 0000000..eb03242
--- /dev/null
+++ b/src/pages/dex/trading/hooks/useMatrixAddresses.ts
@@ -0,0 +1,25 @@
+import MatrixAddress from '@/interfaces/common/MatrixAddress';
+import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
+import { getMatrixAddresses } from '@/utils/methods';
+import { useEffect, useState } from 'react';
+
+const useMatrixAddresses = (ordersHistory: PageOrderData[]) => {
+ const [matrixAddresses, setMatrixAddresses] = useState([]);
+
+ useEffect(() => {
+ const fetchConnections = async () => {
+ const filteredAddresses = ordersHistory?.map((e) => e?.user?.address);
+ if (!filteredAddresses.length) return;
+
+ const data = await getMatrixAddresses(filteredAddresses);
+
+ setMatrixAddresses(data.addresses);
+ };
+
+ fetchConnections();
+ }, [ordersHistory]);
+
+ return matrixAddresses;
+};
+
+export default useMatrixAddresses;
diff --git a/src/pages/dex/trading/hooks/useOrdereForm.ts b/src/pages/dex/trading/hooks/useOrdereForm.ts
new file mode 100644
index 0000000..902b6d9
--- /dev/null
+++ b/src/pages/dex/trading/hooks/useOrdereForm.ts
@@ -0,0 +1,104 @@
+import { useState, useEffect } from 'react';
+import Decimal from 'decimal.js';
+import PairData from '@/interfaces/common/PairData';
+import OrderFormOutput from '@/interfaces/common/orderFormOutput';
+import { handleInputChange } from '../helpers/handleInputChange';
+
+interface UseOrderFormParams {
+ type: 'buy' | 'sell';
+ pairData: PairData | null;
+ balance: string | undefined;
+ assetsRates: Map;
+}
+
+export function useOrderForm({
+ type,
+ pairData,
+ balance,
+ assetsRates,
+}: UseOrderFormParams): OrderFormOutput {
+ const [price, setPrice] = useState('');
+ const [amount, setAmount] = useState('');
+ const [total, setTotal] = useState('');
+
+ const [priceValid, setPriceValid] = useState(false);
+ const [amountValid, setAmountValid] = useState(false);
+ const [totalValid, setTotalValid] = useState(false);
+
+ const [totalUsd, setTotalUsd] = useState(undefined);
+ const [rangeInputValue, setRangeInputValue] = useState('50');
+
+ const priceDP = pairData?.second_currency?.asset_info?.decimal_point || 12;
+ const amountDP = pairData?.first_currency?.asset_info?.decimal_point || 12;
+
+ useEffect(() => {
+ try {
+ const totalDecimal = new Decimal(total);
+ const zanoPrice = assetsRates.get(pairData?.second_currency?.asset_id || '');
+ setTotalUsd(zanoPrice ? totalDecimal.mul(zanoPrice).toFixed(2) : undefined);
+ } catch (err) {
+ setTotalUsd(undefined);
+ }
+ }, [total, assetsRates, pairData?.second_currency?.asset_id]);
+
+ function onPriceChange(inputValue: string) {
+ handleInputChange({
+ inputValue,
+ priceOrAmount: 'price',
+ otherValue: amount,
+ thisDP: priceDP,
+ totalDP: priceDP,
+ setThisState: setPrice,
+ setTotalState: setTotal,
+ setThisValid: setPriceValid,
+ setTotalValid,
+ });
+ }
+
+ function onAmountChange(inputValue: string) {
+ handleInputChange({
+ inputValue,
+ priceOrAmount: 'amount',
+ otherValue: price,
+ thisDP: amountDP,
+ totalDP: priceDP,
+ setThisState: setAmount,
+ setTotalState: setTotal,
+ setThisValid: setAmountValid,
+ setTotalValid,
+ balance,
+ setRangeInputValue,
+ });
+ }
+
+ function resetForm() {
+ setPrice('');
+ setAmount('');
+ setTotal('');
+ setPriceValid(false);
+ setAmountValid(false);
+ setTotalValid(false);
+ setRangeInputValue('50');
+ }
+
+ return {
+ price,
+ amount,
+ total,
+ priceValid,
+ amountValid,
+ totalValid,
+ totalUsd,
+ rangeInputValue,
+ setRangeInputValue,
+ onPriceChange,
+ onAmountChange,
+ resetForm,
+ setTotal,
+ setPrice,
+ setAmount,
+ setPriceValid,
+ setAmountValid,
+ setTotalValid,
+ };
+}
diff --git a/src/pages/dex/trading/hooks/useSocketListeners.ts b/src/pages/dex/trading/hooks/useSocketListeners.ts
new file mode 100644
index 0000000..8ee0514
--- /dev/null
+++ b/src/pages/dex/trading/hooks/useSocketListeners.ts
@@ -0,0 +1,85 @@
+import ApplyTip from '@/interfaces/common/ApplyTip';
+import OrderRow from '@/interfaces/common/OrderRow';
+import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
+import { PairStats } from '@/interfaces/responses/orders/GetPairStatsRes';
+import { getUserOrdersPage } from '@/utils/methods';
+import socket from '@/utils/socket';
+import { useRouter } from 'next/router';
+import { Dispatch, SetStateAction, useEffect } from 'react';
+
+interface useSocketListenersParams {
+ setUserOrders: Dispatch>;
+ setApplyTips: Dispatch>;
+ setPairStats: Dispatch>;
+ setOrdersHistory: Dispatch>;
+ ordersHistory: PageOrderData[];
+ updateOrders: () => Promise;
+}
+
+export const useSocketListeners = ({
+ setUserOrders,
+ setApplyTips,
+ setPairStats,
+ setOrdersHistory,
+ ordersHistory,
+ updateOrders,
+}: useSocketListenersParams) => {
+ const router = useRouter();
+ const pairId = typeof router.query.id === 'string' ? router.query.id : '';
+
+ 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');
+ };
+ }, []);
+};
diff --git a/src/pages/dex/trading/hooks/useTradeInit.ts b/src/pages/dex/trading/hooks/useTradeInit.ts
new file mode 100644
index 0000000..4b5dc9b
--- /dev/null
+++ b/src/pages/dex/trading/hooks/useTradeInit.ts
@@ -0,0 +1,70 @@
+import PairData from '@/interfaces/common/PairData';
+import { Store } from '@/store/store-reducer';
+import { useContext } from 'react';
+import Decimal from 'decimal.js';
+import { PairStats } from '@/interfaces/responses/orders/GetPairStatsRes';
+import { useOrderForm } from './useOrdereForm';
+
+interface useTradeInitParams {
+ pairData: PairData | null;
+ pairStats: PairStats | null;
+}
+
+const useTradeInit = ({ pairData, pairStats }: useTradeInitParams) => {
+ const { state } = useContext(Store);
+
+ const currencyNames = {
+ firstCurrencyName: pairData?.first_currency?.name || '',
+ secondCurrencyName: pairData?.second_currency?.name || '',
+ };
+ const loggedIn = !!state.wallet?.connected;
+
+ const assets = state.wallet?.connected ? state.wallet?.assets || [] : [];
+ const balance = assets.find((e) => e.ticker === currencyNames.firstCurrencyName)?.balance;
+
+ 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 pairRateUsd =
+ pairStats?.rate !== undefined && secondAssetUsdPrice !== undefined
+ ? new Decimal(pairStats.rate)
+ .mul(secondAssetUsdPrice)
+ .toFixed(pairStats.rate < 0.1 ? 6 : 2)
+ : undefined;
+
+ const buyForm = useOrderForm({
+ type: 'buy',
+ pairData,
+ balance,
+ assetsRates: state.assetsRates,
+ });
+
+ const sellForm = useOrderForm({
+ type: 'sell',
+ pairData,
+ balance,
+ assetsRates: state.assetsRates,
+ });
+
+ return {
+ currencyNames,
+ firstAssetLink,
+ secondAssetLink,
+ secondAssetUsdPrice,
+ loggedIn,
+ balance,
+ buyForm,
+ sellForm,
+ pairRateUsd,
+ };
+};
+
+export default useTradeInit;
diff --git a/src/pages/dex/trading/hooks/useTradingData.ts b/src/pages/dex/trading/hooks/useTradingData.ts
new file mode 100644
index 0000000..fafa4cb
--- /dev/null
+++ b/src/pages/dex/trading/hooks/useTradingData.ts
@@ -0,0 +1,144 @@
+import {
+ getCandles,
+ getOrdersPage,
+ getPair,
+ getPairStats,
+ getUserOrdersPage,
+ getTrades,
+} from '@/utils/methods';
+import useUpdateUser from '@/hook/useUpdateUser';
+import { Dispatch, SetStateAction, useContext, useEffect, useState } from 'react';
+import CandleRow from '@/interfaces/common/CandleRow';
+import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
+import { Trade } from '@/interfaces/responses/trades/GetTradeRes';
+import PairData from '@/interfaces/common/PairData';
+import { PairStats } from '@/interfaces/responses/orders/GetPairStatsRes';
+import OrderRow from '@/interfaces/common/OrderRow';
+import ApplyTip from '@/interfaces/common/ApplyTip';
+import { useRouter } from 'next/router';
+import PeriodState from '@/interfaces/states/pages/dex/trading/InputPanelItem/PeriodState';
+import { Store } from '@/store/store-reducer';
+
+interface UseTradingDataParams {
+ periodsState: PeriodState;
+ setCandles: Dispatch>;
+ setOrdersHistory: Dispatch>;
+ setTrades: Dispatch>;
+ setPairData: Dispatch>;
+ setPairStats: Dispatch>;
+ setUserOrders: Dispatch>;
+ setApplyTips: Dispatch>;
+ setMyOrdersLoading: Dispatch>;
+}
+
+export function useTradingData({
+ periodsState,
+ setCandles,
+ setOrdersHistory,
+ setTrades,
+ setPairData,
+ setPairStats,
+ setUserOrders,
+ setApplyTips,
+ setMyOrdersLoading,
+}: UseTradingDataParams) {
+ const { state } = useContext(Store);
+ const fetchUser = useUpdateUser();
+ const router = useRouter();
+ const [candlesLoaded, setCandlesLoaded] = useState(false);
+ const [ordersLoading, setOrdersLoading] = useState(true);
+ const [tradesLoading, setTradesLoading] = useState(true);
+ const pairId = typeof router.query.id === 'string' ? router.query.id : '';
+ const loggedIn = !!state.wallet?.connected;
+
+ async function fetchCandles() {
+ setCandlesLoaded(false);
+ setCandles([]);
+ const result = await getCandles(pairId, periodsState.code);
+ if (result.success) {
+ setCandles(result.data);
+ } else {
+ setCandles([]);
+ }
+ setCandlesLoaded(true);
+ }
+
+ async function updateOrders() {
+ setOrdersLoading(true);
+ const result = await getOrdersPage(pairId);
+ if (!result.success) return;
+ setOrdersHistory(result?.data || []);
+ setOrdersLoading(false);
+ }
+
+ async function updateUserOrders() {
+ setMyOrdersLoading(true);
+ const result = await getUserOrdersPage(pairId);
+ await fetchUser();
+
+ if (!result.success) return;
+ setUserOrders(result?.data?.orders || []);
+ setApplyTips(result?.data?.applyTips || []);
+ setMyOrdersLoading(false);
+ }
+
+ async function fetchTrades() {
+ setTradesLoading(true);
+ const result = await getTrades(pairId);
+
+ if (result.success) {
+ setTrades(result.data);
+ }
+
+ setTradesLoading(false);
+ }
+
+ async function fetchPairStats() {
+ const result = await getPairStats(pairId);
+ if (!result.success) return;
+ setPairStats(result.data);
+ }
+
+ async function getPairData() {
+ const result = await getPair(pairId);
+ if (!result.success) {
+ router.push('/404');
+ return;
+ }
+ setPairData(result.data);
+ }
+
+ useEffect(() => {
+ fetchPairStats();
+ getPairData();
+ updateOrders();
+ }, []);
+
+ useEffect(() => {
+ fetchCandles();
+ }, [periodsState]);
+
+ useEffect(() => {
+ (async () => {
+ await fetchTrades();
+ })();
+ }, [pairId]);
+
+ useEffect(() => {
+ if (!loggedIn) return;
+ setUserOrders([]);
+ updateUserOrders();
+ }, [state.wallet?.connected && state.wallet?.address]);
+
+ return {
+ fetchCandles,
+ updateOrders,
+ updateUserOrders,
+ fetchTrades,
+ fetchPairStats,
+ getPairData,
+ candlesLoaded,
+ ordersLoading,
+ tradesLoading,
+ };
+}
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/Trading.module.scss b/src/styles/Trading.module.scss
index 270f4eb..aeb178e 100644
--- a/src/styles/Trading.module.scss
+++ b/src/styles/Trading.module.scss
@@ -1,1107 +1,59 @@
-.main {
+.trading {
+ padding-inline: 60px;
+ padding-top: 20px;
display: flex;
flex-direction: column;
- @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 {
- display: flex;
- flex-direction: column;
- gap: 25px;
- position: relative;
- border-bottom: 1px solid var(--delimiter-color);
-
- .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 {
+ &__top {
+ margin-top: 20px;
display: flex;
gap: 20px;
- padding-bottom: 40px;
+ padding-bottom: 20px;
+ height: 40dvh;
+ min-height: 380px;
+ max-height: 500px;
- > 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) {
+ &_chart {
+ width: 100%;
+ overflow: hidden;
+ display: flex;
flex-direction: column;
- > * {
- width: 100% !important;
- }
- }
- }
-
- .trading__chart__wrapper {
- width: 100%;
- overflow: hidden;
- display: flex;
- flex-direction: column;
-
- &.mobile {
- display: none;
- }
-
- .trading__chart__preloader {
- height: 100%;
- min-height: 545px;
- }
-
- .trading__chart__settings {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 25px 0;
- border-bottom: 1px solid var(--delimiter-color);
-
- .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;
+ @media screen and (max-width: 1360px) {
+ width: 200px;
}
}
}
-
- > 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;
- }
- }
- }
- }
- }
- }
- }
-
- .orders__message {
- 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;
+ &__info {
display: flex;
- align-items: center;
- gap: 2px;
- border-radius: 100px;
- background: radial-gradient(100% 246.57% at 0% 0%, #a366ff 0%, #601fff 100%);
+ gap: 20px;
+ margin-bottom: 40px;
+ height: 405px;
- > 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;
- }
- }
- }
- }
+ &_createOrders {
+ display: flex;
+ gap: 20px;
+ width: 100%;
}
}
}
diff --git a/src/styles/themes/dark.scss b/src/styles/themes/dark.scss
new file mode 100644
index 0000000..3f47466
--- /dev/null
+++ b/src/styles/themes/dark.scss
@@ -0,0 +1,53 @@
+[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;
+}
diff --git a/src/styles/themes/light.scss b/src/styles/themes/light.scss
index b8eee08..7809ccf 100644
--- a/src/styles/themes/light.scss
+++ b/src/styles/themes/light.scss
@@ -46,54 +46,8 @@
--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;
}
diff --git a/src/utils/methods.ts b/src/utils/methods.ts
index db63ea0..3ea4880 100644
--- a/src/utils/methods.ts
+++ b/src/utils/methods.ts
@@ -327,3 +327,23 @@ export async function getZanoPrice() {
)
.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 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/utils.ts b/src/utils/utils.ts
index deb3643..31c32e6 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -133,9 +133,20 @@ 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 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 => {